summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-format2
-rw-r--r--.github/monitoring-plugins.spec47
-rw-r--r--.github/os_detect.sh10
-rwxr-xr-x.github/prepare_debian.sh3
-rw-r--r--.github/workflows/codeql-analysis.yml24
-rw-r--r--.github/workflows/spellcheck.yml3
-rw-r--r--.github/workflows/test-next.yml20
-rw-r--r--.github/workflows/test.yml19
-rw-r--r--.gitignore20
-rw-r--r--REQUIREMENTS12
-rw-r--r--THANKS.in1
-rw-r--r--configure.ac104
-rw-r--r--gl/Makefile.am1040
-rw-r--r--gl/_Noreturn.h41
-rw-r--r--gl/af_alg.c2
-rw-r--r--gl/af_alg.h2
-rw-r--r--gl/alloca.in.h2
-rw-r--r--gl/arg-nonnull.h2
-rw-r--r--gl/arpa_inet.c21
-rw-r--r--gl/arpa_inet.in.h58
-rw-r--r--gl/asnprintf.c2
-rw-r--r--gl/asprintf.c2
-rw-r--r--gl/assert.in.h2
-rw-r--r--gl/attribute.h132
-rw-r--r--gl/base64.c8
-rw-r--r--gl/base64.h4
-rw-r--r--gl/basename-lgpl.c2
-rw-r--r--gl/basename-lgpl.h2
-rw-r--r--gl/basename.c2
-rw-r--r--gl/btowc.c2
-rw-r--r--gl/byteswap.c21
-rw-r--r--gl/byteswap.in.h106
-rw-r--r--gl/c++defs.h50
-rw-r--r--gl/c-ctype.c21
-rw-r--r--gl/c-ctype.h366
-rw-r--r--gl/c32is-impl.h105
-rw-r--r--gl/c32isalnum.c26
-rw-r--r--gl/c32isalpha.c26
-rw-r--r--gl/c32isblank.c26
-rw-r--r--gl/c32iscntrl.c26
-rw-r--r--gl/c32isdigit.c26
-rw-r--r--gl/c32isgraph.c26
-rw-r--r--gl/c32islower.c26
-rw-r--r--gl/c32isprint.c26
-rw-r--r--gl/c32ispunct.c26
-rw-r--r--gl/c32isspace.c26
-rw-r--r--gl/c32isupper.c26
-rw-r--r--gl/c32isxdigit.c26
-rw-r--r--gl/c32to-impl.h103
-rw-r--r--gl/c32tolower.c26
-rw-r--r--gl/c32width.c102
-rw-r--r--gl/calloc.c17
-rw-r--r--gl/cdefs.h16
-rw-r--r--gl/cloexec.c2
-rw-r--r--gl/cloexec.h2
-rw-r--r--gl/close.c2
-rw-r--r--gl/dirname-lgpl.c2
-rw-r--r--gl/dirname.c2
-rw-r--r--gl/dirname.h2
-rw-r--r--gl/dup2.c2
-rw-r--r--gl/dynarray.h2
-rw-r--r--gl/errno.in.h11
-rw-r--r--gl/error.c177
-rw-r--r--gl/error.in.h71
-rw-r--r--gl/exitfail.c2
-rw-r--r--gl/exitfail.h2
-rw-r--r--gl/fcntl.c47
-rw-r--r--gl/fcntl.in.h41
-rw-r--r--gl/fd-hook.c2
-rw-r--r--gl/fd-hook.h2
-rw-r--r--gl/fflush.c15
-rw-r--r--gl/filename.h2
-rw-r--r--gl/float+.h2
-rw-r--r--gl/float.c99
-rw-r--r--gl/float.in.h221
-rw-r--r--gl/floor.c2
-rw-r--r--gl/floorf.c2
-rw-r--r--gl/fopen.c6
-rw-r--r--gl/fpurge.c8
-rw-r--r--gl/freading.c8
-rw-r--r--gl/freading.h2
-rw-r--r--gl/free.c2
-rw-r--r--gl/fseek.c2
-rw-r--r--gl/fseeko.c24
-rw-r--r--gl/fseterr.c84
-rw-r--r--gl/fseterr.h55
-rw-r--r--gl/fstat.c2
-rw-r--r--gl/fsusage.c2
-rw-r--r--gl/fsusage.h2
-rw-r--r--gl/ftell.c2
-rw-r--r--gl/ftello.c11
-rw-r--r--gl/gai_strerror.c6
-rw-r--r--gl/getaddrinfo.c74
-rw-r--r--gl/getdelim.c2
-rw-r--r--gl/getdtablesize.c2
-rw-r--r--gl/gethostname.c2
-rw-r--r--gl/getline.c2
-rw-r--r--gl/getloadavg.c48
-rw-r--r--gl/getopt-cdefs.in.h12
-rw-r--r--gl/getopt-core.h2
-rw-r--r--gl/getopt-ext.h2
-rw-r--r--gl/getopt-pfx-core.h12
-rw-r--r--gl/getopt-pfx-ext.h4
-rw-r--r--gl/getopt.c8
-rw-r--r--gl/getopt.in.h7
-rw-r--r--gl/getopt1.c2
-rw-r--r--gl/getopt_int.h2
-rw-r--r--gl/getprogname.c2
-rw-r--r--gl/getprogname.h2
-rw-r--r--gl/gettext.h114
-rw-r--r--gl/gl_openssl.h2
-rw-r--r--gl/glthread/lock.c46
-rw-r--r--gl/glthread/lock.h153
-rw-r--r--gl/glthread/once.c80
-rw-r--r--gl/glthread/once.h272
-rw-r--r--gl/glthread/threadlib.c2
-rw-r--r--gl/hard-locale.c2
-rw-r--r--gl/hard-locale.h2
-rw-r--r--gl/ialloc.c2
-rw-r--r--gl/ialloc.h39
-rw-r--r--gl/idpriv-droptemp.c14
-rw-r--r--gl/idpriv.h2
-rw-r--r--gl/idx.h2
-rw-r--r--gl/inet_ntop.c4
-rw-r--r--gl/inet_pton.c268
-rw-r--r--gl/intprops-internal.h27
-rw-r--r--gl/intprops.h10
-rw-r--r--gl/inttypes.in.h18
-rw-r--r--gl/iswblank.c2
-rw-r--r--gl/iswctype-impl.h2
-rw-r--r--gl/iswctype.c2
-rw-r--r--gl/iswdigit.c2
-rw-r--r--gl/iswpunct.c2
-rw-r--r--gl/iswxdigit.c2
-rw-r--r--gl/itold.c2
-rw-r--r--gl/langinfo.in.h49
-rw-r--r--gl/lc-charset-dispatch.c2
-rw-r--r--gl/lc-charset-dispatch.h2
-rw-r--r--gl/libc-config.h7
-rw-r--r--gl/limits.in.h8
-rw-r--r--gl/localcharset.c10
-rw-r--r--gl/localcharset.h2
-rw-r--r--gl/locale.in.h195
-rw-r--r--gl/localeconv.c2
-rw-r--r--gl/lseek.c2
-rw-r--r--gl/lstat.c104
-rw-r--r--gl/m4/00gnulib.m43
-rw-r--r--gl/m4/__inline.m43
-rw-r--r--gl/m4/absolute-header.m43
-rw-r--r--gl/m4/af_alg.m43
-rw-r--r--gl/m4/alloca.m43
-rw-r--r--gl/m4/arpa_inet_h.m49
-rw-r--r--gl/m4/assert_h.m476
-rw-r--r--gl/m4/base64.m43
-rw-r--r--gl/m4/btowc.m413
-rw-r--r--gl/m4/build-to-host.m4274
-rw-r--r--gl/m4/builtin-expect.m410
-rw-r--r--gl/m4/byteswap.m434
-rw-r--r--gl/m4/c-bool.m420
-rw-r--r--gl/m4/c32rtomb.m4187
-rw-r--r--gl/m4/calloc.m473
-rw-r--r--gl/m4/close.m43
-rw-r--r--gl/m4/codeset.m43
-rw-r--r--gl/m4/double-slash-root.m43
-rw-r--r--gl/m4/dup2.m43
-rw-r--r--gl/m4/eealloc.m432
-rw-r--r--gl/m4/environ.m43
-rw-r--r--gl/m4/errno_h.m413
-rw-r--r--gl/m4/error.m44
-rw-r--r--gl/m4/error_h.m420
-rw-r--r--gl/m4/exponentd.m47
-rw-r--r--gl/m4/extensions-aix.m426
-rw-r--r--gl/m4/extensions.m43
-rw-r--r--gl/m4/extern-inline.m43
-rw-r--r--gl/m4/fclose.m43
-rw-r--r--gl/m4/fcntl-o.m497
-rw-r--r--gl/m4/fcntl.m43
-rw-r--r--gl/m4/fcntl_h.m43
-rw-r--r--gl/m4/fflush.m414
-rw-r--r--gl/m4/float_h.m430
-rw-r--r--gl/m4/floorf.m43
-rw-r--r--gl/m4/fopen.m43
-rw-r--r--gl/m4/fpurge.m494
-rw-r--r--gl/m4/freading.m43
-rw-r--r--gl/m4/free.m43
-rw-r--r--gl/m4/fseek.m43
-rw-r--r--gl/m4/fseeko.m49
-rw-r--r--gl/m4/fseterr.m415
-rw-r--r--gl/m4/fstat.m43
-rw-r--r--gl/m4/fstypename.m43
-rw-r--r--gl/m4/fsusage.m44
-rw-r--r--gl/m4/ftell.m43
-rw-r--r--gl/m4/ftello.m49
-rw-r--r--gl/m4/getaddrinfo.m446
-rw-r--r--gl/m4/getdelim.m43
-rw-r--r--gl/m4/getdtablesize.m43
-rw-r--r--gl/m4/gethostname.m43
-rw-r--r--gl/m4/getline.m43
-rw-r--r--gl/m4/getloadavg.m45
-rw-r--r--gl/m4/getopt.m416
-rw-r--r--gl/m4/getprogname.m43
-rw-r--r--gl/m4/gl-openssl.m43
-rw-r--r--gl/m4/gnulib-cache.m42
-rw-r--r--gl/m4/gnulib-common.m4457
-rw-r--r--gl/m4/gnulib-comp.m4517
-rw-r--r--gl/m4/gnulib-i18n.m461
-rw-r--r--gl/m4/gnulib-tool.m48
-rw-r--r--gl/m4/hostent.m43
-rw-r--r--gl/m4/idpriv.m43
-rw-r--r--gl/m4/include_next.m43
-rw-r--r--gl/m4/inet_ntop.m43
-rw-r--r--gl/m4/inet_pton.m472
-rw-r--r--gl/m4/intmax_t.m43
-rw-r--r--gl/m4/inttypes.m43
-rw-r--r--gl/m4/inttypes_h.m43
-rw-r--r--gl/m4/iswblank.m43
-rw-r--r--gl/m4/iswctype.m43
-rw-r--r--gl/m4/iswdigit.m421
-rw-r--r--gl/m4/iswpunct.m43
-rw-r--r--gl/m4/iswxdigit.m421
-rw-r--r--gl/m4/langinfo_h.m420
-rw-r--r--gl/m4/largefile.m411
-rw-r--r--gl/m4/libunistring-base.m4204
-rw-r--r--gl/m4/limits-h.m43
-rw-r--r--gl/m4/localcharset.m43
-rw-r--r--gl/m4/locale-en.m4138
-rw-r--r--gl/m4/locale-fr.m425
-rw-r--r--gl/m4/locale-ja.m410
-rw-r--r--gl/m4/locale-zh.m424
-rw-r--r--gl/m4/locale_h.m452
-rw-r--r--gl/m4/localeconv.m43
-rw-r--r--gl/m4/lock.m43
-rw-r--r--gl/m4/lseek.m43
-rw-r--r--gl/m4/lstat.m482
-rw-r--r--gl/m4/malloc.m4139
-rw-r--r--gl/m4/malloca.m47
-rw-r--r--gl/m4/math_h.m414
-rw-r--r--gl/m4/mbchar.m415
-rw-r--r--gl/m4/mbiter.m416
-rw-r--r--gl/m4/mbrtoc32.m4326
-rw-r--r--gl/m4/mbrtowc.m437
-rw-r--r--gl/m4/mbsinit.m43
-rw-r--r--gl/m4/mbstate_t.m43
-rw-r--r--gl/m4/mbtowc.m43
-rw-r--r--gl/m4/memchr.m47
-rw-r--r--gl/m4/minmax.m43
-rw-r--r--gl/m4/mktime.m46
-rw-r--r--gl/m4/mmap-anon.m43
-rw-r--r--gl/m4/mode_t.m43
-rw-r--r--gl/m4/mountlist.m418
-rw-r--r--gl/m4/msvc-inval.m43
-rw-r--r--gl/m4/msvc-nothrow.m43
-rw-r--r--gl/m4/multiarch.m43
-rw-r--r--gl/m4/musl.m43
-rw-r--r--gl/m4/netdb_h.m43
-rw-r--r--gl/m4/netinet_in_h.m43
-rw-r--r--gl/m4/nl_langinfo.m413
-rw-r--r--gl/m4/nocrash.m43
-rw-r--r--gl/m4/off64_t.m432
-rw-r--r--gl/m4/off_t.m43
-rw-r--r--gl/m4/once.m414
-rw-r--r--gl/m4/open-cloexec.m43
-rw-r--r--gl/m4/open-slash.m43
-rw-r--r--gl/m4/open.m48
-rw-r--r--gl/m4/pathmax.m43
-rw-r--r--gl/m4/pid_t.m43
-rw-r--r--gl/m4/printf.m4288
-rw-r--r--gl/m4/pthread-once.m483
-rw-r--r--gl/m4/pthread-spin.m472
-rw-r--r--gl/m4/pthread_h.m4293
-rw-r--r--gl/m4/pthread_rwlock_rdlock.m43
-rw-r--r--gl/m4/realloc.m4153
-rw-r--r--gl/m4/reallocarray.m416
-rw-r--r--gl/m4/regex.m426
-rw-r--r--gl/m4/sched_h.m4102
-rw-r--r--gl/m4/servent.m43
-rw-r--r--gl/m4/setenv.m47
-rw-r--r--gl/m4/setlocale_null.m47
-rw-r--r--gl/m4/sha256.m43
-rw-r--r--gl/m4/size_max.m43
-rw-r--r--gl/m4/snprintf.m43
-rw-r--r--gl/m4/socketlib.m43
-rw-r--r--gl/m4/sockets.m43
-rw-r--r--gl/m4/socklen.m43
-rw-r--r--gl/m4/sockpfaf.m415
-rw-r--r--gl/m4/ssize_t.m43
-rw-r--r--gl/m4/stat-time.m44
-rw-r--r--gl/m4/stat.m43
-rw-r--r--gl/m4/std-gnu11.m427
-rw-r--r--gl/m4/stdalign.m418
-rw-r--r--gl/m4/stdckdint_h.m4136
-rw-r--r--gl/m4/stddef_h.m463
-rw-r--r--gl/m4/stdint.m47
-rw-r--r--gl/m4/stdint_h.m43
-rw-r--r--gl/m4/stdio_h.m417
-rw-r--r--gl/m4/stdlib_h.m466
-rw-r--r--gl/m4/strcasecmp.m467
-rw-r--r--gl/m4/strcasestr.m47
-rw-r--r--gl/m4/strerror.m43
-rw-r--r--gl/m4/string_h.m419
-rw-r--r--gl/m4/strings_h.m418
-rw-r--r--gl/m4/strncasecmp.m4 (renamed from gl/m4/strcase.m4)34
-rw-r--r--gl/m4/strncpy.m494
-rw-r--r--gl/m4/strsep.m43
-rw-r--r--gl/m4/strstr.m47
-rw-r--r--gl/m4/sys_cdefs_h.m426
-rw-r--r--gl/m4/sys_socket_h.m448
-rw-r--r--gl/m4/sys_stat_h.m43
-rw-r--r--gl/m4/sys_types_h.m416
-rw-r--r--gl/m4/sys_uio_h.m43
-rw-r--r--gl/m4/threadlib.m4376
-rw-r--r--gl/m4/time_h.m412
-rw-r--r--gl/m4/time_r.m43
-rw-r--r--gl/m4/timegm.m43
-rw-r--r--gl/m4/uchar_h.m4279
-rw-r--r--gl/m4/ungetc.m43
-rw-r--r--gl/m4/unicase_h.m445
-rw-r--r--gl/m4/unictype_h.m4179
-rw-r--r--gl/m4/uninorm_h.m447
-rw-r--r--gl/m4/unistd_h.m47
-rw-r--r--gl/m4/unitypes_h.m426
-rw-r--r--gl/m4/unlocked-io.m43
-rw-r--r--gl/m4/vararrays.m43
-rw-r--r--gl/m4/vasnprintf.m474
-rw-r--r--gl/m4/vasprintf.m43
-rw-r--r--gl/m4/visibility.m43
-rw-r--r--gl/m4/vsnprintf.m43
-rw-r--r--gl/m4/warn-on-use.m43
-rw-r--r--gl/m4/wchar_h.m46
-rw-r--r--gl/m4/wchar_t.m425
-rw-r--r--gl/m4/wcrtomb.m413
-rw-r--r--gl/m4/wctype.m43
-rw-r--r--gl/m4/wctype_h.m43
-rw-r--r--gl/m4/wcwidth.m4116
-rw-r--r--gl/m4/wint_t.m43
-rw-r--r--gl/m4/xalloc.m43
-rw-r--r--gl/m4/xsize.m43
-rw-r--r--gl/m4/zzgnulib.m43
-rw-r--r--gl/malloc.c13
-rw-r--r--gl/malloc/dynarray-skeleton.c2
-rw-r--r--gl/malloc/dynarray.h2
-rw-r--r--gl/malloc/dynarray_at_failure.c2
-rw-r--r--gl/malloc/dynarray_emplace_enlarge.c2
-rw-r--r--gl/malloc/dynarray_finalize.c2
-rw-r--r--gl/malloc/dynarray_resize.c2
-rw-r--r--gl/malloc/dynarray_resize_clear.c2
-rw-r--r--gl/malloca.c6
-rw-r--r--gl/malloca.h2
-rw-r--r--gl/math.c4
-rw-r--r--gl/math.in.h487
-rw-r--r--gl/mbchar.c23
-rw-r--r--gl/mbchar.h383
-rw-r--r--gl/mbiterf.c21
-rw-r--r--gl/mbiterf.h214
-rw-r--r--gl/mbrtoc32.c288
-rw-r--r--gl/mbrtowc-impl-utf8.h2
-rw-r--r--gl/mbrtowc-impl.h2
-rw-r--r--gl/mbrtowc.c2
-rw-r--r--gl/mbsinit.c2
-rw-r--r--gl/mbsnlen.c60
-rw-r--r--gl/mbszero.c2
-rw-r--r--gl/mbtowc-impl.h2
-rw-r--r--gl/mbtowc-lock.c2
-rw-r--r--gl/mbtowc-lock.h2
-rw-r--r--gl/mbtowc.c2
-rw-r--r--gl/memchr.c2
-rw-r--r--gl/memchr.valgrind2
-rw-r--r--gl/minmax.h2
-rw-r--r--gl/mktime-internal.h16
-rw-r--r--gl/mktime.c163
-rw-r--r--gl/mountlist.c244
-rw-r--r--gl/mountlist.h7
-rw-r--r--gl/msvc-inval.c2
-rw-r--r--gl/msvc-inval.h2
-rw-r--r--gl/msvc-nothrow.c2
-rw-r--r--gl/msvc-nothrow.h2
-rw-r--r--gl/netdb.in.h33
-rw-r--r--gl/netinet_in.in.h2
-rw-r--r--gl/nl_langinfo-lock.c2
-rw-r--r--gl/nl_langinfo.c105
-rw-r--r--gl/open.c121
-rw-r--r--gl/pathmax.h2
-rw-r--r--gl/printf-args.c21
-rw-r--r--gl/printf-args.h13
-rw-r--r--gl/printf-parse.c8
-rw-r--r--gl/printf-parse.h2
-rw-r--r--gl/pthread-once.c148
-rw-r--r--gl/pthread.h2571
-rw-r--r--gl/pthread.in.h2032
-rw-r--r--gl/realloc.c73
-rw-r--r--gl/reallocarray.c4
-rw-r--r--gl/regcomp.c67
-rw-r--r--gl/regex.c2
-rw-r--r--gl/regex.h51
-rw-r--r--gl/regex_internal.c9
-rw-r--r--gl/regex_internal.h12
-rw-r--r--gl/regexec.c18
-rw-r--r--gl/sched.h631
-rw-r--r--gl/sched.in.h111
-rw-r--r--gl/setenv.c97
-rw-r--r--gl/setlocale-lock.c2
-rw-r--r--gl/setlocale_null-unlocked.c2
-rw-r--r--gl/setlocale_null.c2
-rw-r--r--gl/setlocale_null.h2
-rw-r--r--gl/sha256-stream.c12
-rw-r--r--gl/sha256.c2
-rw-r--r--gl/sha256.h2
-rw-r--r--gl/size_max.h2
-rw-r--r--gl/snprintf.c41
-rw-r--r--gl/sockets.c2
-rw-r--r--gl/sockets.h4
-rw-r--r--gl/stat-time.c2
-rw-r--r--gl/stat-time.h45
-rw-r--r--gl/stat-w32.c2
-rw-r--r--gl/stat-w32.h2
-rw-r--r--gl/stat.c6
-rw-r--r--gl/stdckdint.in.h41
-rw-r--r--gl/stddef.in.h103
-rw-r--r--gl/stdint.in.h13
-rw-r--r--gl/stdio-consolesafe.c199
-rw-r--r--gl/stdio-impl.h116
-rw-r--r--gl/stdio-read.c2
-rw-r--r--gl/stdio-write.c8
-rw-r--r--gl/stdio.in.h587
-rw-r--r--gl/stdlib.c21
-rw-r--r--gl/stdlib.in.h497
-rw-r--r--gl/str-two-way.h2
-rw-r--r--gl/strcasecmp.c6
-rw-r--r--gl/strcasestr.c2
-rw-r--r--gl/streq.h4
-rw-r--r--gl/strerror-override.c7
-rw-r--r--gl/strerror-override.h5
-rw-r--r--gl/strerror.c8
-rw-r--r--gl/string.in.h483
-rw-r--r--gl/strings.in.h150
-rw-r--r--gl/stripslash.c2
-rw-r--r--gl/strncasecmp.c6
-rw-r--r--gl/strncpy.c38
-rw-r--r--gl/strsep.c2
-rw-r--r--gl/strstr.c2
-rw-r--r--gl/sys-limits.h2
-rw-r--r--gl/sys_socket.c4
-rw-r--r--gl/sys_socket.in.h127
-rw-r--r--gl/sys_stat.in.h104
-rw-r--r--gl/sys_types.in.h27
-rw-r--r--gl/sys_uio.in.h2
-rw-r--r--gl/time.in.h116
-rw-r--r--gl/time_r.c2
-rw-r--r--gl/timegm.c5
-rw-r--r--gl/uchar.h1456
-rw-r--r--gl/uchar.in.h912
-rw-r--r--gl/unicase.h472
-rw-r--r--gl/unicase.in.h471
-rw-r--r--gl/unicase/.deps/.dirstamp0
-rw-r--r--gl/unicase/.deps/libgnu_a-tolower.Po49
-rw-r--r--gl/unicase/.dirstamp0
-rw-r--r--gl/unicase/simple-mapping.h39
-rw-r--r--gl/unicase/tolower.c27
-rw-r--r--gl/unicase/tolower.h743
-rw-r--r--gl/unictype.h1148
-rw-r--r--gl/unictype.in.h1146
-rw-r--r--gl/unictype/.deps/.dirstamp0
-rw-r--r--gl/unictype/.deps/libgnu_a-ctype_alnum.Po48
-rw-r--r--gl/unictype/.deps/libgnu_a-ctype_alpha.Po48
-rw-r--r--gl/unictype/.deps/libgnu_a-ctype_blank.Po48
-rw-r--r--gl/unictype/.deps/libgnu_a-ctype_cntrl.Po48
-rw-r--r--gl/unictype/.deps/libgnu_a-ctype_digit.Po48
-rw-r--r--gl/unictype/.deps/libgnu_a-ctype_graph.Po48
-rw-r--r--gl/unictype/.deps/libgnu_a-ctype_lower.Po48
-rw-r--r--gl/unictype/.deps/libgnu_a-ctype_print.Po48
-rw-r--r--gl/unictype/.deps/libgnu_a-ctype_punct.Po48
-rw-r--r--gl/unictype/.deps/libgnu_a-ctype_space.Po48
-rw-r--r--gl/unictype/.deps/libgnu_a-ctype_upper.Po48
-rw-r--r--gl/unictype/.deps/libgnu_a-ctype_xdigit.Po48
-rw-r--r--gl/unictype/.dirstamp0
-rw-r--r--gl/unictype/bitmap.h48
-rw-r--r--gl/unictype/ctype_alnum.c32
-rw-r--r--gl/unictype/ctype_alnum.h897
-rw-r--r--gl/unictype/ctype_alpha.c32
-rw-r--r--gl/unictype/ctype_alpha.h897
-rw-r--r--gl/unictype/ctype_blank.c32
-rw-r--r--gl/unictype/ctype_blank.h184
-rw-r--r--gl/unictype/ctype_cntrl.c32
-rw-r--r--gl/unictype/ctype_cntrl.h176
-rw-r--r--gl/unictype/ctype_digit.c32
-rw-r--r--gl/unictype/ctype_digit.h172
-rw-r--r--gl/unictype/ctype_graph.c32
-rw-r--r--gl/unictype/ctype_graph.h1202
-rw-r--r--gl/unictype/ctype_lower.c32
-rw-r--r--gl/unictype/ctype_lower.h371
-rw-r--r--gl/unictype/ctype_print.c32
-rw-r--r--gl/unictype/ctype_print.h1202
-rw-r--r--gl/unictype/ctype_punct.c32
-rw-r--r--gl/unictype/ctype_punct.h870
-rw-r--r--gl/unictype/ctype_space.c32
-rw-r--r--gl/unictype/ctype_space.h184
-rw-r--r--gl/unictype/ctype_upper.c32
-rw-r--r--gl/unictype/ctype_upper.h367
-rw-r--r--gl/unictype/ctype_xdigit.c32
-rw-r--r--gl/unictype/ctype_xdigit.h172
-rw-r--r--gl/uninorm.h256
-rw-r--r--gl/uninorm.in.h255
-rw-r--r--gl/unistd.c4
-rw-r--r--gl/unistd.in.h443
-rw-r--r--gl/unitypes.h72
-rw-r--r--gl/unitypes.in.h71
-rw-r--r--gl/uniwidth.h73
-rw-r--r--gl/uniwidth.in.h72
-rw-r--r--gl/uniwidth/.deps/.dirstamp0
-rw-r--r--gl/uniwidth/.deps/libgnu_a-width.Po60
-rw-r--r--gl/uniwidth/.dirstamp0
-rw-r--r--gl/uniwidth/cjk.h37
-rw-r--r--gl/uniwidth/width.c95
-rw-r--r--gl/uniwidth/width0.h495
-rw-r--r--gl/uniwidth/width2.h541
-rw-r--r--gl/unlocked-io.h2
-rw-r--r--gl/unsetenv.c34
-rw-r--r--gl/vasnprintf.c1451
-rw-r--r--gl/vasnprintf.h2
-rw-r--r--gl/vasprintf.c14
-rw-r--r--gl/verify.h38
-rw-r--r--gl/vsnprintf.c41
-rw-r--r--gl/vsnzprintf.c65
-rw-r--r--gl/w32sock.h2
-rw-r--r--gl/warn-on-use.h10
-rw-r--r--gl/wchar.in.h313
-rw-r--r--gl/wcrtomb.c2
-rw-r--r--gl/wctype-h.c4
-rw-r--r--gl/wctype-impl.h2
-rw-r--r--gl/wctype.c2
-rw-r--r--gl/wctype.in.h28
-rw-r--r--gl/wcwidth.c73
-rw-r--r--gl/windows-initguard.h2
-rw-r--r--gl/windows-mutex.c26
-rw-r--r--gl/windows-mutex.h3
-rw-r--r--gl/windows-once.c51
-rw-r--r--gl/windows-once.h7
-rw-r--r--gl/windows-recmutex.c2
-rw-r--r--gl/windows-recmutex.h2
-rw-r--r--gl/windows-rwlock.c2
-rw-r--r--gl/windows-rwlock.h2
-rw-r--r--gl/xalloc-die.c4
-rw-r--r--gl/xalloc-oversized.h5
-rw-r--r--gl/xalloc.h2
-rw-r--r--gl/xmalloc.c6
-rw-r--r--gl/xsize.c2
-rw-r--r--gl/xsize.h20
-rw-r--r--lib/Makefile.am5
-rw-r--r--lib/extra_opts.c55
-rw-r--r--lib/maxfd.c6
-rw-r--r--lib/output.c131
-rw-r--r--lib/output.h47
-rw-r--r--lib/parse_ini.c239
-rw-r--r--lib/perfdata.c153
-rw-r--r--lib/perfdata.h60
-rw-r--r--lib/tests/Makefile.am6
-rw-r--r--lib/tests/test_base64.c271
-rw-r--r--lib/tests/test_cmd.c41
-rwxr-xr-xlib/tests/test_disk.t6
-rw-r--r--lib/tests/test_generic_output.c6
-rw-r--r--lib/tests/test_ini1.c54
-rw-r--r--lib/tests/test_opts1.c51
-rw-r--r--lib/tests/test_opts2.c86
-rw-r--r--lib/tests/test_tcp.c28
-rw-r--r--lib/tests/test_utils.c190
-rw-r--r--lib/thresholds.c14
-rw-r--r--lib/thresholds.h7
-rw-r--r--lib/utils_base.c459
-rw-r--r--lib/utils_base.h29
-rw-r--r--lib/utils_cmd.c484
-rw-r--r--lib/utils_cmd.h20
-rw-r--r--lib/utils_disk.c255
-rw-r--r--lib/utils_disk.h48
-rw-r--r--lib/utils_tcp.c41
-rw-r--r--lib/utils_tcp.h4
-rw-r--r--plugins-root/Makefile.am7
-rw-r--r--plugins-root/check_dhcp.c1021
-rw-r--r--plugins-root/check_dhcp.d/config.h50
-rw-r--r--plugins-root/check_icmp.c2931
-rw-r--r--plugins-root/check_icmp.d/check_icmp_helpers.c134
-rw-r--r--plugins-root/check_icmp.d/check_icmp_helpers.h68
-rw-r--r--plugins-root/check_icmp.d/config.h115
-rw-r--r--plugins-root/pst3.c441
-rw-r--r--plugins-root/t/check_dhcp.t24
-rw-r--r--plugins-root/t/check_icmp.t58
-rw-r--r--plugins/Makefile.am57
-rw-r--r--plugins/check_apt.c259
-rw-r--r--plugins/check_apt.d/config.h9
-rw-r--r--plugins/check_by_ssh.c286
-rw-r--r--plugins/check_by_ssh.d/config.h23
-rw-r--r--plugins/check_cluster.c73
-rw-r--r--plugins/check_cluster.d/config.h6
-rw-r--r--plugins/check_curl.c2931
-rw-r--r--plugins/check_curl.d/check_curl_helpers.c1297
-rw-r--r--plugins/check_curl.d/check_curl_helpers.h128
-rw-r--r--plugins/check_curl.d/config.h116
-rw-r--r--plugins/check_dbi.c695
-rw-r--r--plugins/check_dbi.d/config.h31
-rw-r--r--plugins/check_dig.c286
-rw-r--r--plugins/check_dig.d/config.h10
-rw-r--r--plugins/check_disk.c1447
-rw-r--r--plugins/check_disk.d/utils_disk.c528
-rw-r--r--plugins/check_disk.d/utils_disk.h160
-rw-r--r--plugins/check_dns.c133
-rw-r--r--plugins/check_dummy.c15
-rw-r--r--plugins/check_fping.c168
-rw-r--r--plugins/check_fping.d/config.h23
-rw-r--r--plugins/check_game.c68
-rw-r--r--plugins/check_hpjd.c14
-rw-r--r--plugins/check_http.c3581
-rw-r--r--plugins/check_ide_smart.c90
-rw-r--r--plugins/check_ldap.c347
-rw-r--r--plugins/check_ldap.d/config.h24
-rw-r--r--plugins/check_load.c662
-rw-r--r--plugins/check_load.d/config.h30
-rw-r--r--plugins/check_mrtg.c177
-rw-r--r--plugins/check_mrtg.d/config.h17
-rw-r--r--plugins/check_mrtgtraf.c211
-rw-r--r--plugins/check_mrtgtraf.d/config.h19
-rw-r--r--plugins/check_mysql.c376
-rw-r--r--plugins/check_mysql.d/config.h13
-rw-r--r--plugins/check_mysql_query.c154
-rw-r--r--plugins/check_mysql_query.d/config.h10
-rw-r--r--plugins/check_nt.c756
-rw-r--r--plugins/check_nt.d/config.h53
-rw-r--r--plugins/check_ntp.c901
-rw-r--r--plugins/check_ntp_peer.c703
-rw-r--r--plugins/check_ntp_peer.d/config.h82
-rw-r--r--plugins/check_ntp_time.c351
-rw-r--r--plugins/check_ntp_time.d/config.h19
-rw-r--r--plugins/check_nwstat.c1527
-rw-r--r--plugins/check_pgsql.c337
-rw-r--r--plugins/check_pgsql.d/config.h29
-rw-r--r--plugins/check_ping.c580
-rw-r--r--plugins/check_ping.d/config.h46
-rw-r--r--plugins/check_procs.c1178
-rw-r--r--plugins/check_procs.d/config.h75
-rw-r--r--plugins/check_radius.c553
-rw-r--r--plugins/check_radius.d/config.h42
-rw-r--r--plugins/check_real.c269
-rw-r--r--plugins/check_real.d/config.h37
-rw-r--r--plugins/check_smtp.c810
-rw-r--r--plugins/check_smtp.d/config.h28
-rw-r--r--plugins/check_snmp.c1765
-rw-r--r--plugins/check_snmp.d/check_snmp_helpers.c936
-rw-r--r--plugins/check_snmp.d/check_snmp_helpers.h71
-rw-r--r--plugins/check_snmp.d/config.h81
-rw-r--r--plugins/check_ssh.c89
-rw-r--r--plugins/check_swap.c31
-rw-r--r--plugins/check_swap.d/check_swap.h8
-rw-r--r--plugins/check_swap.d/swap.c122
-rw-r--r--plugins/check_tcp.c872
-rw-r--r--plugins/check_tcp.d/config.h84
-rw-r--r--plugins/check_time.c198
-rw-r--r--plugins/check_time.d/config.h42
-rw-r--r--plugins/check_ups.c309
-rw-r--r--plugins/check_ups.d/config.h54
-rw-r--r--plugins/check_users.c268
-rw-r--r--plugins/check_users.d/config.h20
-rw-r--r--plugins/check_users.d/users.c169
-rw-r--r--plugins/check_users.d/users.h18
-rw-r--r--plugins/common.h181
-rw-r--r--plugins/negate.c138
-rw-r--r--plugins/negate.d/config.h24
-rw-r--r--plugins/netutils.c224
-rw-r--r--plugins/netutils.h172
-rw-r--r--plugins/picohttpparser/picohttpparser.c243
-rw-r--r--plugins/picohttpparser/picohttpparser.h31
-rw-r--r--plugins/popen.c68
-rw-r--r--plugins/popen.h20
-rw-r--r--plugins/runcmd.c82
-rw-r--r--plugins/runcmd.h47
-rw-r--r--plugins/sslutils.c387
-rw-r--r--plugins/t/check_apt.t14
-rw-r--r--plugins/t/check_by_ssh.t50
-rw-r--r--plugins/t/check_curl.t49
-rw-r--r--plugins/t/check_dbi.t10
-rw-r--r--plugins/t/check_disk.t220
-rw-r--r--plugins/t/check_ftp.t2
-rw-r--r--plugins/t/check_jabber.t4
-rw-r--r--plugins/t/check_ldap.t14
-rw-r--r--plugins/t/check_load.t18
-rw-r--r--plugins/t/check_mysql.t7
-rw-r--r--plugins/t/check_mysql_query.t2
-rw-r--r--plugins/t/check_ntp.t2
-rw-r--r--plugins/t/check_smtp.t7
-rw-r--r--plugins/t/check_snmp.t103
-rw-r--r--plugins/t/check_tcp.t12
-rw-r--r--plugins/t/check_udp.t4
-rw-r--r--plugins/t/check_users.t4
-rwxr-xr-xplugins/tests/check_curl.t273
-rwxr-xr-xplugins/tests/check_nt.t80
-rwxr-xr-xplugins/tests/check_snmp.t159
-rw-r--r--plugins/tests/check_snmp_agent.pl78
-rw-r--r--plugins/tests/conf/snmpd.conf2
-rw-r--r--plugins/tests/test_check_disk.c (renamed from lib/tests/test_disk.c)189
-rwxr-xr-xplugins/tests/test_check_disk.t6
-rw-r--r--plugins/tests/test_check_snmp.c175
-rwxr-xr-xplugins/tests/test_check_snmp.t6
-rw-r--r--plugins/tests/test_check_swap.c4
-rw-r--r--plugins/urlize.c36
-rw-r--r--plugins/utils.c35
-rw-r--r--plugins/utils.h51
-rw-r--r--tap/tap.c25
-rw-r--r--tap/tap.h43
-rw-r--r--tools/mini_epn.c96
706 files changed, 59632 insertions, 21331 deletions
diff --git a/.clang-format b/.clang-format
index ca411edd..0ff68114 100644
--- a/.clang-format
+++ b/.clang-format
@@ -4,7 +4,7 @@ TabWidth: 4
4AllowShortIfStatementsOnASingleLine: false 4AllowShortIfStatementsOnASingleLine: false
5BreakBeforeBraces: Attach 5BreakBeforeBraces: Attach
6AlignConsecutiveMacros: true 6AlignConsecutiveMacros: true
7ColumnLimit: 140 7ColumnLimit: 100
8IndentPPDirectives: AfterHash 8IndentPPDirectives: AfterHash
9SortIncludes: Never 9SortIncludes: Never
10AllowShortEnumsOnASingleLine: false 10AllowShortEnumsOnASingleLine: false
diff --git a/.github/monitoring-plugins.spec b/.github/monitoring-plugins.spec
index 64ee34f2..e3465227 100644
--- a/.github/monitoring-plugins.spec
+++ b/.github/monitoring-plugins.spec
@@ -88,6 +88,9 @@ BuildRequires: postgresql-devel
88# check_radius 88# check_radius
89BuildRequires: radcli-devel 89BuildRequires: radcli-devel
90 90
91# check_snmp
92BuildRequires: net-snmp-devel
93
91%description 94%description
92Common files for Monitoring Plugins 95Common files for Monitoring Plugins
93 96
@@ -191,7 +194,6 @@ Requires: %{name}-nt
191Requires: %{name}-ntp 194Requires: %{name}-ntp
192Requires: %{name}-ntp_peer 195Requires: %{name}-ntp_peer
193Requires: %{name}-ntp_time 196Requires: %{name}-ntp_time
194Requires: %{name}-nwstat
195Requires: %{name}-oracle 197Requires: %{name}-oracle
196Requires: %{name}-pgsql 198Requires: %{name}-pgsql
197Requires: %{name}-ping 199Requires: %{name}-ping
@@ -650,32 +652,6 @@ Provides check_nagios of the Monitoring Plugins.
650 652
651 653
652 654
653# check_nt
654%package nt
655Summary: Monitoring Plugins - check_nt
656Requires: %{name} = %{version}-%{release}
657
658%description nt
659Provides check_nt of the Monitoring Plugins.
660
661%files nt
662%{plugindir}/check_nt
663
664
665
666# check_ntp
667%package ntp
668Summary: Monitoring Plugins - check_ntp
669Requires: %{name} = %{version}-%{release}
670
671%description ntp
672Provides check_ntp of the Monitoring Plugins.
673
674%files ntp
675%{plugindir}/check_ntp
676
677
678
679# check_ntp_peer 655# check_ntp_peer
680%package ntp_peer 656%package ntp_peer
681Summary: Monitoring Plugins - check_ntp_peer 657Summary: Monitoring Plugins - check_ntp_peer
@@ -702,19 +678,6 @@ Provides check_ntp_time of the Monitoring Plugins.
702 678
703 679
704 680
705# check_nwstat
706%package nwstat
707Summary: Monitoring Plugins - check_nwstat
708Requires: %{name} = %{version}-%{release}
709
710%description nwstat
711Provides check_nwstat of the Monitoring Plugins.
712
713%files nwstat
714%{plugindir}/check_nwstat
715
716
717
718# check_oracle 681# check_oracle
719%package oracle 682%package oracle
720Summary: Monitoring Plugins - check_oracle 683Summary: Monitoring Plugins - check_oracle
@@ -959,3 +922,7 @@ Provides check_wave of the Monitoring Plugins.
959 922
960%files wave 923%files wave
961%{plugindir}/check_wave 924%{plugindir}/check_wave
925
926%changelog
927* Wed Oct 20 2011 John Doe <jdoe@example.com> 0.8.18.1-0.1
928- Initial RPM release
diff --git a/.github/os_detect.sh b/.github/os_detect.sh
index ee9c145d..3c5956de 100644
--- a/.github/os_detect.sh
+++ b/.github/os_detect.sh
@@ -1,10 +1,17 @@
1#!/bin/sh -e 1#!/bin/sh -e
2
3. /etc/os-release
4
2# workaround for really bare-bones Archlinux containers: 5# workaround for really bare-bones Archlinux containers:
3if [ -x "$(command -v pacman)" ]; then 6if [ -x "$(command -v pacman)" ]; then
4 pacman --noconfirm -Sy 7 pacman --noconfirm -Sy
5 pacman --noconfirm -S grep gawk sed 8 pacman --noconfirm -S grep gawk sed
6fi 9fi
7 10
11if [ ${ID} == "fedora" -a ${VERSION_ID} -gt 41 ]; then
12 dnf install -y gawk
13fi
14
8os_release_file= 15os_release_file=
9if [ -s "/etc/os-release" ]; then 16if [ -s "/etc/os-release" ]; then
10 os_release_file="/etc/os-release" 17 os_release_file="/etc/os-release"
@@ -15,4 +22,7 @@ else
15 return 1 22 return 1
16fi 23fi
17export distro_id=$(grep '^ID=' $os_release_file|awk -F = '{print $2}'|sed 's/\"//g') 24export distro_id=$(grep '^ID=' $os_release_file|awk -F = '{print $2}'|sed 's/\"//g')
25export version_id=$(grep '^VERSION_ID=' $os_release_file|awk -F = '{print $2}'|sed 's/\"//g')
18export platform_id=$(grep '^PLATFORM_ID=' /etc/os-release|awk -F = '{print $2}'|sed 's/\"//g'| cut -d":" -f2) 26export platform_id=$(grep '^PLATFORM_ID=' /etc/os-release|awk -F = '{print $2}'|sed 's/\"//g'| cut -d":" -f2)
27# Fedora dropped PLATFORM_ID: https://fedoraproject.org/wiki/Changes/Drop_PLATFORM_ID?#Drop_PLATFORM_ID
28if [ -z $platform_id ]; then export platform_id=$(echo ${distro_id:0:1}${version_id}); fi
diff --git a/.github/prepare_debian.sh b/.github/prepare_debian.sh
index f7b6cf9f..cffe98c5 100755
--- a/.github/prepare_debian.sh
+++ b/.github/prepare_debian.sh
@@ -24,6 +24,7 @@ apt-get -y install perl \
24 libpq-dev \ 24 libpq-dev \
25 libradcli-dev \ 25 libradcli-dev \
26 libnet-snmp-perl \ 26 libnet-snmp-perl \
27 libsnmp-dev \
27 procps \ 28 procps \
28 libdbi0-dev \ 29 libdbi0-dev \
29 libdbd-sqlite3 \ 30 libdbd-sqlite3 \
@@ -111,6 +112,8 @@ mkdir -p /var/lib/snmp/mib_indexes
111sed -e 's/^agentaddress.*/agentaddress 127.0.0.1/' -i /etc/snmp/snmpd.conf 112sed -e 's/^agentaddress.*/agentaddress 127.0.0.1/' -i /etc/snmp/snmpd.conf
112service snmpd start 113service snmpd start
113 114
115sed 's/^mibs ://' -i /etc/snmp/snmp.conf
116
114# start cron, will be used by check_nagios 117# start cron, will be used by check_nagios
115cron 118cron
116 119
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index c402e0cf..bd1037f4 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -13,6 +13,7 @@
13name: "CodeQL" 13name: "CodeQL"
14 14
15on: 15on:
16 workflow_dispatch: {}
16 push: 17 push:
17 branches: [master] 18 branches: [master]
18 pull_request: 19 pull_request:
@@ -40,11 +41,11 @@ jobs:
40 41
41 steps: 42 steps:
42 - name: Checkout repository 43 - name: Checkout repository
43 uses: actions/checkout@v4 44 uses: actions/checkout@v6
44 45
45 # Initializes the CodeQL tools for scanning. 46 # Initializes the CodeQL tools for scanning.
46 - name: Initialize CodeQL 47 - name: Initialize CodeQL
47 uses: github/codeql-action/init@v3 48 uses: github/codeql-action/init@v4
48 with: 49 with:
49 languages: ${{ matrix.language }} 50 languages: ${{ matrix.language }}
50 # If you wish to specify custom queries, you can do so here or in a config file. 51 # If you wish to specify custom queries, you can do so here or in a config file.
@@ -56,9 +57,20 @@ jobs:
56 run: | 57 run: |
57 sudo apt update 58 sudo apt update
58 sudo apt-get install -y --no-install-recommends m4 gettext automake autoconf make build-essential 59 sudo apt-get install -y --no-install-recommends m4 gettext automake autoconf make build-essential
59 sudo apt-get install -y --no-install-recommends perl autotools-dev libdbi-dev libldap2-dev libpq-dev \ 60 sudo apt-get install -y --no-install-recommends perl \
60 libmysqlclient-dev libradcli-dev libkrb5-dev libdbi0-dev \ 61 autotools-dev \
61 libdbd-sqlite3 libssl-dev libcurl4-openssl-dev liburiparser-dev 62 libdbi-dev \
63 libldap2-dev \
64 libpq-dev \
65 libmysqlclient-dev \
66 libradcli-dev \
67 libkrb5-dev \
68 libdbi0-dev \
69 libdbd-sqlite3 \
70 libssl-dev \
71 libcurl4-openssl-dev \
72 liburiparser-dev \
73 libsnmp-dev
62 74
63 - name: Configure build 75 - name: Configure build
64 run: | 76 run: |
@@ -70,4 +82,4 @@ jobs:
70 make 82 make
71 83
72 - name: Perform CodeQL Analysis 84 - name: Perform CodeQL Analysis
73 uses: github/codeql-action/analyze@v3 85 uses: github/codeql-action/analyze@v4
diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml
index 72f7c7eb..f19cc920 100644
--- a/.github/workflows/spellcheck.yml
+++ b/.github/workflows/spellcheck.yml
@@ -2,6 +2,7 @@
2name: Spellcheck 2name: Spellcheck
3 3
4on: 4on:
5 workflow_dispatch: {}
5 # Run for pushes on any branch 6 # Run for pushes on any branch
6 push: 7 push:
7 branches: 8 branches:
@@ -17,7 +18,7 @@ jobs:
17 runs-on: ubuntu-latest 18 runs-on: ubuntu-latest
18 steps: 19 steps:
19 - name: Checkout 20 - name: Checkout
20 uses: actions/checkout@v4 21 uses: actions/checkout@v6
21 - name: Codespell 22 - name: Codespell
22 uses: codespell-project/actions-codespell@v2 23 uses: codespell-project/actions-codespell@v2
23 with: 24 with:
diff --git a/.github/workflows/test-next.yml b/.github/workflows/test-next.yml
index 81240759..a7e9b9d6 100644
--- a/.github/workflows/test-next.yml
+++ b/.github/workflows/test-next.yml
@@ -2,7 +2,13 @@
2name: Tests Debian:Testing and Fedora:Rawhide 2name: Tests Debian:Testing and Fedora:Rawhide
3 3
4on: 4on:
5 workflow_dispatch: {} 5 workflow_dispatch:
6 inputs:
7 debug_enabled:
8 type: boolean
9 description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
10 required: false
11 default: false
6 push: 12 push:
7 branches-ignore: 13 branches-ignore:
8 - '*' 14 - '*'
@@ -24,7 +30,10 @@ jobs:
24 prepare: .github/prepare_debian.sh 30 prepare: .github/prepare_debian.sh
25 steps: 31 steps:
26 - name: Git clone repository 32 - name: Git clone repository
27 uses: actions/checkout@v4 33 uses: actions/checkout@v6
34 - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate
35 uses: mxschmitt/action-tmate@v3
36 if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
28 - name: Run the tests on ${{ matrix.distro }} 37 - name: Run the tests on ${{ matrix.distro }}
29 run: | 38 run: |
30 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol 39 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol
@@ -38,7 +47,7 @@ jobs:
38 ${{ matrix.distro }} \ 47 ${{ matrix.distro }} \
39 /bin/sh -c '${{ matrix.prepare }} && \ 48 /bin/sh -c '${{ matrix.prepare }} && \
40 tools/setup && \ 49 tools/setup && \
41 ./configure --enable-libtap --with-ipv6=no && \ 50 ./configure --enable-libtap && \
42 make && \ 51 make && \
43 make test && \ 52 make test && \
44 make dist && \ 53 make dist && \
@@ -59,7 +68,10 @@ jobs:
59 - {"distro": "fedora:rawhide", "build": ".github/mock.sh"} 68 - {"distro": "fedora:rawhide", "build": ".github/mock.sh"}
60 steps: 69 steps:
61 - name: Git clone repository 70 - name: Git clone repository
62 uses: actions/checkout@v4 71 uses: actions/checkout@v6
72 - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate
73 uses: mxschmitt/action-tmate@v3
74 if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
63 - name: Run the tests on ${{ matrix.distro }} 75 - name: Run the tests on ${{ matrix.distro }}
64 run: | 76 run: |
65 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol 77 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 77ca6585..5a0b2943 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -2,6 +2,13 @@
2name: Tests 2name: Tests
3 3
4on: 4on:
5 workflow_dispatch:
6 inputs:
7 debug_enabled:
8 type: boolean
9 description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
10 required: false
11 default: false
5 push: 12 push:
6 branches: 13 branches:
7 - '*' 14 - '*'
@@ -21,7 +28,10 @@ jobs:
21 prepare: .github/prepare_debian.sh 28 prepare: .github/prepare_debian.sh
22 steps: 29 steps:
23 - name: Git clone repository 30 - name: Git clone repository
24 uses: actions/checkout@v4 31 uses: actions/checkout@v6
32 - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate
33 uses: mxschmitt/action-tmate@v3
34 if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
25 - name: Run the tests on ${{ matrix.distro }} 35 - name: Run the tests on ${{ matrix.distro }}
26 run: | 36 run: |
27 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol 37 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol
@@ -35,7 +45,7 @@ jobs:
35 ${{ matrix.distro }} \ 45 ${{ matrix.distro }} \
36 /bin/sh -c '${{ matrix.prepare }} && \ 46 /bin/sh -c '${{ matrix.prepare }} && \
37 tools/setup && \ 47 tools/setup && \
38 ./configure --enable-libtap --with-ipv6=no && \ 48 ./configure --enable-libtap && \
39 make && \ 49 make && \
40 make test && \ 50 make test && \
41 make dist && \ 51 make dist && \
@@ -59,7 +69,10 @@ jobs:
59# - {"distro": "oraclelinux:9", "build": ".github/mock.sh"} 69# - {"distro": "oraclelinux:9", "build": ".github/mock.sh"}
60 steps: 70 steps:
61 - name: Git clone repository 71 - name: Git clone repository
62 uses: actions/checkout@v4 72 uses: actions/checkout@v6
73 - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate
74 uses: mxschmitt/action-tmate@v3
75 if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
63 - name: Run the tests on ${{ matrix.distro }} 76 - name: Run the tests on ${{ matrix.distro }}
64 run: | 77 run: |
65 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol 78 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol
diff --git a/.gitignore b/.gitignore
index f9cb37e4..d0115b05 100644
--- a/.gitignore
+++ b/.gitignore
@@ -114,7 +114,6 @@ NP-VERSION-FILE
114/lib/tests/Makefile.in 114/lib/tests/Makefile.in
115/lib/tests/test_base64 115/lib/tests/test_base64
116/lib/tests/test_cmd 116/lib/tests/test_cmd
117/lib/tests/test_disk
118/lib/tests/test_tcp 117/lib/tests/test_tcp
119/lib/tests/test_utils 118/lib/tests/test_utils
120/lib/tests/utils_base.Po 119/lib/tests/utils_base.Po
@@ -153,6 +152,8 @@ NP-VERSION-FILE
153/plugins/check_dbi 152/plugins/check_dbi
154/plugins/check_dig 153/plugins/check_dig
155/plugins/check_disk 154/plugins/check_disk
155plugins/check_disk.d/.deps/
156plugins/check_disk.d/.dirstamp
156/plugins/check_dns 157/plugins/check_dns
157/plugins/check_dummy 158/plugins/check_dummy
158/plugins/check_fping 159/plugins/check_fping
@@ -173,11 +174,8 @@ NP-VERSION-FILE
173/plugins/check_netsaint 174/plugins/check_netsaint
174/plugins/check_nntp 175/plugins/check_nntp
175/plugins/check_nntps 176/plugins/check_nntps
176/plugins/check_nt
177/plugins/check_ntp
178/plugins/check_ntp_peer 177/plugins/check_ntp_peer
179/plugins/check_ntp_time 178/plugins/check_ntp_time
180/plugins/check_nwstat
181/plugins/check_pgsql 179/plugins/check_pgsql
182/plugins/check_ping 180/plugins/check_ping
183/plugins/check_pop 181/plugins/check_pop
@@ -197,6 +195,8 @@ NP-VERSION-FILE
197/plugins/check_udp 195/plugins/check_udp
198/plugins/check_ups 196/plugins/check_ups
199/plugins/check_users 197/plugins/check_users
198/plugins/check_users.d/.deps
199/plugins/check_users.d/.dirstamp
200/plugins/check_vsz 200/plugins/check_vsz
201/plugins/config.h 201/plugins/config.h
202/plugins/config.h.in 202/plugins/config.h.in
@@ -222,7 +222,7 @@ NP-VERSION-FILE
222/plugins/tests/Makefile 222/plugins/tests/Makefile
223/plugins/tests/Makefile.in 223/plugins/tests/Makefile.in
224/plugins/tests/test_utils 224/plugins/tests/test_utils
225/plugins/tests/test_disk 225/plugins/tests/test_check_disk
226/plugins/tests/test_check_swap 226/plugins/tests/test_check_swap
227/plugins/tests/.deps 227/plugins/tests/.deps
228/plugins/tests/.dirstamp 228/plugins/tests/.dirstamp
@@ -231,6 +231,14 @@ NP-VERSION-FILE
231/plugins/check_swap.d/.deps 231/plugins/check_swap.d/.deps
232/plugins/check_swap.d/.dirstamp 232/plugins/check_swap.d/.dirstamp
233 233
234# /plugins/check_snmp.d
235/plugins/check_snmp.d/.deps
236/plugins/check_snmp.d/.dirstamp
237
238# /plugins/check_curl.d
239/plugins/check_curl.d/.deps
240/plugins/check_curl.d/.dirstamp
241
234# /plugins-root/ 242# /plugins-root/
235/plugins-root/.deps 243/plugins-root/.deps
236/plugins-root/.libs 244/plugins-root/.libs
@@ -239,6 +247,8 @@ NP-VERSION-FILE
239/plugins-root/check_dhcp 247/plugins-root/check_dhcp
240/plugins-root/check_icmp 248/plugins-root/check_icmp
241/plugins-root/pst3 249/plugins-root/pst3
250/plugins-root/check_icmp.d/.dirstamp
251/plugins-root/check_icmp.d/.deps
242 252
243# /plugins-scripts/ 253# /plugins-scripts/
244/plugins-scripts/Makefile 254/plugins-scripts/Makefile
diff --git a/REQUIREMENTS b/REQUIREMENTS
index f3b1c01d..8f1befbd 100644
--- a/REQUIREMENTS
+++ b/REQUIREMENTS
@@ -26,7 +26,7 @@ check_curl:
26 other SSL implementations are currently not supported 26 other SSL implementations are currently not supported
27 - uriparser 0.7.5 or later 27 - uriparser 0.7.5 or later
28 https://uriparser.github.io/ 28 https://uriparser.github.io/
29 29
30check_fping: 30check_fping:
31 - Requires the fping utility distributed with SATAN. Either 31 - Requires the fping utility distributed with SATAN. Either
32 download and install SATAN or grab the fping program from 32 download and install SATAN or grab the fping program from
@@ -87,20 +87,12 @@ check_ifstatus/check_ifoperstatus
87 - Requires Net::SNMP perl module 87 - Requires Net::SNMP perl module
88 http://www.perl.com/CPAN/modules/by-authors/id/D/DT/DTOWN/ 88 http://www.perl.com/CPAN/modules/by-authors/id/D/DT/DTOWN/
89 89
90check_nwstat:
91 - Requires MRTGEXT NLM for Novell Servers
92 http://forge.novell.com/modules/xfmod/project/?mrtgext
93
94check_nt:
95 - Requires NSClient to run on the NT server to monitor
96 http://nsclient.ready2run.nl/
97
98check_ups: 90check_ups:
99 - Requires Network UPS Tools (>= 1.4) to run on the server to monitor 91 - Requires Network UPS Tools (>= 1.4) to run on the server to monitor
100 http://www.networkupstools.org/ 92 http://www.networkupstools.org/
101 93
102check_ide_smart: 94check_ide_smart:
103 - Uses the Linux specific SMART interface [http://smartlinux.sourceforge.net/smart/index.php]. 95 - Uses the Linux specific SMART interface [http://smartlinux.sourceforge.net/smart/index.php].
104 96
105OS Specific Issues 97OS Specific Issues
106------------------ 98------------------
diff --git a/THANKS.in b/THANKS.in
index 66397ad1..5dbb1b39 100644
--- a/THANKS.in
+++ b/THANKS.in
@@ -426,3 +426,4 @@ Eunice Remoquillo
426Louis Sautier 426Louis Sautier
427Sven Hartge 427Sven Hartge
428Alvar Penning 428Alvar Penning
429Michael Jeanson
diff --git a/configure.ac b/configure.ac
index 204fc6e3..abd90413 100644
--- a/configure.ac
+++ b/configure.ac
@@ -181,10 +181,10 @@ fi
181 181
182# Finally, define tests if we use libtap 182# Finally, define tests if we use libtap
183if test "$enable_libtap" = "yes" ; then 183if test "$enable_libtap" = "yes" ; then
184 EXTRA_TEST="test_utils test_disk test_tcp test_cmd test_base64" 184 EXTRA_TEST="test_utils test_tcp test_cmd test_base64"
185 AC_SUBST(EXTRA_TEST) 185 AC_SUBST(EXTRA_TEST)
186 186
187 EXTRA_PLUGIN_TESTS="tests/test_check_swap" 187 EXTRA_PLUGIN_TESTS="tests/test_check_swap tests/test_check_disk"
188 AC_SUBST(EXTRA_PLUGIN_TESTS) 188 AC_SUBST(EXTRA_PLUGIN_TESTS)
189fi 189fi
190 190
@@ -205,32 +205,46 @@ fi
205dnl Check for PostgreSQL libraries 205dnl Check for PostgreSQL libraries
206_SAVEDLIBS="$LIBS" 206_SAVEDLIBS="$LIBS"
207_SAVEDCPPFLAGS="$CPPFLAGS" 207_SAVEDCPPFLAGS="$CPPFLAGS"
208case $host in
209 *openbsd*)
210 _CRYPTLIB="crypto"
211 ;;
212 *)
213 _CRYPTLIB="crypt"
214esac
215
208AC_ARG_WITH(pgsql, 216AC_ARG_WITH(pgsql,
209 ACX_HELP_STRING([--with-pgsql=DIR], 217 ACX_HELP_STRING([--with-pgsql=DIR],
210 [sets path to pgsql installation]), 218 [sets path to pgsql installation]),
211 PGSQL=$withval,) 219 PGSQL=$withval,)
212AC_CHECK_LIB(crypt,main) 220AC_CHECK_LIB(crypt,main)
213if test "$ac_cv_lib_crypt_main" = "yes" -a "x$PGSQL" != "xno"; then 221AC_CHECK_LIB(crypto,main)
222if test \( "$ac_cv_lib_crypt_main" = "yes" -o "$ac_cv_lib_crypto_main" = "yes" \) -a "x$PGSQL" != "xno"; then
214 if test -n "$PGSQL"; then 223 if test -n "$PGSQL"; then
215 LDFLAGS="$LDFLAGS -L$PGSQL/lib" 224 LDFLAGS="$LDFLAGS -L$PGSQL/lib"
216 CPPFLAGS="$CPPFLAGS -I$PGSQL/include" 225 CPPFLAGS="$CPPFLAGS -I$PGSQL/include"
217 fi 226 fi
218 AC_CHECK_LIB(pq,PQsetdbLogin,,,-lcrypt) 227 AC_CHECK_LIB(pq,PQsetdbLogin,,,"-l$_CRYPTLIB")
219 if test "$ac_cv_lib_pq_PQsetdbLogin" = "yes"; then 228 if test "$ac_cv_lib_pq_PQsetdbLogin" = "yes"; then
220 AC_CHECK_HEADERS(pgsql/libpq-fe.h) 229 AC_CHECK_HEADERS(pgsql/libpq-fe.h)
221 AC_CHECK_HEADERS(postgresql/libpq-fe.h) 230 AC_CHECK_HEADERS(postgresql/libpq-fe.h)
222 AC_CHECK_HEADERS(libpq-fe.h) 231 AC_CHECK_HEADERS(libpq-fe.h)
223 if [[ -n "$PGSQL" -a "$ac_cv_header_libpq_fe_h" = "yes" ]]; then 232 if [[ -n "$PGSQL" -a "$ac_cv_header_libpq_fe_h" = "yes" ]]; then
224 PGLIBS="-L$PGSQL/lib -lpq -lcrypt" 233 PGLIBS="-L$PGSQL/lib -lpq -l$_CRYPTLIB"
225 PGINCLUDE="-I$PGSQL/include" 234 PGINCLUDE="-I$PGSQL/include"
226 elif test "$ac_cv_header_pgsql_libpq_fe_h" = "yes"; then 235 elif test "$ac_cv_header_pgsql_libpq_fe_h" = "yes"; then
227 PGLIBS="-lpq -lcrypt" 236 PGLIBS="-lpq -l$_CRYPTLIB"
228 PGINCLUDE="-I/usr/include/pgsql" 237 PGINCLUDE="-I/usr/include/pgsql"
229 elif test "$ac_cv_header_postgresql_libpq_fe_h" = "yes"; then 238 elif test "$ac_cv_header_postgresql_libpq_fe_h" = "yes"; then
230 PGLIBS="-L$PGSQL/lib -lpq -lcrypt" 239 PGLIBS="-L$PGSQL/lib -lpq -l$_CRYPTLIB"
231 PGINCLUDE="-I/usr/include/postgresql" 240 case $host in
241 *openbsd*)
242 PGINCLUDE="-I$PGSQL/include/postgresql" ;;
243 *)
244 PGINCLUDE="-I/usr/include/postgresql"
245 esac
232 elif test "$ac_cv_header_libpq_fe_h" = "yes"; then 246 elif test "$ac_cv_header_libpq_fe_h" = "yes"; then
233 PGLIBS="-L$PGSQL/lib -lpq -lcrypt" 247 PGLIBS="-L$PGSQL/lib -lpq -l$_CRYPTLIB"
234 PGINCLUDE="-I$PGSQL/include" 248 PGINCLUDE="-I$PGSQL/include"
235 fi 249 fi
236 if test -z "$PGINCLUDE"; then 250 if test -z "$PGINCLUDE"; then
@@ -796,7 +810,7 @@ elif ps axwo 'stat comm vsz rss user uid pid ppid etime args' 2>/dev/null | \
796then 810then
797 ac_cv_ps_varlist="[procstat,&procuid,&procpid,&procppid,&procvsz,&procrss,&procpcpu,procetime,procprog,&pos]" 811 ac_cv_ps_varlist="[procstat,&procuid,&procpid,&procppid,&procvsz,&procrss,&procpcpu,procetime,procprog,&pos]"
798 ac_cv_ps_command="$PATH_TO_PS axwo 'stat uid pid ppid vsz rss pcpu etime comm args'" 812 ac_cv_ps_command="$PATH_TO_PS axwo 'stat uid pid ppid vsz rss pcpu etime comm args'"
799 ac_cv_ps_format="%s %d %d %d %d %d %f %s %s %n" 813 ac_cv_ps_format="%s %u %d %d %d %d %f %s %s %n"
800 ac_cv_ps_cols=10 814 ac_cv_ps_cols=10
801 AC_MSG_RESULT([$ac_cv_ps_command]) 815 AC_MSG_RESULT([$ac_cv_ps_command])
802 816
@@ -1470,17 +1484,6 @@ AC_ARG_WITH(snmpgetnext_command,
1470AS_IF([test -n "$PATH_TO_SNMPGET"], [ 1484AS_IF([test -n "$PATH_TO_SNMPGET"], [
1471 AC_DEFINE_UNQUOTED(PATH_TO_SNMPGET,"$PATH_TO_SNMPGET",[path to snmpget binary]) 1485 AC_DEFINE_UNQUOTED(PATH_TO_SNMPGET,"$PATH_TO_SNMPGET",[path to snmpget binary])
1472 EXTRAS="$EXTRAS check_hpjd" 1486 EXTRAS="$EXTRAS check_hpjd"
1473
1474 dnl PATH_TO_SNMPGETNEXT is used unconditionally in check_snmp:
1475 dnl
1476 dnl https://github.com/nagios-plugins/nagios-plugins/issues/788
1477 dnl
1478 AS_IF([test -n "$PATH_TO_SNMPGETNEXT"], [
1479 AC_DEFINE_UNQUOTED(PATH_TO_SNMPGETNEXT,"$PATH_TO_SNMPGETNEXT",[path to snmpgetnext binary])
1480 EXTRAS="$EXTRAS check_snmp\$(EXEEXT)"
1481 ], [
1482 AC_MSG_WARN([Get snmpgetnext from https://net-snmp.sourceforge.io/ to build the check_snmp plugin])
1483 ])
1484], [ 1487], [
1485 AC_MSG_WARN([Get snmpget from https://net-snmp.sourceforge.io/ to build the check_hpjd and check_snmp plugins]) 1488 AC_MSG_WARN([Get snmpget from https://net-snmp.sourceforge.io/ to build the check_hpjd and check_snmp plugins])
1486]) 1489])
@@ -1493,6 +1496,16 @@ else
1493 AC_MSG_WARN([Tried $PERL - install Net::SNMP perl module if you want to use the perl snmp plugins]) 1496 AC_MSG_WARN([Tried $PERL - install Net::SNMP perl module if you want to use the perl snmp plugins])
1494fi 1497fi
1495 1498
1499dnl Check whether DES encryption is available (might not on RHEL)
1500AC_COMPILE_IFELSE(
1501 [AC_LANG_PROGRAM(
1502 [[#include <net-snmp/net-snmp-config.h>
1503 #include <net-snmp/net-snmp-includes.h>]], [[oid *foo = usmDESPrivProtocol;]]
1504 )],
1505 [AC_DEFINE(HAVE_USM_DES_PRIV_PROTOCOL,1,Define whether we have DES Privacy Protocol)],
1506 []
1507)
1508
1496AC_PATH_PROG(PATH_TO_QUAKESTAT,quakestat) 1509AC_PATH_PROG(PATH_TO_QUAKESTAT,quakestat)
1497AC_PATH_PROG(PATH_TO_QSTAT,qstat) 1510AC_PATH_PROG(PATH_TO_QSTAT,qstat)
1498AC_ARG_WITH(qstat_command, 1511AC_ARG_WITH(qstat_command,
@@ -1519,21 +1532,47 @@ then
1519fi 1532fi
1520 1533
1521AC_PATH_PROG(PATH_TO_FPING,fping) 1534AC_PATH_PROG(PATH_TO_FPING,fping)
1522AC_PATH_PROG(PATH_TO_FPING6,fping6)
1523 1535
1524AC_ARG_WITH(fping_command, 1536AC_ARG_WITH(fping_command,
1525 ACX_HELP_STRING([--with-fping-command=PATH], 1537 ACX_HELP_STRING([--with-fping-command=PATH],
1526 [Path to fping command]), PATH_TO_FPING=$withval) 1538 [Path to fping command]), PATH_TO_FPING=$withval)
1527AC_ARG_WITH(fping6_command, 1539if test -n "$PATH_TO_FPING"; then
1528 ACX_HELP_STRING([--with-fping6-command=PATH],
1529 [Path to fping6 command]), PATH_TO_FPING6=$withval)
1530
1531if test -n "$PATH_TO_FPING"
1532then
1533 AC_DEFINE_UNQUOTED(PATH_TO_FPING,"$PATH_TO_FPING",[path to fping]) 1540 AC_DEFINE_UNQUOTED(PATH_TO_FPING,"$PATH_TO_FPING",[path to fping])
1534 EXTRAS="$EXTRAS check_fping\$(EXEEXT)" 1541 EXTRAS="$EXTRAS check_fping\$(EXEEXT)"
1535 if test x"$with_ipv6" != xno && test -n "$PATH_TO_FPING6"; then 1542
1536 AC_DEFINE_UNQUOTED(PATH_TO_FPING6,"$PATH_TO_FPING6",[path to fping6]) 1543 if test -z "$($PATH_TO_FPING --version)" ; then
1544 AC_MSG_NOTICE([failed to get version of fping])
1545 else
1546 FPING_MAJOR_VERSION="$($PATH_TO_FPING --version | sed 's/.*fping: Version //' | sed 's/\..*//')"
1547 FPING_MINOR_VERSION="$($PATH_TO_FPING --version | sed 's/.*fping: Version //' | sed 's/.*\.//')"
1548
1549 if test $FPING_MAJOR_VERSION -eq 5 ; then
1550 if test $FPING_MINOR_VERSION -ge 3 ; then
1551 AC_DEFINE(FPING_VERSION_5_3_OR_HIGHER, "true", [fping is of version 5.3 or higher])
1552 AC_MSG_NOTICE([fping is of version 5.3 or higher])
1553 AC_DEFINE(FPING_VERSION_5_2_OR_HIGHER, "true", [fping is of version 5.2 or higher])
1554 AC_MSG_NOTICE([fping is of version 5.2 or higher])
1555 elif test $FPING_MINOR_VERSION -ge 2 ; then
1556 AC_DEFINE(FPING_VERSION_5_2_OR_HIGHER, "true", [fping is of version 5.2 or higher])
1557 AC_MSG_NOTICE([fping is of version 5.2 or higher])
1558 else
1559 AC_MSG_NOTICE([fping is of a version lower then 5.2])
1560 fi
1561
1562 elif $FPING_MAJOR_VERSION > 5 ; then
1563 AC_DEFINE(FPING_VERSION_5_2_OR_HIGHER, "true", [fping is of version 5.2 or higher])
1564 AC_MSG_NOTICE([fping is of version 5.2 or higher])
1565 AC_DEFINE(FPING_VERSION_5_3_OR_HIGHER, "true", [fping is of version 5.2 or higher])
1566 AC_MSG_NOTICE([fping is of version 5.3 or higher])
1567 fi
1568
1569 if test "`fping --version | sed 's/.*fping: Version //'`" = "5.2" ; then
1570 AC_DEFINE(FPING_VERSION, "5.2", [the version of fping available])
1571 AC_MSG_NOTICE([fping version: 5.2])
1572 elif test "`fping --version | sed 's/.*fping: Version //'`" = "5.3"; then
1573 AC_DEFINE(FPING_VERSION, "5.3", [the version of fping available])
1574 AC_MSG_NOTICE([fping version: 5.3])
1575 fi
1537 fi 1576 fi
1538else 1577else
1539 AC_MSG_WARN([Get fping from http://www.fping.com in order to make check_fping plugin]) 1578 AC_MSG_WARN([Get fping from http://www.fping.com in order to make check_fping plugin])
@@ -1807,11 +1846,6 @@ if test -n "$PATH_TO_APTGET" ; then
1807fi 1846fi
1808 1847
1809 1848
1810if test -f $srcdir/plugins/check_nt.c ; then
1811 EXTRAS="$EXTRAS check_nt\$(EXEEXT)"
1812fi
1813
1814
1815dnl used in check_dhcp 1849dnl used in check_dhcp
1816AC_CHECK_HEADERS(sys/sockio.h) 1850AC_CHECK_HEADERS(sys/sockio.h)
1817 1851
diff --git a/gl/Makefile.am b/gl/Makefile.am
index df988b37..f462fdb7 100644
--- a/gl/Makefile.am
+++ b/gl/Makefile.am
@@ -1,6 +1,6 @@
1## DO NOT EDIT! GENERATED AUTOMATICALLY! 1## DO NOT EDIT! GENERATED AUTOMATICALLY!
2## Process this file with automake to produce Makefile.in. 2## Process this file with automake to produce Makefile.in.
3# Copyright (C) 2002-2024 Free Software Foundation, Inc. 3# Copyright (C) 2002-2025 Free Software Foundation, Inc.
4# 4#
5# This file is free software; you can redistribute it and/or modify 5# This file is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by 6# it under the terms of the GNU General Public License as published by
@@ -80,9 +80,9 @@ AM_CFLAGS =
80noinst_LIBRARIES += libgnu.a 80noinst_LIBRARIES += libgnu.a
81 81
82libgnu_a_SOURCES = 82libgnu_a_SOURCES =
83libgnu_a_CFLAGS = $(AM_CFLAGS) $(GL_CFLAG_GNULIB_WARNINGS) 83libgnu_a_CFLAGS = $(AM_CFLAGS) $(GL_CFLAG_GNULIB_WARNINGS) $(GL_CFLAG_ALLOW_WARNINGS)
84libgnu_a_LIBADD = $(gl_LIBOBJS) 84libgnu_a_LIBADD = $(gl_libgnu_LIBOBJS)
85libgnu_a_DEPENDENCIES = $(gl_LIBOBJS) 85libgnu_a_DEPENDENCIES = $(gl_libgnu_LIBOBJS)
86EXTRA_libgnu_a_SOURCES = 86EXTRA_libgnu_a_SOURCES =
87 87
88## begin gnulib module absolute-header 88## begin gnulib module absolute-header
@@ -116,9 +116,10 @@ EXTRA_DIST += alloca.in.h
116 116
117## end gnulib module alloca-opt 117## end gnulib module alloca-opt
118 118
119## begin gnulib module arpa_inet 119## begin gnulib module arpa_inet-h
120 120
121BUILT_SOURCES += arpa/inet.h 121BUILT_SOURCES += arpa/inet.h
122libgnu_a_SOURCES += arpa_inet.c
122 123
123# We need the following in order to create <arpa/inet.h> when the system 124# We need the following in order to create <arpa/inet.h> when the system
124# doesn't have one. 125# doesn't have one.
@@ -135,8 +136,12 @@ arpa/inet.h: arpa_inet.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(WARN_ON
135 -e 's/@''GNULIB_INET_NTOP''@/$(GL_GNULIB_INET_NTOP)/g' \ 136 -e 's/@''GNULIB_INET_NTOP''@/$(GL_GNULIB_INET_NTOP)/g' \
136 -e 's/@''GNULIB_INET_PTON''@/$(GL_GNULIB_INET_PTON)/g' \ 137 -e 's/@''GNULIB_INET_PTON''@/$(GL_GNULIB_INET_PTON)/g' \
137 -e 's|@''HAVE_WS2TCPIP_H''@|$(HAVE_WS2TCPIP_H)|g' \ 138 -e 's|@''HAVE_WS2TCPIP_H''@|$(HAVE_WS2TCPIP_H)|g' \
139 -e 's|@''HAVE_DECL_HTONL''@|$(HAVE_DECL_HTONL)|g' \
140 -e 's|@''HAVE_DECL_HTONS''@|$(HAVE_DECL_HTONS)|g' \
138 -e 's|@''HAVE_DECL_INET_NTOP''@|$(HAVE_DECL_INET_NTOP)|g' \ 141 -e 's|@''HAVE_DECL_INET_NTOP''@|$(HAVE_DECL_INET_NTOP)|g' \
139 -e 's|@''HAVE_DECL_INET_PTON''@|$(HAVE_DECL_INET_PTON)|g' \ 142 -e 's|@''HAVE_DECL_INET_PTON''@|$(HAVE_DECL_INET_PTON)|g' \
143 -e 's|@''HAVE_DECL_NTOHL''@|$(HAVE_DECL_NTOHL)|g' \
144 -e 's|@''HAVE_DECL_NTOHS''@|$(HAVE_DECL_NTOHS)|g' \
140 -e 's|@''REPLACE_INET_NTOP''@|$(REPLACE_INET_NTOP)|g' \ 145 -e 's|@''REPLACE_INET_NTOP''@|$(REPLACE_INET_NTOP)|g' \
141 -e 's|@''REPLACE_INET_PTON''@|$(REPLACE_INET_PTON)|g' \ 146 -e 's|@''REPLACE_INET_PTON''@|$(REPLACE_INET_PTON)|g' \
142 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ 147 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
@@ -149,7 +154,7 @@ MOSTLYCLEANDIRS += arpa
149 154
150EXTRA_DIST += arpa_inet.in.h 155EXTRA_DIST += arpa_inet.in.h
151 156
152## end gnulib module arpa_inet 157## end gnulib module arpa_inet-h
153 158
154## begin gnulib module assert-h 159## begin gnulib module assert-h
155 160
@@ -221,6 +226,7 @@ if GL_GENERATE_BYTESWAP_H
221byteswap.h: byteswap.in.h $(top_builddir)/config.status 226byteswap.h: byteswap.in.h $(top_builddir)/config.status
222 $(gl_V_at)$(SED_HEADER_TO_AT_t) $(srcdir)/byteswap.in.h 227 $(gl_V_at)$(SED_HEADER_TO_AT_t) $(srcdir)/byteswap.in.h
223 $(AM_V_at)mv $@-t $@ 228 $(AM_V_at)mv $@-t $@
229libgnu_a_SOURCES += byteswap.c
224else 230else
225byteswap.h: $(top_builddir)/config.status 231byteswap.h: $(top_builddir)/config.status
226 rm -f $@ 232 rm -f $@
@@ -231,6 +237,122 @@ EXTRA_DIST += byteswap.in.h
231 237
232## end gnulib module byteswap 238## end gnulib module byteswap
233 239
240## begin gnulib module c-ctype
241
242libgnu_a_SOURCES += c-ctype.h c-ctype.c
243
244## end gnulib module c-ctype
245
246## begin gnulib module c32isalnum
247
248libgnu_a_SOURCES += c32isalnum.c
249
250EXTRA_DIST += c32is-impl.h
251
252## end gnulib module c32isalnum
253
254## begin gnulib module c32isalpha
255
256libgnu_a_SOURCES += c32isalpha.c
257
258EXTRA_DIST += c32is-impl.h
259
260## end gnulib module c32isalpha
261
262## begin gnulib module c32isblank
263
264libgnu_a_SOURCES += c32isblank.c
265
266EXTRA_DIST += c32is-impl.h
267
268## end gnulib module c32isblank
269
270## begin gnulib module c32iscntrl
271
272libgnu_a_SOURCES += c32iscntrl.c
273
274EXTRA_DIST += c32is-impl.h
275
276## end gnulib module c32iscntrl
277
278## begin gnulib module c32isdigit
279
280libgnu_a_SOURCES += c32isdigit.c
281
282EXTRA_DIST += c32is-impl.h
283
284## end gnulib module c32isdigit
285
286## begin gnulib module c32isgraph
287
288libgnu_a_SOURCES += c32isgraph.c
289
290EXTRA_DIST += c32is-impl.h
291
292## end gnulib module c32isgraph
293
294## begin gnulib module c32islower
295
296libgnu_a_SOURCES += c32islower.c
297
298EXTRA_DIST += c32is-impl.h
299
300## end gnulib module c32islower
301
302## begin gnulib module c32isprint
303
304libgnu_a_SOURCES += c32isprint.c
305
306EXTRA_DIST += c32is-impl.h
307
308## end gnulib module c32isprint
309
310## begin gnulib module c32ispunct
311
312libgnu_a_SOURCES += c32ispunct.c
313
314EXTRA_DIST += c32is-impl.h
315
316## end gnulib module c32ispunct
317
318## begin gnulib module c32isspace
319
320libgnu_a_SOURCES += c32isspace.c
321
322EXTRA_DIST += c32is-impl.h
323
324## end gnulib module c32isspace
325
326## begin gnulib module c32isupper
327
328libgnu_a_SOURCES += c32isupper.c
329
330EXTRA_DIST += c32is-impl.h
331
332## end gnulib module c32isupper
333
334## begin gnulib module c32isxdigit
335
336libgnu_a_SOURCES += c32isxdigit.c
337
338EXTRA_DIST += c32is-impl.h
339
340## end gnulib module c32isxdigit
341
342## begin gnulib module c32tolower
343
344libgnu_a_SOURCES += c32tolower.c
345
346EXTRA_DIST += c32to-impl.h
347
348## end gnulib module c32tolower
349
350## begin gnulib module c32width
351
352libgnu_a_SOURCES += c32width.c
353
354## end gnulib module c32width
355
234## begin gnulib module calloc-gnu 356## begin gnulib module calloc-gnu
235 357
236 358
@@ -313,7 +435,7 @@ endif
313 435
314## end gnulib module dup2 436## end gnulib module dup2
315 437
316## begin gnulib module errno 438## begin gnulib module errno-h
317 439
318BUILT_SOURCES += $(ERRNO_H) 440BUILT_SOURCES += $(ERRNO_H)
319 441
@@ -343,7 +465,7 @@ MOSTLYCLEANFILES += errno.h errno.h-t
343 465
344EXTRA_DIST += errno.in.h 466EXTRA_DIST += errno.in.h
345 467
346## end gnulib module errno 468## end gnulib module errno-h
347 469
348## begin gnulib module error 470## begin gnulib module error
349 471
@@ -455,7 +577,7 @@ EXTRA_DIST += filename.h
455 577
456## end gnulib module filename 578## end gnulib module filename
457 579
458## begin gnulib module float 580## begin gnulib module float-h
459 581
460BUILT_SOURCES += $(FLOAT_H) 582BUILT_SOURCES += $(FLOAT_H)
461 583
@@ -487,7 +609,7 @@ endif
487 609
488EXTRA_DIST += float.in.h 610EXTRA_DIST += float.in.h
489 611
490## end gnulib module float 612## end gnulib module float-h
491 613
492## begin gnulib module floorf 614## begin gnulib module floorf
493 615
@@ -563,6 +685,16 @@ EXTRA_DIST += stdio-impl.h
563 685
564## end gnulib module fseeko 686## end gnulib module fseeko
565 687
688## begin gnulib module fseterr
689
690if GL_COND_OBJ_FSETERR
691libgnu_a_SOURCES += fseterr.c
692endif
693
694EXTRA_DIST += fseterr.h stdio-impl.h
695
696## end gnulib module fseterr
697
566## begin gnulib module fstat 698## begin gnulib module fstat
567 699
568if GL_COND_OBJ_FSTAT 700if GL_COND_OBJ_FSTAT
@@ -807,6 +939,14 @@ endif
807 939
808## end gnulib module inet_ntop 940## end gnulib module inet_ntop
809 941
942## begin gnulib module inet_pton
943
944if GL_COND_OBJ_INET_PTON
945libgnu_a_SOURCES += inet_pton.c
946endif
947
948## end gnulib module inet_pton
949
810## begin gnulib module intprops 950## begin gnulib module intprops
811 951
812 952
@@ -814,7 +954,7 @@ EXTRA_DIST += intprops-internal.h intprops.h
814 954
815## end gnulib module intprops 955## end gnulib module intprops
816 956
817## begin gnulib module inttypes-incomplete 957## begin gnulib module inttypes-h-incomplete
818 958
819BUILT_SOURCES += inttypes.h 959BUILT_SOURCES += inttypes.h
820 960
@@ -855,7 +995,7 @@ MOSTLYCLEANFILES += inttypes.h inttypes.h-t
855 995
856EXTRA_DIST += inttypes.in.h 996EXTRA_DIST += inttypes.in.h
857 997
858## end gnulib module inttypes-incomplete 998## end gnulib module inttypes-h-incomplete
859 999
860## begin gnulib module iswblank 1000## begin gnulib module iswblank
861 1001
@@ -899,7 +1039,7 @@ endif
899 1039
900## end gnulib module iswxdigit 1040## end gnulib module iswxdigit
901 1041
902## begin gnulib module langinfo 1042## begin gnulib module langinfo-h
903 1043
904BUILT_SOURCES += langinfo.h 1044BUILT_SOURCES += langinfo.h
905 1045
@@ -917,6 +1057,7 @@ langinfo.h: langinfo.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(WARN_ON_U
917 -e 's|@''HAVE_LANGINFO_CODESET''@|$(HAVE_LANGINFO_CODESET)|g' \ 1057 -e 's|@''HAVE_LANGINFO_CODESET''@|$(HAVE_LANGINFO_CODESET)|g' \
918 -e 's|@''HAVE_LANGINFO_T_FMT_AMPM''@|$(HAVE_LANGINFO_T_FMT_AMPM)|g' \ 1058 -e 's|@''HAVE_LANGINFO_T_FMT_AMPM''@|$(HAVE_LANGINFO_T_FMT_AMPM)|g' \
919 -e 's|@''HAVE_LANGINFO_ALTMON''@|$(HAVE_LANGINFO_ALTMON)|g' \ 1059 -e 's|@''HAVE_LANGINFO_ALTMON''@|$(HAVE_LANGINFO_ALTMON)|g' \
1060 -e 's|@''HAVE_LANGINFO_ABALTMON''@|$(HAVE_LANGINFO_ABALTMON)|g' \
920 -e 's|@''HAVE_LANGINFO_ERA''@|$(HAVE_LANGINFO_ERA)|g' \ 1061 -e 's|@''HAVE_LANGINFO_ERA''@|$(HAVE_LANGINFO_ERA)|g' \
921 -e 's|@''HAVE_LANGINFO_YESEXPR''@|$(HAVE_LANGINFO_YESEXPR)|g' \ 1062 -e 's|@''HAVE_LANGINFO_YESEXPR''@|$(HAVE_LANGINFO_YESEXPR)|g' \
922 -e 's|@''HAVE_NL_LANGINFO''@|$(HAVE_NL_LANGINFO)|g' \ 1063 -e 's|@''HAVE_NL_LANGINFO''@|$(HAVE_NL_LANGINFO)|g' \
@@ -929,7 +1070,7 @@ MOSTLYCLEANFILES += langinfo.h langinfo.h-t
929 1070
930EXTRA_DIST += langinfo.in.h 1071EXTRA_DIST += langinfo.in.h
931 1072
932## end gnulib module langinfo 1073## end gnulib module langinfo-h
933 1074
934## begin gnulib module libc-config 1075## begin gnulib module libc-config
935 1076
@@ -972,7 +1113,7 @@ EXTRA_DIST += localcharset.h
972 1113
973## end gnulib module localcharset 1114## end gnulib module localcharset
974 1115
975## begin gnulib module locale 1116## begin gnulib module locale-h
976 1117
977BUILT_SOURCES += locale.h 1118BUILT_SOURCES += locale.h
978 1119
@@ -985,20 +1126,28 @@ locale.h: locale.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
985 -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \ 1126 -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
986 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ 1127 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
987 -e 's|@''NEXT_LOCALE_H''@|$(NEXT_LOCALE_H)|g' \ 1128 -e 's|@''NEXT_LOCALE_H''@|$(NEXT_LOCALE_H)|g' \
1129 -e 's|@''HAVE_LOCALE_T''@|$(HAVE_LOCALE_T)|g' \
1130 -e 's|@''HAVE_WINDOWS_LOCALE_T''@|$(HAVE_WINDOWS_LOCALE_T)|g' \
988 -e 's/@''GNULIB_LOCALECONV''@/$(GL_GNULIB_LOCALECONV)/g' \ 1131 -e 's/@''GNULIB_LOCALECONV''@/$(GL_GNULIB_LOCALECONV)/g' \
989 -e 's/@''GNULIB_SETLOCALE''@/$(GL_GNULIB_SETLOCALE)/g' \ 1132 -e 's/@''GNULIB_SETLOCALE''@/$(GL_GNULIB_SETLOCALE)/g' \
990 -e 's/@''GNULIB_SETLOCALE_NULL''@/$(GL_GNULIB_SETLOCALE_NULL)/g' \ 1133 -e 's/@''GNULIB_SETLOCALE_NULL''@/$(GL_GNULIB_SETLOCALE_NULL)/g' \
1134 -e 's/@''GNULIB_NEWLOCALE''@/$(GL_GNULIB_NEWLOCALE)/g' \
991 -e 's/@''GNULIB_DUPLOCALE''@/$(GL_GNULIB_DUPLOCALE)/g' \ 1135 -e 's/@''GNULIB_DUPLOCALE''@/$(GL_GNULIB_DUPLOCALE)/g' \
1136 -e 's/@''GNULIB_FREELOCALE''@/$(GL_GNULIB_FREELOCALE)/g' \
1137 -e 's/@''GNULIB_GETLOCALENAME_L''@/$(GL_GNULIB_GETLOCALENAME_L)/g' \
1138 -e 's/@''GNULIB_GETLOCALENAME_L_UNSAFE''@/$(GL_GNULIB_GETLOCALENAME_L_UNSAFE)/g' \
992 -e 's/@''GNULIB_LOCALENAME_UNSAFE''@/$(GL_GNULIB_LOCALENAME_UNSAFE)/g' \ 1139 -e 's/@''GNULIB_LOCALENAME_UNSAFE''@/$(GL_GNULIB_LOCALENAME_UNSAFE)/g' \
993 -e 's|@''HAVE_NEWLOCALE''@|$(HAVE_NEWLOCALE)|g' \ 1140 -e 's|@''HAVE_NEWLOCALE''@|$(HAVE_NEWLOCALE)|g' \
994 -e 's|@''HAVE_DUPLOCALE''@|$(HAVE_DUPLOCALE)|g' \ 1141 -e 's|@''HAVE_DUPLOCALE''@|$(HAVE_DUPLOCALE)|g' \
995 -e 's|@''HAVE_FREELOCALE''@|$(HAVE_FREELOCALE)|g' \ 1142 -e 's|@''HAVE_FREELOCALE''@|$(HAVE_FREELOCALE)|g' \
1143 -e 's|@''HAVE_GETLOCALENAME_L''@|$(HAVE_GETLOCALENAME_L)|g' \
996 -e 's|@''HAVE_XLOCALE_H''@|$(HAVE_XLOCALE_H)|g' \ 1144 -e 's|@''HAVE_XLOCALE_H''@|$(HAVE_XLOCALE_H)|g' \
997 -e 's|@''REPLACE_LOCALECONV''@|$(REPLACE_LOCALECONV)|g' \ 1145 -e 's|@''REPLACE_LOCALECONV''@|$(REPLACE_LOCALECONV)|g' \
998 -e 's|@''REPLACE_SETLOCALE''@|$(REPLACE_SETLOCALE)|g' \ 1146 -e 's|@''REPLACE_SETLOCALE''@|$(REPLACE_SETLOCALE)|g' \
999 -e 's|@''REPLACE_NEWLOCALE''@|$(REPLACE_NEWLOCALE)|g' \ 1147 -e 's|@''REPLACE_NEWLOCALE''@|$(REPLACE_NEWLOCALE)|g' \
1000 -e 's|@''REPLACE_DUPLOCALE''@|$(REPLACE_DUPLOCALE)|g' \ 1148 -e 's|@''REPLACE_DUPLOCALE''@|$(REPLACE_DUPLOCALE)|g' \
1001 -e 's|@''REPLACE_FREELOCALE''@|$(REPLACE_FREELOCALE)|g' \ 1149 -e 's|@''REPLACE_FREELOCALE''@|$(REPLACE_FREELOCALE)|g' \
1150 -e 's|@''REPLACE_GETLOCALENAME_L''@|$(REPLACE_GETLOCALENAME_L)|g' \
1002 -e 's|@''REPLACE_STRUCT_LCONV''@|$(REPLACE_STRUCT_LCONV)|g' \ 1151 -e 's|@''REPLACE_STRUCT_LCONV''@|$(REPLACE_STRUCT_LCONV)|g' \
1003 -e 's|@''LOCALENAME_ENHANCE_LOCALE_FUNCS''@|$(LOCALENAME_ENHANCE_LOCALE_FUNCS)|g' \ 1152 -e 's|@''LOCALENAME_ENHANCE_LOCALE_FUNCS''@|$(LOCALENAME_ENHANCE_LOCALE_FUNCS)|g' \
1004 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ 1153 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
@@ -1010,7 +1159,7 @@ MOSTLYCLEANFILES += locale.h locale.h-t
1010 1159
1011EXTRA_DIST += locale.in.h 1160EXTRA_DIST += locale.in.h
1012 1161
1013## end gnulib module locale 1162## end gnulib module locale-h
1014 1163
1015## begin gnulib module localeconv 1164## begin gnulib module localeconv
1016 1165
@@ -1034,6 +1183,14 @@ endif
1034 1183
1035## end gnulib module lseek 1184## end gnulib module lseek
1036 1185
1186## begin gnulib module lstat
1187
1188if GL_COND_OBJ_LSTAT
1189libgnu_a_SOURCES += lstat.c
1190endif
1191
1192## end gnulib module lstat
1193
1037## begin gnulib module malloc-gnu 1194## begin gnulib module malloc-gnu
1038 1195
1039 1196
@@ -1060,7 +1217,7 @@ EXTRA_DIST += malloca.h
1060 1217
1061## end gnulib module malloca 1218## end gnulib module malloca
1062 1219
1063## begin gnulib module math 1220## begin gnulib module math-h
1064 1221
1065BUILT_SOURCES += math.h 1222BUILT_SOURCES += math.h
1066libgnu_a_SOURCES += math.c 1223libgnu_a_SOURCES += math.c
@@ -1150,6 +1307,9 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
1150 -e 's/@''GNULIB_LOGB''@/$(GL_GNULIB_LOGB)/g' \ 1307 -e 's/@''GNULIB_LOGB''@/$(GL_GNULIB_LOGB)/g' \
1151 -e 's/@''GNULIB_LOGBF''@/$(GL_GNULIB_LOGBF)/g' \ 1308 -e 's/@''GNULIB_LOGBF''@/$(GL_GNULIB_LOGBF)/g' \
1152 -e 's/@''GNULIB_LOGBL''@/$(GL_GNULIB_LOGBL)/g' \ 1309 -e 's/@''GNULIB_LOGBL''@/$(GL_GNULIB_LOGBL)/g' \
1310 -e 's/@''GNULIB_LOGP1''@/$(GL_GNULIB_LOGP1)/g' \
1311 -e 's/@''GNULIB_LOGP1F''@/$(GL_GNULIB_LOGP1F)/g' \
1312 -e 's/@''GNULIB_LOGP1L''@/$(GL_GNULIB_LOGP1L)/g' \
1153 -e 's/@''GNULIB_MODF''@/$(GL_GNULIB_MODF)/g' \ 1313 -e 's/@''GNULIB_MODF''@/$(GL_GNULIB_MODF)/g' \
1154 -e 's/@''GNULIB_MODFF''@/$(GL_GNULIB_MODFF)/g' \ 1314 -e 's/@''GNULIB_MODFF''@/$(GL_GNULIB_MODFF)/g' \
1155 -e 's/@''GNULIB_MODFL''@/$(GL_GNULIB_MODFL)/g' \ 1315 -e 's/@''GNULIB_MODFL''@/$(GL_GNULIB_MODFL)/g' \
@@ -1243,6 +1403,9 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
1243 -e 's|@''HAVE_LOG1PL''@|$(HAVE_LOG1PL)|g' \ 1403 -e 's|@''HAVE_LOG1PL''@|$(HAVE_LOG1PL)|g' \
1244 -e 's|@''HAVE_LOGBF''@|$(HAVE_LOGBF)|g' \ 1404 -e 's|@''HAVE_LOGBF''@|$(HAVE_LOGBF)|g' \
1245 -e 's|@''HAVE_LOGBL''@|$(HAVE_LOGBL)|g' \ 1405 -e 's|@''HAVE_LOGBL''@|$(HAVE_LOGBL)|g' \
1406 -e 's|@''HAVE_LOGP1''@|$(HAVE_LOGP1)|g' \
1407 -e 's|@''HAVE_LOGP1F''@|$(HAVE_LOGP1F)|g' \
1408 -e 's|@''HAVE_LOGP1L''@|$(HAVE_LOGP1L)|g' \
1246 -e 's|@''HAVE_MODFF''@|$(HAVE_MODFF)|g' \ 1409 -e 's|@''HAVE_MODFF''@|$(HAVE_MODFF)|g' \
1247 -e 's|@''HAVE_MODFL''@|$(HAVE_MODFL)|g' \ 1410 -e 's|@''HAVE_MODFL''@|$(HAVE_MODFL)|g' \
1248 -e 's|@''HAVE_POWF''@|$(HAVE_POWF)|g' \ 1411 -e 's|@''HAVE_POWF''@|$(HAVE_POWF)|g' \
@@ -1389,6 +1552,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
1389 -e 's|@''REPLACE_SIGNBIT_USING_BUILTINS''@|$(REPLACE_SIGNBIT_USING_BUILTINS)|g' \ 1552 -e 's|@''REPLACE_SIGNBIT_USING_BUILTINS''@|$(REPLACE_SIGNBIT_USING_BUILTINS)|g' \
1390 -e 's|@''REPLACE_SINF''@|$(REPLACE_SINF)|g' \ 1553 -e 's|@''REPLACE_SINF''@|$(REPLACE_SINF)|g' \
1391 -e 's|@''REPLACE_SINHF''@|$(REPLACE_SINHF)|g' \ 1554 -e 's|@''REPLACE_SINHF''@|$(REPLACE_SINHF)|g' \
1555 -e 's|@''REPLACE_SINL''@|$(REPLACE_SINL)|g' \
1392 -e 's|@''REPLACE_SQRTF''@|$(REPLACE_SQRTF)|g' \ 1556 -e 's|@''REPLACE_SQRTF''@|$(REPLACE_SQRTF)|g' \
1393 -e 's|@''REPLACE_SQRTL''@|$(REPLACE_SQRTL)|g' \ 1557 -e 's|@''REPLACE_SQRTL''@|$(REPLACE_SQRTL)|g' \
1394 -e 's|@''REPLACE_TANF''@|$(REPLACE_TANF)|g' \ 1558 -e 's|@''REPLACE_TANF''@|$(REPLACE_TANF)|g' \
@@ -1412,7 +1576,33 @@ MOSTLYCLEANFILES += math.h math.h-t1 math.h-t2 math.h-t3 math.h-t4 math.h-t5 mat
1412 1576
1413EXTRA_DIST += math.in.h 1577EXTRA_DIST += math.in.h
1414 1578
1415## end gnulib module math 1579## end gnulib module math-h
1580
1581## begin gnulib module mbchar
1582
1583libgnu_a_SOURCES += mbchar.c
1584
1585EXTRA_DIST += mbchar.h
1586
1587## end gnulib module mbchar
1588
1589## begin gnulib module mbiterf
1590
1591libgnu_a_SOURCES += mbiterf.h mbiterf.c
1592
1593## end gnulib module mbiterf
1594
1595## begin gnulib module mbrtoc32
1596
1597if GL_COND_OBJ_MBRTOC32
1598libgnu_a_SOURCES += mbrtoc32.c
1599endif
1600
1601EXTRA_DIST += lc-charset-dispatch.c lc-charset-dispatch.h mbrtowc-impl-utf8.h mbrtowc-impl.h mbtowc-lock.c mbtowc-lock.h windows-initguard.h
1602
1603EXTRA_libgnu_a_SOURCES += lc-charset-dispatch.c mbtowc-lock.c
1604
1605## end gnulib module mbrtoc32
1416 1606
1417## begin gnulib module mbrtowc 1607## begin gnulib module mbrtowc
1418 1608
@@ -1434,6 +1624,12 @@ endif
1434 1624
1435## end gnulib module mbsinit 1625## end gnulib module mbsinit
1436 1626
1627## begin gnulib module mbsnlen
1628
1629libgnu_a_SOURCES += mbsnlen.c
1630
1631## end gnulib module mbsnlen
1632
1437## begin gnulib module mbszero 1633## begin gnulib module mbszero
1438 1634
1439libgnu_a_SOURCES += mbszero.c 1635libgnu_a_SOURCES += mbszero.c
@@ -1486,9 +1682,7 @@ EXTRA_libgnu_a_SOURCES += mktime.c
1486 1682
1487## begin gnulib module mountlist 1683## begin gnulib module mountlist
1488 1684
1489if GL_COND_OBJ_MOUNTLIST
1490libgnu_a_SOURCES += mountlist.c 1685libgnu_a_SOURCES += mountlist.c
1491endif
1492 1686
1493EXTRA_DIST += mountlist.h 1687EXTRA_DIST += mountlist.h
1494 1688
@@ -1514,7 +1708,7 @@ EXTRA_DIST += msvc-nothrow.h
1514 1708
1515## end gnulib module msvc-nothrow 1709## end gnulib module msvc-nothrow
1516 1710
1517## begin gnulib module netdb 1711## begin gnulib module netdb-h
1518 1712
1519BUILT_SOURCES += netdb.h 1713BUILT_SOURCES += netdb.h
1520 1714
@@ -1545,9 +1739,9 @@ MOSTLYCLEANFILES += netdb.h netdb.h-t
1545 1739
1546EXTRA_DIST += netdb.in.h 1740EXTRA_DIST += netdb.in.h
1547 1741
1548## end gnulib module netdb 1742## end gnulib module netdb-h
1549 1743
1550## begin gnulib module netinet_in 1744## begin gnulib module netinet_in-h
1551 1745
1552BUILT_SOURCES += $(NETINET_IN_H) 1746BUILT_SOURCES += $(NETINET_IN_H)
1553 1747
@@ -1574,7 +1768,7 @@ MOSTLYCLEANDIRS += netinet
1574 1768
1575EXTRA_DIST += netinet_in.in.h 1769EXTRA_DIST += netinet_in.in.h
1576 1770
1577## end gnulib module netinet_in 1771## end gnulib module netinet_in-h
1578 1772
1579## begin gnulib module nl_langinfo 1773## begin gnulib module nl_langinfo
1580 1774
@@ -1589,6 +1783,12 @@ EXTRA_DIST += windows-initguard.h
1589 1783
1590## end gnulib module nl_langinfo 1784## end gnulib module nl_langinfo
1591 1785
1786## begin gnulib module once
1787
1788libgnu_a_SOURCES += glthread/once.h glthread/once.c
1789
1790## end gnulib module once
1791
1592## begin gnulib module open 1792## begin gnulib module open
1593 1793
1594if GL_COND_OBJ_OPEN 1794if GL_COND_OBJ_OPEN
@@ -1604,21 +1804,168 @@ EXTRA_DIST += pathmax.h
1604 1804
1605## end gnulib module pathmax 1805## end gnulib module pathmax
1606 1806
1607## begin gnulib module realloc-gnu 1807## begin gnulib module pthread-h
1608 1808
1809BUILT_SOURCES += pthread.h
1810
1811# We need the following in order to create <pthread.h> when the system
1812# doesn't have one that works with the given compiler.
1813pthread.h: pthread.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(_NORETURN_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)
1814 $(gl_V_at)$(SED_HEADER_STDOUT) \
1815 -e 's|@''GUARD_PREFIX''@|GL|g' \
1816 -e 's|@''HAVE_PTHREAD_H''@|$(HAVE_PTHREAD_H)|g' \
1817 -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
1818 -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
1819 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
1820 -e 's|@''NEXT_PTHREAD_H''@|$(NEXT_PTHREAD_H)|g' \
1821 -e 's/@''GNULIB_PTHREAD_THREAD''@/$(GL_GNULIB_PTHREAD_THREAD)/g' \
1822 -e 's/@''GNULIB_PTHREAD_ONCE''@/$(GL_GNULIB_PTHREAD_ONCE)/g' \
1823 -e 's/@''GNULIB_PTHREAD_MUTEX''@/$(GL_GNULIB_PTHREAD_MUTEX)/g' \
1824 -e 's/@''GNULIB_PTHREAD_RWLOCK''@/$(GL_GNULIB_PTHREAD_RWLOCK)/g' \
1825 -e 's/@''GNULIB_PTHREAD_COND''@/$(GL_GNULIB_PTHREAD_COND)/g' \
1826 -e 's/@''GNULIB_PTHREAD_TSS''@/$(GL_GNULIB_PTHREAD_TSS)/g' \
1827 -e 's/@''GNULIB_PTHREAD_SPIN''@/$(GL_GNULIB_PTHREAD_SPIN)/g' \
1828 -e 's/@''GNULIB_PTHREAD_MUTEX_TIMEDLOCK''@/$(GL_GNULIB_PTHREAD_MUTEX_TIMEDLOCK)/g' \
1829 -e 's|@''HAVE_PTHREAD_T''@|$(HAVE_PTHREAD_T)|g' \
1830 -e 's|@''HAVE_PTHREAD_SPINLOCK_T''@|$(HAVE_PTHREAD_SPINLOCK_T)|g' \
1831 -e 's|@''HAVE_PTHREAD_CREATE_DETACHED''@|$(HAVE_PTHREAD_CREATE_DETACHED)|g' \
1832 -e 's|@''HAVE_PTHREAD_MUTEX_RECURSIVE''@|$(HAVE_PTHREAD_MUTEX_RECURSIVE)|g' \
1833 -e 's|@''HAVE_PTHREAD_MUTEX_ROBUST''@|$(HAVE_PTHREAD_MUTEX_ROBUST)|g' \
1834 -e 's|@''HAVE_PTHREAD_PROCESS_SHARED''@|$(HAVE_PTHREAD_PROCESS_SHARED)|g' \
1835 -e 's|@''HAVE_PTHREAD_CREATE''@|$(HAVE_PTHREAD_CREATE)|g' \
1836 -e 's|@''HAVE_PTHREAD_ATTR_INIT''@|$(HAVE_PTHREAD_ATTR_INIT)|g' \
1837 -e 's|@''HAVE_PTHREAD_ATTR_GETDETACHSTATE''@|$(HAVE_PTHREAD_ATTR_GETDETACHSTATE)|g' \
1838 -e 's|@''HAVE_PTHREAD_ATTR_SETDETACHSTATE''@|$(HAVE_PTHREAD_ATTR_SETDETACHSTATE)|g' \
1839 -e 's|@''HAVE_PTHREAD_ATTR_DESTROY''@|$(HAVE_PTHREAD_ATTR_DESTROY)|g' \
1840 -e 's|@''HAVE_PTHREAD_SELF''@|$(HAVE_PTHREAD_SELF)|g' \
1841 -e 's|@''HAVE_PTHREAD_EQUAL''@|$(HAVE_PTHREAD_EQUAL)|g' \
1842 -e 's|@''HAVE_PTHREAD_DETACH''@|$(HAVE_PTHREAD_DETACH)|g' \
1843 -e 's|@''HAVE_PTHREAD_JOIN''@|$(HAVE_PTHREAD_JOIN)|g' \
1844 -e 's|@''HAVE_PTHREAD_EXIT''@|$(HAVE_PTHREAD_EXIT)|g' \
1845 < $(srcdir)/pthread.in.h > $@-t1
1846 $(AM_V_at)sed \
1847 -e 's|@''HAVE_PTHREAD_ONCE''@|$(HAVE_PTHREAD_ONCE)|g' \
1848 -e 's|@''HAVE_PTHREAD_MUTEX_INIT''@|$(HAVE_PTHREAD_MUTEX_INIT)|g' \
1849 -e 's|@''HAVE_PTHREAD_MUTEXATTR_INIT''@|$(HAVE_PTHREAD_MUTEXATTR_INIT)|g' \
1850 -e 's|@''HAVE_PTHREAD_MUTEXATTR_GETTYPE''@|$(HAVE_PTHREAD_MUTEXATTR_GETTYPE)|g' \
1851 -e 's|@''HAVE_PTHREAD_MUTEXATTR_SETTYPE''@|$(HAVE_PTHREAD_MUTEXATTR_SETTYPE)|g' \
1852 -e 's|@''HAVE_PTHREAD_MUTEXATTR_GETROBUST''@|$(HAVE_PTHREAD_MUTEXATTR_GETROBUST)|g' \
1853 -e 's|@''HAVE_PTHREAD_MUTEXATTR_SETROBUST''@|$(HAVE_PTHREAD_MUTEXATTR_SETROBUST)|g' \
1854 -e 's|@''HAVE_PTHREAD_MUTEXATTR_DESTROY''@|$(HAVE_PTHREAD_MUTEXATTR_DESTROY)|g' \
1855 -e 's|@''HAVE_PTHREAD_MUTEX_LOCK''@|$(HAVE_PTHREAD_MUTEX_LOCK)|g' \
1856 -e 's|@''HAVE_PTHREAD_MUTEX_TRYLOCK''@|$(HAVE_PTHREAD_MUTEX_TRYLOCK)|g' \
1857 -e 's|@''HAVE_PTHREAD_MUTEX_TIMEDLOCK''@|$(HAVE_PTHREAD_MUTEX_TIMEDLOCK)|g' \
1858 -e 's|@''HAVE_PTHREAD_MUTEX_UNLOCK''@|$(HAVE_PTHREAD_MUTEX_UNLOCK)|g' \
1859 -e 's|@''HAVE_PTHREAD_MUTEX_DESTROY''@|$(HAVE_PTHREAD_MUTEX_DESTROY)|g' \
1860 -e 's|@''HAVE_PTHREAD_RWLOCK_INIT''@|$(HAVE_PTHREAD_RWLOCK_INIT)|g' \
1861 -e 's|@''HAVE_PTHREAD_RWLOCKATTR_INIT''@|$(HAVE_PTHREAD_RWLOCKATTR_INIT)|g' \
1862 -e 's|@''HAVE_PTHREAD_RWLOCKATTR_DESTROY''@|$(HAVE_PTHREAD_RWLOCKATTR_DESTROY)|g' \
1863 -e 's|@''HAVE_PTHREAD_RWLOCK_RDLOCK''@|$(HAVE_PTHREAD_RWLOCK_RDLOCK)|g' \
1864 -e 's|@''HAVE_PTHREAD_RWLOCK_WRLOCK''@|$(HAVE_PTHREAD_RWLOCK_WRLOCK)|g' \
1865 -e 's|@''HAVE_PTHREAD_RWLOCK_TRYRDLOCK''@|$(HAVE_PTHREAD_RWLOCK_TRYRDLOCK)|g' \
1866 -e 's|@''HAVE_PTHREAD_RWLOCK_TRYWRLOCK''@|$(HAVE_PTHREAD_RWLOCK_TRYWRLOCK)|g' \
1867 -e 's|@''HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK''@|$(HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK)|g' \
1868 -e 's|@''HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK''@|$(HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK)|g' \
1869 -e 's|@''HAVE_PTHREAD_RWLOCK_UNLOCK''@|$(HAVE_PTHREAD_RWLOCK_UNLOCK)|g' \
1870 -e 's|@''HAVE_PTHREAD_RWLOCK_DESTROY''@|$(HAVE_PTHREAD_RWLOCK_DESTROY)|g' \
1871 -e 's|@''HAVE_PTHREAD_COND_INIT''@|$(HAVE_PTHREAD_COND_INIT)|g' \
1872 -e 's|@''HAVE_PTHREAD_CONDATTR_INIT''@|$(HAVE_PTHREAD_CONDATTR_INIT)|g' \
1873 -e 's|@''HAVE_PTHREAD_CONDATTR_DESTROY''@|$(HAVE_PTHREAD_CONDATTR_DESTROY)|g' \
1874 -e 's|@''HAVE_PTHREAD_COND_WAIT''@|$(HAVE_PTHREAD_COND_WAIT)|g' \
1875 -e 's|@''HAVE_PTHREAD_COND_TIMEDWAIT''@|$(HAVE_PTHREAD_COND_TIMEDWAIT)|g' \
1876 -e 's|@''HAVE_PTHREAD_COND_SIGNAL''@|$(HAVE_PTHREAD_COND_SIGNAL)|g' \
1877 -e 's|@''HAVE_PTHREAD_COND_BROADCAST''@|$(HAVE_PTHREAD_COND_BROADCAST)|g' \
1878 -e 's|@''HAVE_PTHREAD_COND_DESTROY''@|$(HAVE_PTHREAD_COND_DESTROY)|g' \
1879 -e 's|@''HAVE_PTHREAD_KEY_CREATE''@|$(HAVE_PTHREAD_KEY_CREATE)|g' \
1880 -e 's|@''HAVE_PTHREAD_SETSPECIFIC''@|$(HAVE_PTHREAD_SETSPECIFIC)|g' \
1881 -e 's|@''HAVE_PTHREAD_GETSPECIFIC''@|$(HAVE_PTHREAD_GETSPECIFIC)|g' \
1882 -e 's|@''HAVE_PTHREAD_KEY_DELETE''@|$(HAVE_PTHREAD_KEY_DELETE)|g' \
1883 -e 's|@''HAVE_PTHREAD_SPIN_INIT''@|$(HAVE_PTHREAD_SPIN_INIT)|g' \
1884 -e 's|@''HAVE_PTHREAD_SPIN_LOCK''@|$(HAVE_PTHREAD_SPIN_LOCK)|g' \
1885 -e 's|@''HAVE_PTHREAD_SPIN_TRYLOCK''@|$(HAVE_PTHREAD_SPIN_TRYLOCK)|g' \
1886 -e 's|@''HAVE_PTHREAD_SPIN_UNLOCK''@|$(HAVE_PTHREAD_SPIN_UNLOCK)|g' \
1887 -e 's|@''HAVE_PTHREAD_SPIN_DESTROY''@|$(HAVE_PTHREAD_SPIN_DESTROY)|g' \
1888 < $@-t1 > $@-t2
1889 $(AM_V_at)sed \
1890 -e 's|@''REPLACE_PTHREAD_CREATE''@|$(REPLACE_PTHREAD_CREATE)|g' \
1891 -e 's|@''REPLACE_PTHREAD_ATTR_INIT''@|$(REPLACE_PTHREAD_ATTR_INIT)|g' \
1892 -e 's|@''REPLACE_PTHREAD_ATTR_GETDETACHSTATE''@|$(REPLACE_PTHREAD_ATTR_GETDETACHSTATE)|g' \
1893 -e 's|@''REPLACE_PTHREAD_ATTR_SETDETACHSTATE''@|$(REPLACE_PTHREAD_ATTR_SETDETACHSTATE)|g' \
1894 -e 's|@''REPLACE_PTHREAD_ATTR_DESTROY''@|$(REPLACE_PTHREAD_ATTR_DESTROY)|g' \
1895 -e 's|@''REPLACE_PTHREAD_SELF''@|$(REPLACE_PTHREAD_SELF)|g' \
1896 -e 's|@''REPLACE_PTHREAD_EQUAL''@|$(REPLACE_PTHREAD_EQUAL)|g' \
1897 -e 's|@''REPLACE_PTHREAD_DETACH''@|$(REPLACE_PTHREAD_DETACH)|g' \
1898 -e 's|@''REPLACE_PTHREAD_JOIN''@|$(REPLACE_PTHREAD_JOIN)|g' \
1899 -e 's|@''REPLACE_PTHREAD_EXIT''@|$(REPLACE_PTHREAD_EXIT)|g' \
1900 -e 's|@''REPLACE_PTHREAD_ONCE''@|$(REPLACE_PTHREAD_ONCE)|g' \
1901 -e 's|@''REPLACE_PTHREAD_MUTEX_INIT''@|$(REPLACE_PTHREAD_MUTEX_INIT)|g' \
1902 -e 's|@''REPLACE_PTHREAD_MUTEXATTR_INIT''@|$(REPLACE_PTHREAD_MUTEXATTR_INIT)|g' \
1903 -e 's|@''REPLACE_PTHREAD_MUTEXATTR_GETTYPE''@|$(REPLACE_PTHREAD_MUTEXATTR_GETTYPE)|g' \
1904 -e 's|@''REPLACE_PTHREAD_MUTEXATTR_SETTYPE''@|$(REPLACE_PTHREAD_MUTEXATTR_SETTYPE)|g' \
1905 -e 's|@''REPLACE_PTHREAD_MUTEXATTR_GETROBUST''@|$(REPLACE_PTHREAD_MUTEXATTR_GETROBUST)|g' \
1906 -e 's|@''REPLACE_PTHREAD_MUTEXATTR_SETROBUST''@|$(REPLACE_PTHREAD_MUTEXATTR_SETROBUST)|g' \
1907 -e 's|@''REPLACE_PTHREAD_MUTEXATTR_DESTROY''@|$(REPLACE_PTHREAD_MUTEXATTR_DESTROY)|g' \
1908 -e 's|@''REPLACE_PTHREAD_MUTEX_LOCK''@|$(REPLACE_PTHREAD_MUTEX_LOCK)|g' \
1909 -e 's|@''REPLACE_PTHREAD_MUTEX_TRYLOCK''@|$(REPLACE_PTHREAD_MUTEX_TRYLOCK)|g' \
1910 -e 's|@''REPLACE_PTHREAD_MUTEX_TIMEDLOCK''@|$(REPLACE_PTHREAD_MUTEX_TIMEDLOCK)|g' \
1911 -e 's|@''REPLACE_PTHREAD_MUTEX_UNLOCK''@|$(REPLACE_PTHREAD_MUTEX_UNLOCK)|g' \
1912 -e 's|@''REPLACE_PTHREAD_MUTEX_DESTROY''@|$(REPLACE_PTHREAD_MUTEX_DESTROY)|g' \
1913 -e 's|@''REPLACE_PTHREAD_RWLOCK_INIT''@|$(REPLACE_PTHREAD_RWLOCK_INIT)|g' \
1914 -e 's|@''REPLACE_PTHREAD_RWLOCKATTR_INIT''@|$(REPLACE_PTHREAD_RWLOCKATTR_INIT)|g' \
1915 -e 's|@''REPLACE_PTHREAD_RWLOCKATTR_DESTROY''@|$(REPLACE_PTHREAD_RWLOCKATTR_DESTROY)|g' \
1916 -e 's|@''REPLACE_PTHREAD_RWLOCK_RDLOCK''@|$(REPLACE_PTHREAD_RWLOCK_RDLOCK)|g' \
1917 -e 's|@''REPLACE_PTHREAD_RWLOCK_WRLOCK''@|$(REPLACE_PTHREAD_RWLOCK_WRLOCK)|g' \
1918 -e 's|@''REPLACE_PTHREAD_RWLOCK_TRYRDLOCK''@|$(REPLACE_PTHREAD_RWLOCK_TRYRDLOCK)|g' \
1919 -e 's|@''REPLACE_PTHREAD_RWLOCK_TRYWRLOCK''@|$(REPLACE_PTHREAD_RWLOCK_TRYWRLOCK)|g' \
1920 -e 's|@''REPLACE_PTHREAD_RWLOCK_TIMEDRDLOCK''@|$(REPLACE_PTHREAD_RWLOCK_TIMEDRDLOCK)|g' \
1921 -e 's|@''REPLACE_PTHREAD_RWLOCK_TIMEDWRLOCK''@|$(REPLACE_PTHREAD_RWLOCK_TIMEDWRLOCK)|g' \
1922 -e 's|@''REPLACE_PTHREAD_RWLOCK_UNLOCK''@|$(REPLACE_PTHREAD_RWLOCK_UNLOCK)|g' \
1923 -e 's|@''REPLACE_PTHREAD_RWLOCK_DESTROY''@|$(REPLACE_PTHREAD_RWLOCK_DESTROY)|g' \
1924 < $@-t2 > $@-t3
1925 $(AM_V_at)sed \
1926 -e 's|@''REPLACE_PTHREAD_COND_INIT''@|$(REPLACE_PTHREAD_COND_INIT)|g' \
1927 -e 's|@''REPLACE_PTHREAD_CONDATTR_INIT''@|$(REPLACE_PTHREAD_CONDATTR_INIT)|g' \
1928 -e 's|@''REPLACE_PTHREAD_CONDATTR_DESTROY''@|$(REPLACE_PTHREAD_CONDATTR_DESTROY)|g' \
1929 -e 's|@''REPLACE_PTHREAD_COND_WAIT''@|$(REPLACE_PTHREAD_COND_WAIT)|g' \
1930 -e 's|@''REPLACE_PTHREAD_COND_TIMEDWAIT''@|$(REPLACE_PTHREAD_COND_TIMEDWAIT)|g' \
1931 -e 's|@''REPLACE_PTHREAD_COND_SIGNAL''@|$(REPLACE_PTHREAD_COND_SIGNAL)|g' \
1932 -e 's|@''REPLACE_PTHREAD_COND_BROADCAST''@|$(REPLACE_PTHREAD_COND_BROADCAST)|g' \
1933 -e 's|@''REPLACE_PTHREAD_COND_DESTROY''@|$(REPLACE_PTHREAD_COND_DESTROY)|g' \
1934 -e 's|@''REPLACE_PTHREAD_KEY_CREATE''@|$(REPLACE_PTHREAD_KEY_CREATE)|g' \
1935 -e 's|@''REPLACE_PTHREAD_SETSPECIFIC''@|$(REPLACE_PTHREAD_SETSPECIFIC)|g' \
1936 -e 's|@''REPLACE_PTHREAD_GETSPECIFIC''@|$(REPLACE_PTHREAD_GETSPECIFIC)|g' \
1937 -e 's|@''REPLACE_PTHREAD_KEY_DELETE''@|$(REPLACE_PTHREAD_KEY_DELETE)|g' \
1938 -e 's|@''REPLACE_PTHREAD_SPIN_INIT''@|$(REPLACE_PTHREAD_SPIN_INIT)|g' \
1939 -e 's|@''REPLACE_PTHREAD_SPIN_LOCK''@|$(REPLACE_PTHREAD_SPIN_LOCK)|g' \
1940 -e 's|@''REPLACE_PTHREAD_SPIN_TRYLOCK''@|$(REPLACE_PTHREAD_SPIN_TRYLOCK)|g' \
1941 -e 's|@''REPLACE_PTHREAD_SPIN_UNLOCK''@|$(REPLACE_PTHREAD_SPIN_UNLOCK)|g' \
1942 -e 's|@''REPLACE_PTHREAD_SPIN_DESTROY''@|$(REPLACE_PTHREAD_SPIN_DESTROY)|g' \
1943 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
1944 -e '/definition of _Noreturn/r $(_NORETURN_H)' \
1945 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
1946 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
1947 < $@-t3 > $@-t4
1948 $(AM_V_at)rm -f $@-t1 $@-t2 $@-t3
1949 $(AM_V_at)mv $@-t4 $@
1950MOSTLYCLEANFILES += pthread.h pthread.h-t1 pthread.h-t2 pthread.h-t3 pthread.h-t4
1609 1951
1610EXTRA_DIST += realloc.c 1952EXTRA_DIST += pthread.in.h
1611 1953
1612EXTRA_libgnu_a_SOURCES += realloc.c 1954## end gnulib module pthread-h
1613 1955
1614## end gnulib module realloc-gnu 1956## begin gnulib module pthread-once
1615 1957
1616## begin gnulib module realloc-posix 1958if GL_COND_OBJ_PTHREAD_ONCE
1959libgnu_a_SOURCES += pthread-once.c
1960endif
1617 1961
1962## end gnulib module pthread-once
1618 1963
1619EXTRA_DIST += realloc.c 1964## begin gnulib module realloc-posix
1620 1965
1621EXTRA_libgnu_a_SOURCES += realloc.c 1966if GL_COND_OBJ_REALLOC_POSIX
1967libgnu_a_SOURCES += realloc.c
1968endif
1622 1969
1623## end gnulib module realloc-posix 1970## end gnulib module realloc-posix
1624 1971
@@ -1642,6 +1989,35 @@ EXTRA_libgnu_a_SOURCES += regcomp.c regex_internal.c regexec.c
1642 1989
1643## end gnulib module regex 1990## end gnulib module regex
1644 1991
1992## begin gnulib module sched-h
1993
1994BUILT_SOURCES += sched.h
1995
1996# We need the following in order to create a replacement for <sched.h> when
1997# the system doesn't have one.
1998sched.h: sched.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(WARN_ON_USE_H)
1999 $(gl_V_at)$(SED_HEADER_STDOUT) \
2000 -e 's|@''GUARD_PREFIX''@|GL|g' \
2001 -e 's|@''HAVE_SCHED_H''@|$(HAVE_SCHED_H)|g' \
2002 -e 's|@''HAVE_SYS_CDEFS_H''@|$(HAVE_SYS_CDEFS_H)|g' \
2003 -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
2004 -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
2005 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
2006 -e 's|@''NEXT_SCHED_H''@|$(NEXT_SCHED_H)|g' \
2007 -e 's|@''HAVE_STRUCT_SCHED_PARAM''@|$(HAVE_STRUCT_SCHED_PARAM)|g' \
2008 -e 's/@''GNULIB_SCHED_YIELD''@/$(GL_GNULIB_SCHED_YIELD)/g' \
2009 -e 's|@''HAVE_SCHED_YIELD''@|$(HAVE_SCHED_YIELD)|g' \
2010 -e 's|@''REPLACE_SCHED_YIELD''@|$(REPLACE_SCHED_YIELD)|g' \
2011 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
2012 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
2013 $(srcdir)/sched.in.h > $@-t
2014 $(AM_V_at)mv $@-t $@
2015MOSTLYCLEANFILES += sched.h sched.h-t
2016
2017EXTRA_DIST += sched.in.h
2018
2019## end gnulib module sched-h
2020
1645## begin gnulib module setenv 2021## begin gnulib module setenv
1646 2022
1647if GL_COND_OBJ_SETENV 2023if GL_COND_OBJ_SETENV
@@ -1760,7 +2136,7 @@ EXTRA_DIST += stat-time.h
1760 2136
1761## end gnulib module stat-time 2137## end gnulib module stat-time
1762 2138
1763## begin gnulib module stdckdint 2139## begin gnulib module stdckdint-h
1764 2140
1765BUILT_SOURCES += $(STDCKDINT_H) 2141BUILT_SOURCES += $(STDCKDINT_H)
1766 2142
@@ -1769,6 +2145,15 @@ BUILT_SOURCES += $(STDCKDINT_H)
1769if GL_GENERATE_STDCKDINT_H 2145if GL_GENERATE_STDCKDINT_H
1770stdckdint.h: stdckdint.in.h $(top_builddir)/config.status 2146stdckdint.h: stdckdint.in.h $(top_builddir)/config.status
1771 $(gl_V_at)$(SED_HEADER_STDOUT) \ 2147 $(gl_V_at)$(SED_HEADER_STDOUT) \
2148 -e 's|@''GUARD_PREFIX''@|GL|g' \
2149 -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
2150 -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
2151 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
2152 -e 's|@''NEXT_STDCKDINT_H''@|$(NEXT_STDCKDINT_H)|g' \
2153 -e 's|@''HAVE_C_STDCKDINT_H''@|$(HAVE_C_STDCKDINT_H)|g' \
2154 -e 's|@''HAVE_WORKING_C_STDCKDINT_H''@|$(HAVE_WORKING_C_STDCKDINT_H)|g' \
2155 -e 's|@''HAVE_CXX_STDCKDINT_H''@|$(HAVE_CXX_STDCKDINT_H)|g' \
2156 -e 's|@''HAVE_WORKING_CXX_STDCKDINT_H''@|$(HAVE_WORKING_CXX_STDCKDINT_H)|g' \
1772 $(srcdir)/stdckdint.in.h > $@-t 2157 $(srcdir)/stdckdint.in.h > $@-t
1773 $(AM_V_at)mv $@-t $@ 2158 $(AM_V_at)mv $@-t $@
1774else 2159else
@@ -1779,9 +2164,9 @@ MOSTLYCLEANFILES += stdckdint.h stdckdint.h-t
1779 2164
1780EXTRA_DIST += intprops-internal.h stdckdint.in.h 2165EXTRA_DIST += intprops-internal.h stdckdint.in.h
1781 2166
1782## end gnulib module stdckdint 2167## end gnulib module stdckdint-h
1783 2168
1784## begin gnulib module stddef 2169## begin gnulib module stddef-h
1785 2170
1786BUILT_SOURCES += $(STDDEF_H) 2171BUILT_SOURCES += $(STDDEF_H)
1787 2172
@@ -1795,9 +2180,11 @@ stddef.h: stddef.in.h $(top_builddir)/config.status
1795 -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \ 2180 -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
1796 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ 2181 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
1797 -e 's|@''NEXT_STDDEF_H''@|$(NEXT_STDDEF_H)|g' \ 2182 -e 's|@''NEXT_STDDEF_H''@|$(NEXT_STDDEF_H)|g' \
1798 -e 's|@''HAVE_MAX_ALIGN_T''@|$(HAVE_MAX_ALIGN_T)|g' \ 2183 -e 's|@''NULLPTR_T_NEEDS_STDDEF''@|$(NULLPTR_T_NEEDS_STDDEF)|g' \
1799 -e 's|@''HAVE_WCHAR_T''@|$(HAVE_WCHAR_T)|g' \ 2184 -e 's|@''STDDEF_NOT_IDEMPOTENT''@|$(STDDEF_NOT_IDEMPOTENT)|g' \
1800 -e 's|@''REPLACE_NULL''@|$(REPLACE_NULL)|g' \ 2185 -e 's|@''REPLACE_NULL''@|$(REPLACE_NULL)|g' \
2186 -e 's|@''HAVE_MAX_ALIGN_T''@|$(HAVE_MAX_ALIGN_T)|g' \
2187 -e 's|@''HAVE_C_UNREACHABLE''@|$(HAVE_C_UNREACHABLE)|g' \
1801 $(srcdir)/stddef.in.h > $@-t 2188 $(srcdir)/stddef.in.h > $@-t
1802 $(AM_V_at)mv $@-t $@ 2189 $(AM_V_at)mv $@-t $@
1803else 2190else
@@ -1808,9 +2195,9 @@ MOSTLYCLEANFILES += stddef.h stddef.h-t
1808 2195
1809EXTRA_DIST += stddef.in.h 2196EXTRA_DIST += stddef.in.h
1810 2197
1811## end gnulib module stddef 2198## end gnulib module stddef-h
1812 2199
1813## begin gnulib module stdint 2200## begin gnulib module stdint-h
1814 2201
1815BUILT_SOURCES += $(STDINT_H) 2202BUILT_SOURCES += $(STDINT_H)
1816 2203
@@ -1856,9 +2243,9 @@ MOSTLYCLEANFILES += stdint.h stdint.h-t
1856 2243
1857EXTRA_DIST += stdint.in.h 2244EXTRA_DIST += stdint.in.h
1858 2245
1859## end gnulib module stdint 2246## end gnulib module stdint-h
1860 2247
1861## begin gnulib module stdio 2248## begin gnulib module stdio-h
1862 2249
1863BUILT_SOURCES += stdio.h 2250BUILT_SOURCES += stdio.h
1864 2251
@@ -1872,6 +2259,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
1872 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ 2259 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
1873 -e 's|@''NEXT_STDIO_H''@|$(NEXT_STDIO_H)|g' \ 2260 -e 's|@''NEXT_STDIO_H''@|$(NEXT_STDIO_H)|g' \
1874 -e 's/@''GNULIB_DPRINTF''@/$(GL_GNULIB_DPRINTF)/g' \ 2261 -e 's/@''GNULIB_DPRINTF''@/$(GL_GNULIB_DPRINTF)/g' \
2262 -e 's/@''GNULIB_DZPRINTF''@/$(GL_GNULIB_DZPRINTF)/g' \
1875 -e 's/@''GNULIB_FCLOSE''@/$(GL_GNULIB_FCLOSE)/g' \ 2263 -e 's/@''GNULIB_FCLOSE''@/$(GL_GNULIB_FCLOSE)/g' \
1876 -e 's/@''GNULIB_FDOPEN''@/$(GL_GNULIB_FDOPEN)/g' \ 2264 -e 's/@''GNULIB_FDOPEN''@/$(GL_GNULIB_FDOPEN)/g' \
1877 -e 's/@''GNULIB_FFLUSH''@/$(GL_GNULIB_FFLUSH)/g' \ 2265 -e 's/@''GNULIB_FFLUSH''@/$(GL_GNULIB_FFLUSH)/g' \
@@ -1892,12 +2280,14 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
1892 -e 's/@''GNULIB_FTELL''@/$(GL_GNULIB_FTELL)/g' \ 2280 -e 's/@''GNULIB_FTELL''@/$(GL_GNULIB_FTELL)/g' \
1893 -e 's/@''GNULIB_FTELLO''@/$(GL_GNULIB_FTELLO)/g' \ 2281 -e 's/@''GNULIB_FTELLO''@/$(GL_GNULIB_FTELLO)/g' \
1894 -e 's/@''GNULIB_FWRITE''@/$(GL_GNULIB_FWRITE)/g' \ 2282 -e 's/@''GNULIB_FWRITE''@/$(GL_GNULIB_FWRITE)/g' \
2283 -e 's/@''GNULIB_FZPRINTF''@/$(GL_GNULIB_FZPRINTF)/g' \
1895 -e 's/@''GNULIB_GETC''@/$(GL_GNULIB_GETC)/g' \ 2284 -e 's/@''GNULIB_GETC''@/$(GL_GNULIB_GETC)/g' \
1896 -e 's/@''GNULIB_GETCHAR''@/$(GL_GNULIB_GETCHAR)/g' \ 2285 -e 's/@''GNULIB_GETCHAR''@/$(GL_GNULIB_GETCHAR)/g' \
1897 -e 's/@''GNULIB_GETDELIM''@/$(GL_GNULIB_GETDELIM)/g' \ 2286 -e 's/@''GNULIB_GETDELIM''@/$(GL_GNULIB_GETDELIM)/g' \
1898 -e 's/@''GNULIB_GETLINE''@/$(GL_GNULIB_GETLINE)/g' \ 2287 -e 's/@''GNULIB_GETLINE''@/$(GL_GNULIB_GETLINE)/g' \
1899 -e 's/@''GNULIB_OBSTACK_PRINTF''@/$(GL_GNULIB_OBSTACK_PRINTF)/g' \ 2288 -e 's/@''GNULIB_OBSTACK_PRINTF''@/$(GL_GNULIB_OBSTACK_PRINTF)/g' \
1900 -e 's/@''GNULIB_OBSTACK_PRINTF_POSIX''@/$(GL_GNULIB_OBSTACK_PRINTF_POSIX)/g' \ 2289 -e 's/@''GNULIB_OBSTACK_PRINTF_POSIX''@/$(GL_GNULIB_OBSTACK_PRINTF_POSIX)/g' \
2290 -e 's/@''GNULIB_OBSTACK_ZPRINTF''@/$(GL_GNULIB_OBSTACK_ZPRINTF)/g' \
1901 -e 's/@''GNULIB_PCLOSE''@/$(GL_GNULIB_PCLOSE)/g' \ 2291 -e 's/@''GNULIB_PCLOSE''@/$(GL_GNULIB_PCLOSE)/g' \
1902 -e 's/@''GNULIB_PERROR''@/$(GL_GNULIB_PERROR)/g' \ 2292 -e 's/@''GNULIB_PERROR''@/$(GL_GNULIB_PERROR)/g' \
1903 -e 's/@''GNULIB_POPEN''@/$(GL_GNULIB_POPEN)/g' \ 2293 -e 's/@''GNULIB_POPEN''@/$(GL_GNULIB_POPEN)/g' \
@@ -1911,20 +2301,29 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
1911 -e 's/@''GNULIB_RENAMEAT''@/$(GL_GNULIB_RENAMEAT)/g' \ 2301 -e 's/@''GNULIB_RENAMEAT''@/$(GL_GNULIB_RENAMEAT)/g' \
1912 -e 's/@''GNULIB_SCANF''@/$(GL_GNULIB_SCANF)/g' \ 2302 -e 's/@''GNULIB_SCANF''@/$(GL_GNULIB_SCANF)/g' \
1913 -e 's/@''GNULIB_SNPRINTF''@/$(GL_GNULIB_SNPRINTF)/g' \ 2303 -e 's/@''GNULIB_SNPRINTF''@/$(GL_GNULIB_SNPRINTF)/g' \
2304 -e 's/@''GNULIB_SNZPRINTF''@/$(GL_GNULIB_SNZPRINTF)/g' \
1914 -e 's/@''GNULIB_SPRINTF_POSIX''@/$(GL_GNULIB_SPRINTF_POSIX)/g' \ 2305 -e 's/@''GNULIB_SPRINTF_POSIX''@/$(GL_GNULIB_SPRINTF_POSIX)/g' \
1915 -e 's/@''GNULIB_STDIO_H_NONBLOCKING''@/$(GL_GNULIB_STDIO_H_NONBLOCKING)/g' \ 2306 -e 's/@''GNULIB_STDIO_H_NONBLOCKING''@/$(GL_GNULIB_STDIO_H_NONBLOCKING)/g' \
1916 -e 's/@''GNULIB_STDIO_H_SIGPIPE''@/$(GL_GNULIB_STDIO_H_SIGPIPE)/g' \ 2307 -e 's/@''GNULIB_STDIO_H_SIGPIPE''@/$(GL_GNULIB_STDIO_H_SIGPIPE)/g' \
2308 -e 's/@''GNULIB_SZPRINTF''@/$(GL_GNULIB_SZPRINTF)/g' \
1917 -e 's/@''GNULIB_TMPFILE''@/$(GL_GNULIB_TMPFILE)/g' \ 2309 -e 's/@''GNULIB_TMPFILE''@/$(GL_GNULIB_TMPFILE)/g' \
1918 -e 's/@''GNULIB_VASPRINTF''@/$(GL_GNULIB_VASPRINTF)/g' \ 2310 -e 's/@''GNULIB_VASPRINTF''@/$(GL_GNULIB_VASPRINTF)/g' \
2311 -e 's/@''GNULIB_VASZPRINTF''@/$(GL_GNULIB_VASZPRINTF)/g' \
1919 -e 's/@''GNULIB_VDPRINTF''@/$(GL_GNULIB_VDPRINTF)/g' \ 2312 -e 's/@''GNULIB_VDPRINTF''@/$(GL_GNULIB_VDPRINTF)/g' \
2313 -e 's/@''GNULIB_VDZPRINTF''@/$(GL_GNULIB_VDZPRINTF)/g' \
1920 -e 's/@''GNULIB_VFPRINTF''@/$(GL_GNULIB_VFPRINTF)/g' \ 2314 -e 's/@''GNULIB_VFPRINTF''@/$(GL_GNULIB_VFPRINTF)/g' \
1921 -e 's/@''GNULIB_VFPRINTF_POSIX''@/$(GL_GNULIB_VFPRINTF_POSIX)/g' \ 2315 -e 's/@''GNULIB_VFPRINTF_POSIX''@/$(GL_GNULIB_VFPRINTF_POSIX)/g' \
2316 -e 's/@''GNULIB_VFZPRINTF''@/$(GL_GNULIB_VFZPRINTF)/g' \
1922 -e 's/@''GNULIB_VFSCANF''@/$(GL_GNULIB_VFSCANF)/g' \ 2317 -e 's/@''GNULIB_VFSCANF''@/$(GL_GNULIB_VFSCANF)/g' \
1923 -e 's/@''GNULIB_VSCANF''@/$(GL_GNULIB_VSCANF)/g' \ 2318 -e 's/@''GNULIB_VSCANF''@/$(GL_GNULIB_VSCANF)/g' \
1924 -e 's/@''GNULIB_VPRINTF''@/$(GL_GNULIB_VPRINTF)/g' \ 2319 -e 's/@''GNULIB_VPRINTF''@/$(GL_GNULIB_VPRINTF)/g' \
1925 -e 's/@''GNULIB_VPRINTF_POSIX''@/$(GL_GNULIB_VPRINTF_POSIX)/g' \ 2320 -e 's/@''GNULIB_VPRINTF_POSIX''@/$(GL_GNULIB_VPRINTF_POSIX)/g' \
1926 -e 's/@''GNULIB_VSNPRINTF''@/$(GL_GNULIB_VSNPRINTF)/g' \ 2321 -e 's/@''GNULIB_VSNPRINTF''@/$(GL_GNULIB_VSNPRINTF)/g' \
2322 -e 's/@''GNULIB_VSNZPRINTF''@/$(GL_GNULIB_VSNZPRINTF)/g' \
1927 -e 's/@''GNULIB_VSPRINTF_POSIX''@/$(GL_GNULIB_VSPRINTF_POSIX)/g' \ 2323 -e 's/@''GNULIB_VSPRINTF_POSIX''@/$(GL_GNULIB_VSPRINTF_POSIX)/g' \
2324 -e 's/@''GNULIB_VSZPRINTF''@/$(GL_GNULIB_VSZPRINTF)/g' \
2325 -e 's/@''GNULIB_VZPRINTF''@/$(GL_GNULIB_VZPRINTF)/g' \
2326 -e 's/@''GNULIB_ZPRINTF''@/$(GL_GNULIB_ZPRINTF)/g' \
1928 -e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GL_GNULIB_MDA_FCLOSEALL)/g' \ 2327 -e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GL_GNULIB_MDA_FCLOSEALL)/g' \
1929 -e 's/@''GNULIB_MDA_FDOPEN''@/$(GL_GNULIB_MDA_FDOPEN)/g' \ 2328 -e 's/@''GNULIB_MDA_FDOPEN''@/$(GL_GNULIB_MDA_FDOPEN)/g' \
1930 -e 's/@''GNULIB_MDA_FILENO''@/$(GL_GNULIB_MDA_FILENO)/g' \ 2329 -e 's/@''GNULIB_MDA_FILENO''@/$(GL_GNULIB_MDA_FILENO)/g' \
@@ -1996,6 +2395,9 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
1996 $(AM_V_at)mv $@-t3 $@ 2395 $(AM_V_at)mv $@-t3 $@
1997MOSTLYCLEANFILES += stdio.h stdio.h-t1 stdio.h-t2 stdio.h-t3 2396MOSTLYCLEANFILES += stdio.h stdio.h-t1 stdio.h-t2 stdio.h-t3
1998 2397
2398if GL_COND_OBJ_STDIO_CONSOLESAFE
2399libgnu_a_SOURCES += stdio-consolesafe.c
2400endif
1999if GL_COND_OBJ_STDIO_READ 2401if GL_COND_OBJ_STDIO_READ
2000libgnu_a_SOURCES += stdio-read.c 2402libgnu_a_SOURCES += stdio-read.c
2001endif 2403endif
@@ -2005,14 +2407,13 @@ endif
2005 2407
2006EXTRA_DIST += stdio.in.h 2408EXTRA_DIST += stdio.in.h
2007 2409
2008## end gnulib module stdio 2410## end gnulib module stdio-h
2009 2411
2010## begin gnulib module stdlib 2412## begin gnulib module stdlib-h
2011 2413
2012BUILT_SOURCES += stdlib.h 2414BUILT_SOURCES += stdlib.h
2415libgnu_a_SOURCES += stdlib.c
2013 2416
2014# We need the following in order to create <stdlib.h> when the system
2015# doesn't have one that works with the given compiler.
2016stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \ 2417stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
2017 $(_NORETURN_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H) 2418 $(_NORETURN_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)
2018 $(gl_V_at)$(SED_HEADER_STDOUT) \ 2419 $(gl_V_at)$(SED_HEADER_STDOUT) \
@@ -2022,6 +2423,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
2022 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ 2423 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
2023 -e 's|@''NEXT_STDLIB_H''@|$(NEXT_STDLIB_H)|g' \ 2424 -e 's|@''NEXT_STDLIB_H''@|$(NEXT_STDLIB_H)|g' \
2024 -e 's/@''GNULIB__EXIT''@/$(GL_GNULIB__EXIT)/g' \ 2425 -e 's/@''GNULIB__EXIT''@/$(GL_GNULIB__EXIT)/g' \
2426 -e 's/@''GNULIB_ABORT_DEBUG''@/$(GL_GNULIB_ABORT_DEBUG)/g' \
2025 -e 's/@''GNULIB_ALIGNED_ALLOC''@/$(GL_GNULIB_ALIGNED_ALLOC)/g' \ 2427 -e 's/@''GNULIB_ALIGNED_ALLOC''@/$(GL_GNULIB_ALIGNED_ALLOC)/g' \
2026 -e 's/@''GNULIB_ATOLL''@/$(GL_GNULIB_ATOLL)/g' \ 2428 -e 's/@''GNULIB_ATOLL''@/$(GL_GNULIB_ATOLL)/g' \
2027 -e 's/@''GNULIB_CALLOC_GNU''@/$(GL_GNULIB_CALLOC_GNU)/g' \ 2429 -e 's/@''GNULIB_CALLOC_GNU''@/$(GL_GNULIB_CALLOC_GNU)/g' \
@@ -2050,13 +2452,13 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
2050 -e 's/@''GNULIB_RAND''@/$(GL_GNULIB_RAND)/g' \ 2452 -e 's/@''GNULIB_RAND''@/$(GL_GNULIB_RAND)/g' \
2051 -e 's/@''GNULIB_RANDOM''@/$(GL_GNULIB_RANDOM)/g' \ 2453 -e 's/@''GNULIB_RANDOM''@/$(GL_GNULIB_RANDOM)/g' \
2052 -e 's/@''GNULIB_RANDOM_R''@/$(GL_GNULIB_RANDOM_R)/g' \ 2454 -e 's/@''GNULIB_RANDOM_R''@/$(GL_GNULIB_RANDOM_R)/g' \
2053 -e 's/@''GNULIB_REALLOC_GNU''@/$(GL_GNULIB_REALLOC_GNU)/g' \
2054 -e 's/@''GNULIB_REALLOC_POSIX''@/$(GL_GNULIB_REALLOC_POSIX)/g' \ 2455 -e 's/@''GNULIB_REALLOC_POSIX''@/$(GL_GNULIB_REALLOC_POSIX)/g' \
2055 -e 's/@''GNULIB_REALLOCARRAY''@/$(GL_GNULIB_REALLOCARRAY)/g' \ 2456 -e 's/@''GNULIB_REALLOCARRAY''@/$(GL_GNULIB_REALLOCARRAY)/g' \
2056 -e 's/@''GNULIB_REALPATH''@/$(GL_GNULIB_REALPATH)/g' \ 2457 -e 's/@''GNULIB_REALPATH''@/$(GL_GNULIB_REALPATH)/g' \
2057 -e 's/@''GNULIB_RPMATCH''@/$(GL_GNULIB_RPMATCH)/g' \ 2458 -e 's/@''GNULIB_RPMATCH''@/$(GL_GNULIB_RPMATCH)/g' \
2058 -e 's/@''GNULIB_SECURE_GETENV''@/$(GL_GNULIB_SECURE_GETENV)/g' \ 2459 -e 's/@''GNULIB_SECURE_GETENV''@/$(GL_GNULIB_SECURE_GETENV)/g' \
2059 -e 's/@''GNULIB_SETENV''@/$(GL_GNULIB_SETENV)/g' \ 2460 -e 's/@''GNULIB_SETENV''@/$(GL_GNULIB_SETENV)/g' \
2461 -e 's/@''GNULIB_STACK_TRACE''@/$(GL_GNULIB_STACK_TRACE)/g' \
2060 -e 's/@''GNULIB_STRTOD''@/$(GL_GNULIB_STRTOD)/g' \ 2462 -e 's/@''GNULIB_STRTOD''@/$(GL_GNULIB_STRTOD)/g' \
2061 -e 's/@''GNULIB_STRTOF''@/$(GL_GNULIB_STRTOF)/g' \ 2463 -e 's/@''GNULIB_STRTOF''@/$(GL_GNULIB_STRTOF)/g' \
2062 -e 's/@''GNULIB_STRTOL''@/$(GL_GNULIB_STRTOL)/g' \ 2464 -e 's/@''GNULIB_STRTOL''@/$(GL_GNULIB_STRTOL)/g' \
@@ -2124,6 +2526,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
2124 < $@-t1 > $@-t2 2526 < $@-t1 > $@-t2
2125 $(AM_V_at)sed \ 2527 $(AM_V_at)sed \
2126 -e 's|@''REPLACE__EXIT''@|$(REPLACE__EXIT)|g' \ 2528 -e 's|@''REPLACE__EXIT''@|$(REPLACE__EXIT)|g' \
2529 -e 's|@''REPLACE_ABORT''@|$(REPLACE_ABORT)|g' \
2127 -e 's|@''REPLACE_ALIGNED_ALLOC''@|$(REPLACE_ALIGNED_ALLOC)|g' \ 2530 -e 's|@''REPLACE_ALIGNED_ALLOC''@|$(REPLACE_ALIGNED_ALLOC)|g' \
2128 -e 's|@''REPLACE_CALLOC_FOR_CALLOC_GNU''@|$(REPLACE_CALLOC_FOR_CALLOC_GNU)|g' \ 2531 -e 's|@''REPLACE_CALLOC_FOR_CALLOC_GNU''@|$(REPLACE_CALLOC_FOR_CALLOC_GNU)|g' \
2129 -e 's|@''REPLACE_CALLOC_FOR_CALLOC_POSIX''@|$(REPLACE_CALLOC_FOR_CALLOC_POSIX)|g' \ 2532 -e 's|@''REPLACE_CALLOC_FOR_CALLOC_POSIX''@|$(REPLACE_CALLOC_FOR_CALLOC_POSIX)|g' \
@@ -2150,7 +2553,6 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
2150 -e 's|@''REPLACE_RAND''@|$(REPLACE_RAND)|g' \ 2553 -e 's|@''REPLACE_RAND''@|$(REPLACE_RAND)|g' \
2151 -e 's|@''REPLACE_RANDOM''@|$(REPLACE_RANDOM)|g' \ 2554 -e 's|@''REPLACE_RANDOM''@|$(REPLACE_RANDOM)|g' \
2152 -e 's|@''REPLACE_RANDOM_R''@|$(REPLACE_RANDOM_R)|g' \ 2555 -e 's|@''REPLACE_RANDOM_R''@|$(REPLACE_RANDOM_R)|g' \
2153 -e 's|@''REPLACE_REALLOC_FOR_REALLOC_GNU''@|$(REPLACE_REALLOC_FOR_REALLOC_GNU)|g' \
2154 -e 's|@''REPLACE_REALLOC_FOR_REALLOC_POSIX''@|$(REPLACE_REALLOC_FOR_REALLOC_POSIX)|g' \ 2556 -e 's|@''REPLACE_REALLOC_FOR_REALLOC_POSIX''@|$(REPLACE_REALLOC_FOR_REALLOC_POSIX)|g' \
2155 -e 's|@''REPLACE_REALLOCARRAY''@|$(REPLACE_REALLOCARRAY)|g' \ 2557 -e 's|@''REPLACE_REALLOCARRAY''@|$(REPLACE_REALLOCARRAY)|g' \
2156 -e 's|@''REPLACE_REALPATH''@|$(REPLACE_REALPATH)|g' \ 2558 -e 's|@''REPLACE_REALPATH''@|$(REPLACE_REALPATH)|g' \
@@ -2165,6 +2567,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
2165 -e 's|@''REPLACE_STRTOULL''@|$(REPLACE_STRTOULL)|g' \ 2567 -e 's|@''REPLACE_STRTOULL''@|$(REPLACE_STRTOULL)|g' \
2166 -e 's|@''REPLACE_UNSETENV''@|$(REPLACE_UNSETENV)|g' \ 2568 -e 's|@''REPLACE_UNSETENV''@|$(REPLACE_UNSETENV)|g' \
2167 -e 's|@''REPLACE_WCTOMB''@|$(REPLACE_WCTOMB)|g' \ 2569 -e 's|@''REPLACE_WCTOMB''@|$(REPLACE_WCTOMB)|g' \
2570 -e 's|@''CAN_PRINT_STACK_TRACE''@|$(CAN_PRINT_STACK_TRACE)|g' \
2168 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ 2571 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
2169 -e '/definition of _Noreturn/r $(_NORETURN_H)' \ 2572 -e '/definition of _Noreturn/r $(_NORETURN_H)' \
2170 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ 2573 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
@@ -2176,18 +2579,15 @@ MOSTLYCLEANFILES += stdlib.h stdlib.h-t1 stdlib.h-t2 stdlib.h-t3
2176 2579
2177EXTRA_DIST += stdlib.in.h 2580EXTRA_DIST += stdlib.in.h
2178 2581
2179## end gnulib module stdlib 2582## end gnulib module stdlib-h
2180 2583
2181## begin gnulib module strcase 2584## begin gnulib module strcasecmp
2182 2585
2183if GL_COND_OBJ_STRCASECMP 2586if GL_COND_OBJ_STRCASECMP
2184libgnu_a_SOURCES += strcasecmp.c 2587libgnu_a_SOURCES += strcasecmp.c
2185endif 2588endif
2186if GL_COND_OBJ_STRNCASECMP
2187libgnu_a_SOURCES += strncasecmp.c
2188endif
2189 2589
2190## end gnulib module strcase 2590## end gnulib module strcasecmp
2191 2591
2192## begin gnulib module strcasestr 2592## begin gnulib module strcasestr
2193 2593
@@ -2232,7 +2632,7 @@ EXTRA_DIST += strerror-override.h
2232 2632
2233## end gnulib module strerror-override 2633## end gnulib module strerror-override
2234 2634
2235## begin gnulib module string 2635## begin gnulib module string-h
2236 2636
2237BUILT_SOURCES += string.h 2637BUILT_SOURCES += string.h
2238 2638
@@ -2262,6 +2662,8 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2262 -e 's/@''GNULIB_MBSSPN''@/$(GL_GNULIB_MBSSPN)/g' \ 2662 -e 's/@''GNULIB_MBSSPN''@/$(GL_GNULIB_MBSSPN)/g' \
2263 -e 's/@''GNULIB_MBSSEP''@/$(GL_GNULIB_MBSSEP)/g' \ 2663 -e 's/@''GNULIB_MBSSEP''@/$(GL_GNULIB_MBSSEP)/g' \
2264 -e 's/@''GNULIB_MBSTOK_R''@/$(GL_GNULIB_MBSTOK_R)/g' \ 2664 -e 's/@''GNULIB_MBSTOK_R''@/$(GL_GNULIB_MBSTOK_R)/g' \
2665 -e 's/@''GNULIB_MBS_ENDSWITH''@/$(GL_GNULIB_MBS_ENDSWITH)/g' \
2666 -e 's/@''GNULIB_MBS_STARTSWITH''@/$(GL_GNULIB_MBS_STARTSWITH)/g' \
2265 -e 's/@''GNULIB_MEMCHR''@/$(GL_GNULIB_MEMCHR)/g' \ 2667 -e 's/@''GNULIB_MEMCHR''@/$(GL_GNULIB_MEMCHR)/g' \
2266 -e 's/@''GNULIB_MEMMEM''@/$(GL_GNULIB_MEMMEM)/g' \ 2668 -e 's/@''GNULIB_MEMMEM''@/$(GL_GNULIB_MEMMEM)/g' \
2267 -e 's/@''GNULIB_MEMPCPY''@/$(GL_GNULIB_MEMPCPY)/g' \ 2669 -e 's/@''GNULIB_MEMPCPY''@/$(GL_GNULIB_MEMPCPY)/g' \
@@ -2273,6 +2675,7 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2273 -e 's/@''GNULIB_STRCHRNUL''@/$(GL_GNULIB_STRCHRNUL)/g' \ 2675 -e 's/@''GNULIB_STRCHRNUL''@/$(GL_GNULIB_STRCHRNUL)/g' \
2274 -e 's/@''GNULIB_STRDUP''@/$(GL_GNULIB_STRDUP)/g' \ 2676 -e 's/@''GNULIB_STRDUP''@/$(GL_GNULIB_STRDUP)/g' \
2275 -e 's/@''GNULIB_STRNCAT''@/$(GL_GNULIB_STRNCAT)/g' \ 2677 -e 's/@''GNULIB_STRNCAT''@/$(GL_GNULIB_STRNCAT)/g' \
2678 -e 's/@''GNULIB_STRNCPY''@/$(GL_GNULIB_STRNCPY)/g' \
2276 -e 's/@''GNULIB_STRNDUP''@/$(GL_GNULIB_STRNDUP)/g' \ 2679 -e 's/@''GNULIB_STRNDUP''@/$(GL_GNULIB_STRNDUP)/g' \
2277 -e 's/@''GNULIB_STRNLEN''@/$(GL_GNULIB_STRNLEN)/g' \ 2680 -e 's/@''GNULIB_STRNLEN''@/$(GL_GNULIB_STRNLEN)/g' \
2278 -e 's/@''GNULIB_STRPBRK''@/$(GL_GNULIB_STRPBRK)/g' \ 2681 -e 's/@''GNULIB_STRPBRK''@/$(GL_GNULIB_STRPBRK)/g' \
@@ -2280,8 +2683,11 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2280 -e 's/@''GNULIB_STRSTR''@/$(GL_GNULIB_STRSTR)/g' \ 2683 -e 's/@''GNULIB_STRSTR''@/$(GL_GNULIB_STRSTR)/g' \
2281 -e 's/@''GNULIB_STRCASESTR''@/$(GL_GNULIB_STRCASESTR)/g' \ 2684 -e 's/@''GNULIB_STRCASESTR''@/$(GL_GNULIB_STRCASESTR)/g' \
2282 -e 's/@''GNULIB_STRTOK_R''@/$(GL_GNULIB_STRTOK_R)/g' \ 2685 -e 's/@''GNULIB_STRTOK_R''@/$(GL_GNULIB_STRTOK_R)/g' \
2686 -e 's/@''GNULIB_STR_ENDSWITH''@/$(GL_GNULIB_STR_ENDSWITH)/g' \
2687 -e 's/@''GNULIB_STR_STARTSWITH''@/$(GL_GNULIB_STR_STARTSWITH)/g' \
2283 -e 's/@''GNULIB_STRERROR''@/$(GL_GNULIB_STRERROR)/g' \ 2688 -e 's/@''GNULIB_STRERROR''@/$(GL_GNULIB_STRERROR)/g' \
2284 -e 's/@''GNULIB_STRERROR_R''@/$(GL_GNULIB_STRERROR_R)/g' \ 2689 -e 's/@''GNULIB_STRERROR_R''@/$(GL_GNULIB_STRERROR_R)/g' \
2690 -e 's/@''GNULIB_STRERROR_L''@/$(GL_GNULIB_STRERROR_L)/g' \
2285 -e 's/@''GNULIB_STRERRORNAME_NP''@/$(GL_GNULIB_STRERRORNAME_NP)/g' \ 2691 -e 's/@''GNULIB_STRERRORNAME_NP''@/$(GL_GNULIB_STRERRORNAME_NP)/g' \
2286 -e 's/@''GNULIB_SIGABBREV_NP''@/$(GL_GNULIB_SIGABBREV_NP)/g' \ 2692 -e 's/@''GNULIB_SIGABBREV_NP''@/$(GL_GNULIB_SIGABBREV_NP)/g' \
2287 -e 's/@''GNULIB_SIGDESCR_NP''@/$(GL_GNULIB_SIGDESCR_NP)/g' \ 2693 -e 's/@''GNULIB_SIGDESCR_NP''@/$(GL_GNULIB_SIGDESCR_NP)/g' \
@@ -2312,6 +2718,7 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2312 -e 's|@''HAVE_STRCASESTR''@|$(HAVE_STRCASESTR)|g' \ 2718 -e 's|@''HAVE_STRCASESTR''@|$(HAVE_STRCASESTR)|g' \
2313 -e 's|@''HAVE_DECL_STRTOK_R''@|$(HAVE_DECL_STRTOK_R)|g' \ 2719 -e 's|@''HAVE_DECL_STRTOK_R''@|$(HAVE_DECL_STRTOK_R)|g' \
2314 -e 's|@''HAVE_DECL_STRERROR_R''@|$(HAVE_DECL_STRERROR_R)|g' \ 2720 -e 's|@''HAVE_DECL_STRERROR_R''@|$(HAVE_DECL_STRERROR_R)|g' \
2721 -e 's|@''HAVE_STRERROR_L''@|$(HAVE_STRERROR_L)|g' \
2315 -e 's|@''HAVE_STRERRORNAME_NP''@|$(HAVE_STRERRORNAME_NP)|g' \ 2722 -e 's|@''HAVE_STRERRORNAME_NP''@|$(HAVE_STRERRORNAME_NP)|g' \
2316 -e 's|@''HAVE_SIGABBREV_NP''@|$(HAVE_SIGABBREV_NP)|g' \ 2723 -e 's|@''HAVE_SIGABBREV_NP''@|$(HAVE_SIGABBREV_NP)|g' \
2317 -e 's|@''HAVE_SIGDESCR_NP''@|$(HAVE_SIGDESCR_NP)|g' \ 2724 -e 's|@''HAVE_SIGDESCR_NP''@|$(HAVE_SIGDESCR_NP)|g' \
@@ -2328,6 +2735,7 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2328 -e 's|@''REPLACE_STRCHRNUL''@|$(REPLACE_STRCHRNUL)|g' \ 2735 -e 's|@''REPLACE_STRCHRNUL''@|$(REPLACE_STRCHRNUL)|g' \
2329 -e 's|@''REPLACE_STRDUP''@|$(REPLACE_STRDUP)|g' \ 2736 -e 's|@''REPLACE_STRDUP''@|$(REPLACE_STRDUP)|g' \
2330 -e 's|@''REPLACE_STRNCAT''@|$(REPLACE_STRNCAT)|g' \ 2737 -e 's|@''REPLACE_STRNCAT''@|$(REPLACE_STRNCAT)|g' \
2738 -e 's|@''REPLACE_STRNCPY''@|$(REPLACE_STRNCPY)|g' \
2331 -e 's|@''REPLACE_STRNDUP''@|$(REPLACE_STRNDUP)|g' \ 2739 -e 's|@''REPLACE_STRNDUP''@|$(REPLACE_STRNDUP)|g' \
2332 -e 's|@''REPLACE_STRNLEN''@|$(REPLACE_STRNLEN)|g' \ 2740 -e 's|@''REPLACE_STRNLEN''@|$(REPLACE_STRNLEN)|g' \
2333 -e 's|@''REPLACE_STRSTR''@|$(REPLACE_STRSTR)|g' \ 2741 -e 's|@''REPLACE_STRSTR''@|$(REPLACE_STRSTR)|g' \
@@ -2335,6 +2743,7 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2335 -e 's|@''REPLACE_STRTOK_R''@|$(REPLACE_STRTOK_R)|g' \ 2743 -e 's|@''REPLACE_STRTOK_R''@|$(REPLACE_STRTOK_R)|g' \
2336 -e 's|@''REPLACE_STRERROR''@|$(REPLACE_STRERROR)|g' \ 2744 -e 's|@''REPLACE_STRERROR''@|$(REPLACE_STRERROR)|g' \
2337 -e 's|@''REPLACE_STRERROR_R''@|$(REPLACE_STRERROR_R)|g' \ 2745 -e 's|@''REPLACE_STRERROR_R''@|$(REPLACE_STRERROR_R)|g' \
2746 -e 's|@''REPLACE_STRERROR_L''@|$(REPLACE_STRERROR_L)|g' \
2338 -e 's|@''REPLACE_STRERRORNAME_NP''@|$(REPLACE_STRERRORNAME_NP)|g' \ 2747 -e 's|@''REPLACE_STRERRORNAME_NP''@|$(REPLACE_STRERRORNAME_NP)|g' \
2339 -e 's|@''REPLACE_STRSIGNAL''@|$(REPLACE_STRSIGNAL)|g' \ 2748 -e 's|@''REPLACE_STRSIGNAL''@|$(REPLACE_STRSIGNAL)|g' \
2340 -e 's|@''REPLACE_STRVERSCMP''@|$(REPLACE_STRVERSCMP)|g' \ 2749 -e 's|@''REPLACE_STRVERSCMP''@|$(REPLACE_STRVERSCMP)|g' \
@@ -2349,9 +2758,9 @@ MOSTLYCLEANFILES += string.h string.h-t1 string.h-t2
2349 2758
2350EXTRA_DIST += string.in.h 2759EXTRA_DIST += string.in.h
2351 2760
2352## end gnulib module string 2761## end gnulib module string-h
2353 2762
2354## begin gnulib module strings 2763## begin gnulib module strings-h
2355 2764
2356BUILT_SOURCES += strings.h 2765BUILT_SOURCES += strings.h
2357 2766
@@ -2366,9 +2775,20 @@ strings.h: strings.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(WARN_ON_USE
2366 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ 2775 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
2367 -e 's|@''NEXT_STRINGS_H''@|$(NEXT_STRINGS_H)|g' \ 2776 -e 's|@''NEXT_STRINGS_H''@|$(NEXT_STRINGS_H)|g' \
2368 -e 's/@''GNULIB_FFS''@/$(GL_GNULIB_FFS)/g' \ 2777 -e 's/@''GNULIB_FFS''@/$(GL_GNULIB_FFS)/g' \
2778 -e 's/@''GNULIB_STRCASECMP''@/$(GL_GNULIB_STRCASECMP)/g' \
2779 -e 's/@''GNULIB_STRCASECMP_L''@/$(GL_GNULIB_STRCASECMP_L)/g' \
2780 -e 's/@''GNULIB_STRNCASECMP''@/$(GL_GNULIB_STRNCASECMP)/g' \
2781 -e 's/@''GNULIB_STRNCASECMP_L''@/$(GL_GNULIB_STRNCASECMP_L)/g' \
2369 -e 's|@''HAVE_FFS''@|$(HAVE_FFS)|g' \ 2782 -e 's|@''HAVE_FFS''@|$(HAVE_FFS)|g' \
2370 -e 's|@''HAVE_STRCASECMP''@|$(HAVE_STRCASECMP)|g' \ 2783 -e 's|@''HAVE_STRCASECMP''@|$(HAVE_STRCASECMP)|g' \
2784 -e 's|@''HAVE_STRCASECMP_L''@|$(HAVE_STRCASECMP_L)|g' \
2785 -e 's|@''HAVE_STRNCASECMP''@|$(HAVE_STRNCASECMP)|g' \
2786 -e 's|@''HAVE_STRNCASECMP_L''@|$(HAVE_STRNCASECMP_L)|g' \
2371 -e 's|@''HAVE_DECL_STRNCASECMP''@|$(HAVE_DECL_STRNCASECMP)|g' \ 2787 -e 's|@''HAVE_DECL_STRNCASECMP''@|$(HAVE_DECL_STRNCASECMP)|g' \
2788 -e 's|@''REPLACE_STRCASECMP''@|$(REPLACE_STRCASECMP)|g' \
2789 -e 's|@''REPLACE_STRCASECMP_L''@|$(REPLACE_STRCASECMP_L)|g' \
2790 -e 's|@''REPLACE_STRNCASECMP''@|$(REPLACE_STRNCASECMP)|g' \
2791 -e 's|@''REPLACE_STRNCASECMP_L''@|$(REPLACE_STRNCASECMP_L)|g' \
2372 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ 2792 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
2373 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ 2793 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
2374 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ 2794 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
@@ -2378,7 +2798,23 @@ MOSTLYCLEANFILES += strings.h strings.h-t
2378 2798
2379EXTRA_DIST += strings.in.h 2799EXTRA_DIST += strings.in.h
2380 2800
2381## end gnulib module strings 2801## end gnulib module strings-h
2802
2803## begin gnulib module strncasecmp
2804
2805if GL_COND_OBJ_STRNCASECMP
2806libgnu_a_SOURCES += strncasecmp.c
2807endif
2808
2809## end gnulib module strncasecmp
2810
2811## begin gnulib module strncpy
2812
2813if GL_COND_OBJ_STRNCPY
2814libgnu_a_SOURCES += strncpy.c
2815endif
2816
2817## end gnulib module strncpy
2382 2818
2383## begin gnulib module strsep 2819## begin gnulib module strsep
2384 2820
@@ -2397,7 +2833,7 @@ EXTRA_libgnu_a_SOURCES += strstr.c
2397 2833
2398## end gnulib module strstr-simple 2834## end gnulib module strstr-simple
2399 2835
2400## begin gnulib module sys_socket 2836## begin gnulib module sys_socket-h
2401 2837
2402BUILT_SOURCES += sys/socket.h 2838BUILT_SOURCES += sys/socket.h
2403libgnu_a_SOURCES += sys_socket.c 2839libgnu_a_SOURCES += sys_socket.c
@@ -2445,9 +2881,9 @@ MOSTLYCLEANDIRS += sys
2445 2881
2446EXTRA_DIST += sys_socket.in.h 2882EXTRA_DIST += sys_socket.in.h
2447 2883
2448## end gnulib module sys_socket 2884## end gnulib module sys_socket-h
2449 2885
2450## begin gnulib module sys_stat 2886## begin gnulib module sys_stat-h
2451 2887
2452BUILT_SOURCES += sys/stat.h 2888BUILT_SOURCES += sys/stat.h
2453 2889
@@ -2518,9 +2954,9 @@ MOSTLYCLEANDIRS += sys
2518 2954
2519EXTRA_DIST += sys_stat.in.h 2955EXTRA_DIST += sys_stat.in.h
2520 2956
2521## end gnulib module sys_stat 2957## end gnulib module sys_stat-h
2522 2958
2523## begin gnulib module sys_types 2959## begin gnulib module sys_types-h
2524 2960
2525BUILT_SOURCES += sys/types.h 2961BUILT_SOURCES += sys/types.h
2526 2962
@@ -2535,16 +2971,20 @@ sys/types.h: sys_types.in.h $(top_builddir)/config.status
2535 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ 2971 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
2536 -e 's|@''NEXT_SYS_TYPES_H''@|$(NEXT_SYS_TYPES_H)|g' \ 2972 -e 's|@''NEXT_SYS_TYPES_H''@|$(NEXT_SYS_TYPES_H)|g' \
2537 -e 's|@''WINDOWS_64_BIT_OFF_T''@|$(WINDOWS_64_BIT_OFF_T)|g' \ 2973 -e 's|@''WINDOWS_64_BIT_OFF_T''@|$(WINDOWS_64_BIT_OFF_T)|g' \
2974 -e 's|@''HAVE_OFF64_T''@|$(HAVE_OFF64_T)|g' \
2538 -e 's|@''WINDOWS_STAT_INODES''@|$(WINDOWS_STAT_INODES)|g' \ 2975 -e 's|@''WINDOWS_STAT_INODES''@|$(WINDOWS_STAT_INODES)|g' \
2976 -e 's|@''HAVE_BLKSIZE_T''@|$(HAVE_BLKSIZE_T)|g' \
2977 -e 's|@''HAVE_BLKCNT_T''@|$(HAVE_BLKCNT_T)|g' \
2539 $(srcdir)/sys_types.in.h > $@-t 2978 $(srcdir)/sys_types.in.h > $@-t
2540 $(AM_V_at)mv $@-t $@ 2979 $(AM_V_at)mv $@-t $@
2541MOSTLYCLEANFILES += sys/types.h sys/types.h-t 2980MOSTLYCLEANFILES += sys/types.h sys/types.h-t
2981MOSTLYCLEANDIRS += sys
2542 2982
2543EXTRA_DIST += sys_types.in.h 2983EXTRA_DIST += sys_types.in.h
2544 2984
2545## end gnulib module sys_types 2985## end gnulib module sys_types-h
2546 2986
2547## begin gnulib module sys_uio 2987## begin gnulib module sys_uio-h
2548 2988
2549BUILT_SOURCES += sys/uio.h 2989BUILT_SOURCES += sys/uio.h
2550 2990
@@ -2566,7 +3006,7 @@ MOSTLYCLEANDIRS += sys
2566 3006
2567EXTRA_DIST += sys_uio.in.h 3007EXTRA_DIST += sys_uio.in.h
2568 3008
2569## end gnulib module sys_uio 3009## end gnulib module sys_uio-h
2570 3010
2571## begin gnulib module threadlib 3011## begin gnulib module threadlib
2572 3012
@@ -2599,6 +3039,7 @@ time.h: time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
2599 -e 's/@''GNULIB_TIMESPEC_GETRES''@/$(GL_GNULIB_TIMESPEC_GETRES)/g' \ 3039 -e 's/@''GNULIB_TIMESPEC_GETRES''@/$(GL_GNULIB_TIMESPEC_GETRES)/g' \
2600 -e 's/@''GNULIB_TIME_R''@/$(GL_GNULIB_TIME_R)/g' \ 3040 -e 's/@''GNULIB_TIME_R''@/$(GL_GNULIB_TIME_R)/g' \
2601 -e 's/@''GNULIB_TIME_RZ''@/$(GL_GNULIB_TIME_RZ)/g' \ 3041 -e 's/@''GNULIB_TIME_RZ''@/$(GL_GNULIB_TIME_RZ)/g' \
3042 -e 's/@''GNULIB_TZNAME''@/$(GL_GNULIB_TZNAME)/g' \
2602 -e 's/@''GNULIB_TZSET''@/$(GL_GNULIB_TZSET)/g' \ 3043 -e 's/@''GNULIB_TZSET''@/$(GL_GNULIB_TZSET)/g' \
2603 -e 's/@''GNULIB_MDA_TZSET''@/$(GL_GNULIB_MDA_TZSET)/g' \ 3044 -e 's/@''GNULIB_MDA_TZSET''@/$(GL_GNULIB_MDA_TZSET)/g' \
2604 -e 's|@''HAVE_DECL_LOCALTIME_R''@|$(HAVE_DECL_LOCALTIME_R)|g' \ 3045 -e 's|@''HAVE_DECL_LOCALTIME_R''@|$(HAVE_DECL_LOCALTIME_R)|g' \
@@ -2608,11 +3049,14 @@ time.h: time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
2608 -e 's|@''HAVE_TIMESPEC_GET''@|$(HAVE_TIMESPEC_GET)|g' \ 3049 -e 's|@''HAVE_TIMESPEC_GET''@|$(HAVE_TIMESPEC_GET)|g' \
2609 -e 's|@''HAVE_TIMESPEC_GETRES''@|$(HAVE_TIMESPEC_GETRES)|g' \ 3050 -e 's|@''HAVE_TIMESPEC_GETRES''@|$(HAVE_TIMESPEC_GETRES)|g' \
2610 -e 's|@''HAVE_TIMEZONE_T''@|$(HAVE_TIMEZONE_T)|g' \ 3051 -e 's|@''HAVE_TIMEZONE_T''@|$(HAVE_TIMEZONE_T)|g' \
3052 -e 's|@''HAVE_TZALLOC''@|$(HAVE_TZALLOC)|g' \
2611 -e 's|@''REPLACE_CTIME''@|$(REPLACE_CTIME)|g' \ 3053 -e 's|@''REPLACE_CTIME''@|$(REPLACE_CTIME)|g' \
2612 -e 's|@''REPLACE_GMTIME''@|$(REPLACE_GMTIME)|g' \ 3054 -e 's|@''REPLACE_GMTIME''@|$(REPLACE_GMTIME)|g' \
2613 -e 's|@''REPLACE_LOCALTIME''@|$(REPLACE_LOCALTIME)|g' \ 3055 -e 's|@''REPLACE_LOCALTIME''@|$(REPLACE_LOCALTIME)|g' \
2614 -e 's|@''REPLACE_LOCALTIME_R''@|$(REPLACE_LOCALTIME_R)|g' \ 3056 -e 's|@''REPLACE_LOCALTIME_R''@|$(REPLACE_LOCALTIME_R)|g' \
3057 -e 's|@''REPLACE_LOCALTIME_RZ''@|$(REPLACE_LOCALTIME_RZ)|g' \
2615 -e 's|@''REPLACE_MKTIME''@|$(REPLACE_MKTIME)|g' \ 3058 -e 's|@''REPLACE_MKTIME''@|$(REPLACE_MKTIME)|g' \
3059 -e 's|@''REPLACE_MKTIME_Z''@|$(REPLACE_MKTIME_Z)|g' \
2616 -e 's|@''REPLACE_NANOSLEEP''@|$(REPLACE_NANOSLEEP)|g' \ 3060 -e 's|@''REPLACE_NANOSLEEP''@|$(REPLACE_NANOSLEEP)|g' \
2617 -e 's|@''REPLACE_STRFTIME''@|$(REPLACE_STRFTIME)|g' \ 3061 -e 's|@''REPLACE_STRFTIME''@|$(REPLACE_STRFTIME)|g' \
2618 -e 's|@''REPLACE_TIME''@|$(REPLACE_TIME)|g' \ 3062 -e 's|@''REPLACE_TIME''@|$(REPLACE_TIME)|g' \
@@ -2654,7 +3098,412 @@ EXTRA_DIST += mktime-internal.h
2654 3098
2655## end gnulib module timegm 3099## end gnulib module timegm
2656 3100
2657## begin gnulib module unistd 3101## begin gnulib module uchar-h
3102
3103BUILT_SOURCES += uchar.h
3104
3105uchar.h: uchar.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)
3106 $(gl_V_at)$(SED_HEADER_STDOUT) \
3107 -e 's|@''GUARD_PREFIX''@|GL|g' \
3108 -e 's/@''HAVE_UCHAR_H''@/$(HAVE_UCHAR_H)/g' \
3109 -e 's/@''CXX_HAVE_UCHAR_H''@/$(CXX_HAVE_UCHAR_H)/g' \
3110 -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
3111 -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
3112 -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
3113 -e 's|@''NEXT_UCHAR_H''@|$(NEXT_UCHAR_H)|g' \
3114 -e 's|@''CXX_HAS_CHAR8_TYPE''@|$(CXX_HAS_CHAR8_TYPE)|g' \
3115 -e 's|@''CXX_HAS_UCHAR_TYPES''@|$(CXX_HAS_UCHAR_TYPES)|g' \
3116 -e 's|@''SMALL_WCHAR_T''@|$(SMALL_WCHAR_T)|g' \
3117 -e 's|@''GNULIBHEADERS_OVERRIDE_CHAR8_T''@|$(GNULIBHEADERS_OVERRIDE_CHAR8_T)|g' \
3118 -e 's|@''GNULIBHEADERS_OVERRIDE_CHAR16_T''@|$(GNULIBHEADERS_OVERRIDE_CHAR16_T)|g' \
3119 -e 's|@''GNULIBHEADERS_OVERRIDE_CHAR32_T''@|$(GNULIBHEADERS_OVERRIDE_CHAR32_T)|g' \
3120 -e 's/@''GNULIB_BTOC32''@/$(GL_GNULIB_BTOC32)/g' \
3121 -e 's/@''GNULIB_BTOWC''@/$(GL_GNULIB_BTOWC)/g' \
3122 -e 's/@''GNULIB_C32ISALNUM''@/$(GL_GNULIB_C32ISALNUM)/g' \
3123 -e 's/@''GNULIB_C32ISALPHA''@/$(GL_GNULIB_C32ISALPHA)/g' \
3124 -e 's/@''GNULIB_C32ISBLANK''@/$(GL_GNULIB_C32ISBLANK)/g' \
3125 -e 's/@''GNULIB_C32ISCNTRL''@/$(GL_GNULIB_C32ISCNTRL)/g' \
3126 -e 's/@''GNULIB_C32ISDIGIT''@/$(GL_GNULIB_C32ISDIGIT)/g' \
3127 -e 's/@''GNULIB_C32ISGRAPH''@/$(GL_GNULIB_C32ISGRAPH)/g' \
3128 -e 's/@''GNULIB_C32ISLOWER''@/$(GL_GNULIB_C32ISLOWER)/g' \
3129 -e 's/@''GNULIB_C32ISPRINT''@/$(GL_GNULIB_C32ISPRINT)/g' \
3130 -e 's/@''GNULIB_C32ISPUNCT''@/$(GL_GNULIB_C32ISPUNCT)/g' \
3131 -e 's/@''GNULIB_C32ISSPACE''@/$(GL_GNULIB_C32ISSPACE)/g' \
3132 -e 's/@''GNULIB_C32ISUPPER''@/$(GL_GNULIB_C32ISUPPER)/g' \
3133 -e 's/@''GNULIB_C32ISXDIGIT''@/$(GL_GNULIB_C32ISXDIGIT)/g' \
3134 -e 's/@''GNULIB_C32TOLOWER''@/$(GL_GNULIB_C32TOLOWER)/g' \
3135 -e 's/@''GNULIB_C32TOUPPER''@/$(GL_GNULIB_C32TOUPPER)/g' \
3136 -e 's/@''GNULIB_C32WIDTH''@/$(GL_GNULIB_C32WIDTH)/g' \
3137 -e 's/@''GNULIB_C32RTOMB''@/$(GL_GNULIB_C32RTOMB)/g' \
3138 -e 's/@''GNULIB_C32SNRTOMBS''@/$(GL_GNULIB_C32SNRTOMBS)/g' \
3139 -e 's/@''GNULIB_C32SRTOMBS''@/$(GL_GNULIB_C32SRTOMBS)/g' \
3140 -e 's/@''GNULIB_C32STOMBS''@/$(GL_GNULIB_C32STOMBS)/g' \
3141 -e 's/@''GNULIB_C32SWIDTH''@/$(GL_GNULIB_C32SWIDTH)/g' \
3142 -e 's/@''GNULIB_C32TOB''@/$(GL_GNULIB_C32TOB)/g' \
3143 -e 's/@''GNULIB_C32_APPLY_MAPPING''@/$(GL_GNULIB_C32_APPLY_MAPPING)/g' \
3144 -e 's/@''GNULIB_C32_APPLY_TYPE_TEST''@/$(GL_GNULIB_C32_APPLY_TYPE_TEST)/g' \
3145 -e 's/@''GNULIB_C32_GET_MAPPING''@/$(GL_GNULIB_C32_GET_MAPPING)/g' \
3146 -e 's/@''GNULIB_C32_GET_TYPE_TEST''@/$(GL_GNULIB_C32_GET_TYPE_TEST)/g' \
3147 -e 's/@''GNULIB_ISWCTYPE''@/$(GL_GNULIB_ISWCTYPE)/g' \
3148 -e 's/@''GNULIB_ISWDIGIT''@/$(GL_GNULIB_ISWDIGIT)/g' \
3149 -e 's/@''GNULIB_ISWXDIGIT''@/$(GL_GNULIB_ISWXDIGIT)/g' \
3150 -e 's/@''GNULIB_MBRTOC16''@/$(GL_GNULIB_MBRTOC16)/g' \
3151 -e 's/@''GNULIB_MBRTOC32''@/$(GL_GNULIB_MBRTOC32)/g' \
3152 -e 's/@''GNULIB_MBSNRTOC32S''@/$(GL_GNULIB_MBSNRTOC32S)/g' \
3153 -e 's/@''GNULIB_MBSNRTOWCS''@/$(GL_GNULIB_MBSNRTOWCS)/g' \
3154 -e 's/@''GNULIB_MBSRTOC32S''@/$(GL_GNULIB_MBSRTOC32S)/g' \
3155 -e 's/@''GNULIB_MBSRTOWCS''@/$(GL_GNULIB_MBSRTOWCS)/g' \
3156 -e 's/@''GNULIB_MBSTOC32S''@/$(GL_GNULIB_MBSTOC32S)/g' \
3157 -e 's/@''GNULIB_TOWCTRANS''@/$(GL_GNULIB_TOWCTRANS)/g' \
3158 -e 's/@''GNULIB_WCSNRTOMBS''@/$(GL_GNULIB_WCSNRTOMBS)/g' \
3159 -e 's/@''GNULIB_WCSRTOMBS''@/$(GL_GNULIB_WCSRTOMBS)/g' \
3160 -e 's/@''GNULIB_WCSWIDTH''@/$(GL_GNULIB_WCSWIDTH)/g' \
3161 -e 's/@''GNULIB_WCTOB''@/$(GL_GNULIB_WCTOB)/g' \
3162 -e 's/@''GNULIB_WCTRANS''@/$(GL_GNULIB_WCTRANS)/g' \
3163 -e 's/@''GNULIB_WCTYPE''@/$(GL_GNULIB_WCTYPE)/g' \
3164 -e 's/@''GNULIB_WCWIDTH''@/$(GL_GNULIB_WCWIDTH)/g' \
3165 -e 's|@''HAVE_C32RTOMB''@|$(HAVE_C32RTOMB)|g' \
3166 -e 's|@''HAVE_MBRTOC16''@|$(HAVE_MBRTOC16)|g' \
3167 -e 's|@''HAVE_MBRTOC32''@|$(HAVE_MBRTOC32)|g' \
3168 -e 's|@''REPLACE_C32RTOMB''@|$(REPLACE_C32RTOMB)|g' \
3169 -e 's|@''REPLACE_MBRTOC16''@|$(REPLACE_MBRTOC16)|g' \
3170 -e 's|@''REPLACE_MBRTOC32''@|$(REPLACE_MBRTOC32)|g' \
3171 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
3172 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
3173 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
3174 $(srcdir)/uchar.in.h > $@-t
3175 $(AM_V_at)mv $@-t $@
3176MOSTLYCLEANFILES += uchar.h uchar.h-t
3177
3178EXTRA_DIST += uchar.in.h
3179
3180## end gnulib module uchar-h
3181
3182## begin gnulib module unicase/base
3183
3184BUILT_SOURCES += $(LIBUNISTRING_UNICASE_H)
3185
3186unicase.h: unicase.in.h
3187 $(gl_V_at)$(SED_HEADER_STDOUT) \
3188 -e 's|@''HAVE_UNISTRING_WOE32DLL_H''@|$(HAVE_UNISTRING_WOE32DLL_H)|g' \
3189 -e 's/@''GNULIB_UNICASE_EMPTY_PREFIX_CONTEXT_DLL_VARIABLE''@/$(GL_GNULIB_UNICASE_EMPTY_PREFIX_CONTEXT_DLL_VARIABLE)/g' \
3190 -e 's/@''GNULIB_UNICASE_EMPTY_SUFFIX_CONTEXT_DLL_VARIABLE''@/$(GL_GNULIB_UNICASE_EMPTY_SUFFIX_CONTEXT_DLL_VARIABLE)/g' \
3191 $(srcdir)/unicase.in.h > $@-t
3192 $(AM_V_at)mv $@-t $@
3193MOSTLYCLEANFILES += unicase.h unicase.h-t
3194
3195EXTRA_DIST += unicase.in.h
3196
3197## end gnulib module unicase/base
3198
3199## begin gnulib module unicase/tolower
3200
3201if LIBUNISTRING_COMPILE_UNICASE_TOLOWER
3202libgnu_a_SOURCES += unicase/tolower.c
3203endif
3204
3205EXTRA_DIST += unicase/simple-mapping.h unicase/tolower.h
3206
3207## end gnulib module unicase/tolower
3208
3209## begin gnulib module unictype/base
3210
3211BUILT_SOURCES += $(LIBUNISTRING_UNICTYPE_H)
3212
3213unictype.h: unictype.in.h
3214 $(gl_V_at)$(SED_HEADER_STDOUT) \
3215 -e 's|@''HAVE_UNISTRING_WOE32DLL_H''@|$(HAVE_UNISTRING_WOE32DLL_H)|g' \
3216 -e 's/@''GNULIB_UNICTYPE_CATEGORY_L_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_L_DLL_VARIABLE)/g' \
3217 -e 's/@''GNULIB_UNICTYPE_CATEGORY_LC_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_LC_DLL_VARIABLE)/g' \
3218 -e 's/@''GNULIB_UNICTYPE_CATEGORY_LU_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_LU_DLL_VARIABLE)/g' \
3219 -e 's/@''GNULIB_UNICTYPE_CATEGORY_LL_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_LL_DLL_VARIABLE)/g' \
3220 -e 's/@''GNULIB_UNICTYPE_CATEGORY_LT_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_LT_DLL_VARIABLE)/g' \
3221 -e 's/@''GNULIB_UNICTYPE_CATEGORY_LM_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_LM_DLL_VARIABLE)/g' \
3222 -e 's/@''GNULIB_UNICTYPE_CATEGORY_LO_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_LO_DLL_VARIABLE)/g' \
3223 -e 's/@''GNULIB_UNICTYPE_CATEGORY_M_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_M_DLL_VARIABLE)/g' \
3224 -e 's/@''GNULIB_UNICTYPE_CATEGORY_MN_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_MN_DLL_VARIABLE)/g' \
3225 -e 's/@''GNULIB_UNICTYPE_CATEGORY_MC_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_MC_DLL_VARIABLE)/g' \
3226 -e 's/@''GNULIB_UNICTYPE_CATEGORY_ME_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_ME_DLL_VARIABLE)/g' \
3227 -e 's/@''GNULIB_UNICTYPE_CATEGORY_N_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_N_DLL_VARIABLE)/g' \
3228 -e 's/@''GNULIB_UNICTYPE_CATEGORY_ND_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_ND_DLL_VARIABLE)/g' \
3229 -e 's/@''GNULIB_UNICTYPE_CATEGORY_NL_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_NL_DLL_VARIABLE)/g' \
3230 -e 's/@''GNULIB_UNICTYPE_CATEGORY_NO_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_NO_DLL_VARIABLE)/g' \
3231 -e 's/@''GNULIB_UNICTYPE_CATEGORY_P_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_P_DLL_VARIABLE)/g' \
3232 -e 's/@''GNULIB_UNICTYPE_CATEGORY_PC_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_PC_DLL_VARIABLE)/g' \
3233 -e 's/@''GNULIB_UNICTYPE_CATEGORY_PD_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_PD_DLL_VARIABLE)/g' \
3234 -e 's/@''GNULIB_UNICTYPE_CATEGORY_PS_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_PS_DLL_VARIABLE)/g' \
3235 -e 's/@''GNULIB_UNICTYPE_CATEGORY_PE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_PE_DLL_VARIABLE)/g' \
3236 -e 's/@''GNULIB_UNICTYPE_CATEGORY_PI_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_PI_DLL_VARIABLE)/g' \
3237 -e 's/@''GNULIB_UNICTYPE_CATEGORY_PF_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_PF_DLL_VARIABLE)/g' \
3238 -e 's/@''GNULIB_UNICTYPE_CATEGORY_PO_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_PO_DLL_VARIABLE)/g' \
3239 -e 's/@''GNULIB_UNICTYPE_CATEGORY_S_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_S_DLL_VARIABLE)/g' \
3240 -e 's/@''GNULIB_UNICTYPE_CATEGORY_SM_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_SM_DLL_VARIABLE)/g' \
3241 -e 's/@''GNULIB_UNICTYPE_CATEGORY_SC_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_SC_DLL_VARIABLE)/g' \
3242 -e 's/@''GNULIB_UNICTYPE_CATEGORY_SK_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_SK_DLL_VARIABLE)/g' \
3243 -e 's/@''GNULIB_UNICTYPE_CATEGORY_SO_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_SO_DLL_VARIABLE)/g' \
3244 -e 's/@''GNULIB_UNICTYPE_CATEGORY_Z_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_Z_DLL_VARIABLE)/g' \
3245 -e 's/@''GNULIB_UNICTYPE_CATEGORY_ZS_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_ZS_DLL_VARIABLE)/g' \
3246 -e 's/@''GNULIB_UNICTYPE_CATEGORY_ZL_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_ZL_DLL_VARIABLE)/g' \
3247 -e 's/@''GNULIB_UNICTYPE_CATEGORY_ZP_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_ZP_DLL_VARIABLE)/g' \
3248 -e 's/@''GNULIB_UNICTYPE_CATEGORY_C_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_C_DLL_VARIABLE)/g' \
3249 -e 's/@''GNULIB_UNICTYPE_CATEGORY_CC_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_CC_DLL_VARIABLE)/g' \
3250 -e 's/@''GNULIB_UNICTYPE_CATEGORY_CF_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_CF_DLL_VARIABLE)/g' \
3251 -e 's/@''GNULIB_UNICTYPE_CATEGORY_CS_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_CS_DLL_VARIABLE)/g' \
3252 -e 's/@''GNULIB_UNICTYPE_CATEGORY_CO_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_CO_DLL_VARIABLE)/g' \
3253 -e 's/@''GNULIB_UNICTYPE_CATEGORY_CN_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_CATEGORY_CN_DLL_VARIABLE)/g' \
3254 < $(srcdir)/unictype.in.h > $@-t1
3255 $(AM_V_at)sed \
3256 -e 's/@''GNULIB_UNICTYPE_PROPERTY_WHITE_SPACE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_WHITE_SPACE_DLL_VARIABLE)/g' \
3257 -e 's/@''GNULIB_UNICTYPE_PROPERTY_ALPHABETIC_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_ALPHABETIC_DLL_VARIABLE)/g' \
3258 -e 's/@''GNULIB_UNICTYPE_PROPERTY_OTHER_ALPHABETIC_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_OTHER_ALPHABETIC_DLL_VARIABLE)/g' \
3259 -e 's/@''GNULIB_UNICTYPE_PROPERTY_NOT_A_CHARACTER_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_NOT_A_CHARACTER_DLL_VARIABLE)/g' \
3260 -e 's/@''GNULIB_UNICTYPE_PROPERTY_DEFAULT_IGNORABLE_CODE_POINT_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_DEFAULT_IGNORABLE_CODE_POINT_DLL_VARIABLE)/g' \
3261 -e 's/@''GNULIB_UNICTYPE_PROPERTY_OTHER_DEFAULT_IGNORABLE_CODE_POINT_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_OTHER_DEFAULT_IGNORABLE_CODE_POINT_DLL_VARIABLE)/g' \
3262 -e 's/@''GNULIB_UNICTYPE_PROPERTY_DEPRECATED_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_DEPRECATED_DLL_VARIABLE)/g' \
3263 -e 's/@''GNULIB_UNICTYPE_PROPERTY_LOGICAL_ORDER_EXCEPTION_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_LOGICAL_ORDER_EXCEPTION_DLL_VARIABLE)/g' \
3264 -e 's/@''GNULIB_UNICTYPE_PROPERTY_VARIATION_SELECTOR_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_VARIATION_SELECTOR_DLL_VARIABLE)/g' \
3265 -e 's/@''GNULIB_UNICTYPE_PROPERTY_PRIVATE_USE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_PRIVATE_USE_DLL_VARIABLE)/g' \
3266 -e 's/@''GNULIB_UNICTYPE_PROPERTY_UNASSIGNED_CODE_VALUE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_UNASSIGNED_CODE_VALUE_DLL_VARIABLE)/g' \
3267 -e 's/@''GNULIB_UNICTYPE_PROPERTY_UPPERCASE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_UPPERCASE_DLL_VARIABLE)/g' \
3268 -e 's/@''GNULIB_UNICTYPE_PROPERTY_OTHER_UPPERCASE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_OTHER_UPPERCASE_DLL_VARIABLE)/g' \
3269 -e 's/@''GNULIB_UNICTYPE_PROPERTY_LOWERCASE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_LOWERCASE_DLL_VARIABLE)/g' \
3270 -e 's/@''GNULIB_UNICTYPE_PROPERTY_OTHER_LOWERCASE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_OTHER_LOWERCASE_DLL_VARIABLE)/g' \
3271 -e 's/@''GNULIB_UNICTYPE_PROPERTY_TITLECASE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_TITLECASE_DLL_VARIABLE)/g' \
3272 -e 's/@''GNULIB_UNICTYPE_PROPERTY_CASED_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_CASED_DLL_VARIABLE)/g' \
3273 -e 's/@''GNULIB_UNICTYPE_PROPERTY_CASE_IGNORABLE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_CASE_IGNORABLE_DLL_VARIABLE)/g' \
3274 -e 's/@''GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_LOWERCASED_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_LOWERCASED_DLL_VARIABLE)/g' \
3275 -e 's/@''GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_UPPERCASED_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_UPPERCASED_DLL_VARIABLE)/g' \
3276 -e 's/@''GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_TITLECASED_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_TITLECASED_DLL_VARIABLE)/g' \
3277 -e 's/@''GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_CASEFOLDED_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_CASEFOLDED_DLL_VARIABLE)/g' \
3278 -e 's/@''GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_CASEMAPPED_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_CASEMAPPED_DLL_VARIABLE)/g' \
3279 -e 's/@''GNULIB_UNICTYPE_PROPERTY_SOFT_DOTTED_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_SOFT_DOTTED_DLL_VARIABLE)/g' \
3280 < $@-t1 > $@-t2
3281 $(AM_V_at)sed \
3282 -e 's/@''GNULIB_UNICTYPE_PROPERTY_ID_START_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_ID_START_DLL_VARIABLE)/g' \
3283 -e 's/@''GNULIB_UNICTYPE_PROPERTY_OTHER_ID_START_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_OTHER_ID_START_DLL_VARIABLE)/g' \
3284 -e 's/@''GNULIB_UNICTYPE_PROPERTY_ID_CONTINUE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_ID_CONTINUE_DLL_VARIABLE)/g' \
3285 -e 's/@''GNULIB_UNICTYPE_PROPERTY_OTHER_ID_CONTINUE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_OTHER_ID_CONTINUE_DLL_VARIABLE)/g' \
3286 -e 's/@''GNULIB_UNICTYPE_PROPERTY_XID_START_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_XID_START_DLL_VARIABLE)/g' \
3287 -e 's/@''GNULIB_UNICTYPE_PROPERTY_XID_CONTINUE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_XID_CONTINUE_DLL_VARIABLE)/g' \
3288 -e 's/@''GNULIB_UNICTYPE_PROPERTY_ID_COMPAT_MATH_START_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_ID_COMPAT_MATH_START_DLL_VARIABLE)/g' \
3289 -e 's/@''GNULIB_UNICTYPE_PROPERTY_ID_COMPAT_MATH_CONTINUE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_ID_COMPAT_MATH_CONTINUE_DLL_VARIABLE)/g' \
3290 -e 's/@''GNULIB_UNICTYPE_PROPERTY_PATTERN_WHITE_SPACE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_PATTERN_WHITE_SPACE_DLL_VARIABLE)/g' \
3291 -e 's/@''GNULIB_UNICTYPE_PROPERTY_PATTERN_SYNTAX_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_PATTERN_SYNTAX_DLL_VARIABLE)/g' \
3292 -e 's/@''GNULIB_UNICTYPE_PROPERTY_JOIN_CONTROL_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_JOIN_CONTROL_DLL_VARIABLE)/g' \
3293 -e 's/@''GNULIB_UNICTYPE_PROPERTY_GRAPHEME_BASE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_GRAPHEME_BASE_DLL_VARIABLE)/g' \
3294 -e 's/@''GNULIB_UNICTYPE_PROPERTY_GRAPHEME_EXTEND_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_GRAPHEME_EXTEND_DLL_VARIABLE)/g' \
3295 -e 's/@''GNULIB_UNICTYPE_PROPERTY_OTHER_GRAPHEME_EXTEND_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_OTHER_GRAPHEME_EXTEND_DLL_VARIABLE)/g' \
3296 -e 's/@''GNULIB_UNICTYPE_PROPERTY_GRAPHEME_LINK_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_GRAPHEME_LINK_DLL_VARIABLE)/g' \
3297 -e 's/@''GNULIB_UNICTYPE_PROPERTY_MODIFIER_COMBINING_MARK_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_MODIFIER_COMBINING_MARK_DLL_VARIABLE)/g' \
3298 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_CONTROL_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_CONTROL_DLL_VARIABLE)/g' \
3299 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_LEFT_TO_RIGHT_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_LEFT_TO_RIGHT_DLL_VARIABLE)/g' \
3300 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_HEBREW_RIGHT_TO_LEFT_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_HEBREW_RIGHT_TO_LEFT_DLL_VARIABLE)/g' \
3301 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_ARABIC_RIGHT_TO_LEFT_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_ARABIC_RIGHT_TO_LEFT_DLL_VARIABLE)/g' \
3302 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_EUROPEAN_DIGIT_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_EUROPEAN_DIGIT_DLL_VARIABLE)/g' \
3303 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_EUR_NUM_SEPARATOR_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_EUR_NUM_SEPARATOR_DLL_VARIABLE)/g' \
3304 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_EUR_NUM_TERMINATOR_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_EUR_NUM_TERMINATOR_DLL_VARIABLE)/g' \
3305 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_ARABIC_DIGIT_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_ARABIC_DIGIT_DLL_VARIABLE)/g' \
3306 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_COMMON_SEPARATOR_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_COMMON_SEPARATOR_DLL_VARIABLE)/g' \
3307 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_BLOCK_SEPARATOR_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_BLOCK_SEPARATOR_DLL_VARIABLE)/g' \
3308 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_SEGMENT_SEPARATOR_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_SEGMENT_SEPARATOR_DLL_VARIABLE)/g' \
3309 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_WHITESPACE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_WHITESPACE_DLL_VARIABLE)/g' \
3310 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_NON_SPACING_MARK_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_NON_SPACING_MARK_DLL_VARIABLE)/g' \
3311 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_BOUNDARY_NEUTRAL_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_BOUNDARY_NEUTRAL_DLL_VARIABLE)/g' \
3312 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_PDF_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_PDF_DLL_VARIABLE)/g' \
3313 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_EMBEDDING_OR_OVERRIDE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_EMBEDDING_OR_OVERRIDE_DLL_VARIABLE)/g' \
3314 -e 's/@''GNULIB_UNICTYPE_PROPERTY_BIDI_OTHER_NEUTRAL_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_BIDI_OTHER_NEUTRAL_DLL_VARIABLE)/g' \
3315 < $@-t2 > $@-t3
3316 $(AM_V_at)sed \
3317 -e 's/@''GNULIB_UNICTYPE_PROPERTY_HEX_DIGIT_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_HEX_DIGIT_DLL_VARIABLE)/g' \
3318 -e 's/@''GNULIB_UNICTYPE_PROPERTY_ASCII_HEX_DIGIT_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_ASCII_HEX_DIGIT_DLL_VARIABLE)/g' \
3319 -e 's/@''GNULIB_UNICTYPE_PROPERTY_IDEOGRAPHIC_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_IDEOGRAPHIC_DLL_VARIABLE)/g' \
3320 -e 's/@''GNULIB_UNICTYPE_PROPERTY_UNIFIED_IDEOGRAPH_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_UNIFIED_IDEOGRAPH_DLL_VARIABLE)/g' \
3321 -e 's/@''GNULIB_UNICTYPE_PROPERTY_RADICAL_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_RADICAL_DLL_VARIABLE)/g' \
3322 -e 's/@''GNULIB_UNICTYPE_PROPERTY_IDS_UNARY_OPERATOR_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_IDS_UNARY_OPERATOR_DLL_VARIABLE)/g' \
3323 -e 's/@''GNULIB_UNICTYPE_PROPERTY_IDS_BINARY_OPERATOR_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_IDS_BINARY_OPERATOR_DLL_VARIABLE)/g' \
3324 -e 's/@''GNULIB_UNICTYPE_PROPERTY_IDS_TRINARY_OPERATOR_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_IDS_TRINARY_OPERATOR_DLL_VARIABLE)/g' \
3325 -e 's/@''GNULIB_UNICTYPE_PROPERTY_EMOJI_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_EMOJI_DLL_VARIABLE)/g' \
3326 -e 's/@''GNULIB_UNICTYPE_PROPERTY_EMOJI_PRESENTATION_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_EMOJI_PRESENTATION_DLL_VARIABLE)/g' \
3327 -e 's/@''GNULIB_UNICTYPE_PROPERTY_EMOJI_MODIFIER_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_EMOJI_MODIFIER_DLL_VARIABLE)/g' \
3328 -e 's/@''GNULIB_UNICTYPE_PROPERTY_EMOJI_MODIFIER_BASE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_EMOJI_MODIFIER_BASE_DLL_VARIABLE)/g' \
3329 -e 's/@''GNULIB_UNICTYPE_PROPERTY_EMOJI_COMPONENT_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_EMOJI_COMPONENT_DLL_VARIABLE)/g' \
3330 -e 's/@''GNULIB_UNICTYPE_PROPERTY_EXTENDED_PICTOGRAPHIC_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_EXTENDED_PICTOGRAPHIC_DLL_VARIABLE)/g' \
3331 -e 's/@''GNULIB_UNICTYPE_PROPERTY_ZERO_WIDTH_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_ZERO_WIDTH_DLL_VARIABLE)/g' \
3332 -e 's/@''GNULIB_UNICTYPE_PROPERTY_SPACE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_SPACE_DLL_VARIABLE)/g' \
3333 -e 's/@''GNULIB_UNICTYPE_PROPERTY_NON_BREAK_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_NON_BREAK_DLL_VARIABLE)/g' \
3334 -e 's/@''GNULIB_UNICTYPE_PROPERTY_ISO_CONTROL_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_ISO_CONTROL_DLL_VARIABLE)/g' \
3335 -e 's/@''GNULIB_UNICTYPE_PROPERTY_FORMAT_CONTROL_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_FORMAT_CONTROL_DLL_VARIABLE)/g' \
3336 -e 's/@''GNULIB_UNICTYPE_PROPERTY_PREPENDED_CONCATENATION_MARK_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_PREPENDED_CONCATENATION_MARK_DLL_VARIABLE)/g' \
3337 -e 's/@''GNULIB_UNICTYPE_PROPERTY_DASH_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_DASH_DLL_VARIABLE)/g' \
3338 -e 's/@''GNULIB_UNICTYPE_PROPERTY_HYPHEN_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_HYPHEN_DLL_VARIABLE)/g' \
3339 -e 's/@''GNULIB_UNICTYPE_PROPERTY_PUNCTUATION_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_PUNCTUATION_DLL_VARIABLE)/g' \
3340 -e 's/@''GNULIB_UNICTYPE_PROPERTY_LINE_SEPARATOR_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_LINE_SEPARATOR_DLL_VARIABLE)/g' \
3341 -e 's/@''GNULIB_UNICTYPE_PROPERTY_PARAGRAPH_SEPARATOR_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_PARAGRAPH_SEPARATOR_DLL_VARIABLE)/g' \
3342 -e 's/@''GNULIB_UNICTYPE_PROPERTY_QUOTATION_MARK_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_QUOTATION_MARK_DLL_VARIABLE)/g' \
3343 -e 's/@''GNULIB_UNICTYPE_PROPERTY_SENTENCE_TERMINAL_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_SENTENCE_TERMINAL_DLL_VARIABLE)/g' \
3344 -e 's/@''GNULIB_UNICTYPE_PROPERTY_TERMINAL_PUNCTUATION_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_TERMINAL_PUNCTUATION_DLL_VARIABLE)/g' \
3345 -e 's/@''GNULIB_UNICTYPE_PROPERTY_CURRENCY_SYMBOL_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_CURRENCY_SYMBOL_DLL_VARIABLE)/g' \
3346 -e 's/@''GNULIB_UNICTYPE_PROPERTY_MATH_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_MATH_DLL_VARIABLE)/g' \
3347 -e 's/@''GNULIB_UNICTYPE_PROPERTY_OTHER_MATH_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_OTHER_MATH_DLL_VARIABLE)/g' \
3348 -e 's/@''GNULIB_UNICTYPE_PROPERTY_PAIRED_PUNCTUATION_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_PAIRED_PUNCTUATION_DLL_VARIABLE)/g' \
3349 -e 's/@''GNULIB_UNICTYPE_PROPERTY_LEFT_OF_PAIR_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_LEFT_OF_PAIR_DLL_VARIABLE)/g' \
3350 -e 's/@''GNULIB_UNICTYPE_PROPERTY_COMBINING_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_COMBINING_DLL_VARIABLE)/g' \
3351 -e 's/@''GNULIB_UNICTYPE_PROPERTY_COMPOSITE_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_COMPOSITE_DLL_VARIABLE)/g' \
3352 -e 's/@''GNULIB_UNICTYPE_PROPERTY_DECIMAL_DIGIT_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_DECIMAL_DIGIT_DLL_VARIABLE)/g' \
3353 -e 's/@''GNULIB_UNICTYPE_PROPERTY_NUMERIC_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_NUMERIC_DLL_VARIABLE)/g' \
3354 -e 's/@''GNULIB_UNICTYPE_PROPERTY_DIACRITIC_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_DIACRITIC_DLL_VARIABLE)/g' \
3355 -e 's/@''GNULIB_UNICTYPE_PROPERTY_EXTENDER_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_EXTENDER_DLL_VARIABLE)/g' \
3356 -e 's/@''GNULIB_UNICTYPE_PROPERTY_IGNORABLE_CONTROL_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_IGNORABLE_CONTROL_DLL_VARIABLE)/g' \
3357 -e 's/@''GNULIB_UNICTYPE_PROPERTY_REGIONAL_INDICATOR_DLL_VARIABLE''@/$(GL_GNULIB_UNICTYPE_PROPERTY_REGIONAL_INDICATOR_DLL_VARIABLE)/g' \
3358 < $@-t3 > $@-t4
3359 $(AM_V_at)rm -f $@-t1 $@-t2 $@-t3
3360 $(AM_V_at)mv $@-t4 $@
3361MOSTLYCLEANFILES += unictype.h unictype.h-t1 unictype.h-t2 unictype.h-t3 unictype.h-t4
3362
3363EXTRA_DIST += unictype.in.h
3364
3365## end gnulib module unictype/base
3366
3367## begin gnulib module unictype/ctype-alnum
3368
3369if LIBUNISTRING_COMPILE_UNICTYPE_CTYPE_ALNUM
3370libgnu_a_SOURCES += unictype/ctype_alnum.c
3371endif
3372
3373EXTRA_DIST += unictype/bitmap.h unictype/ctype_alnum.h
3374
3375## end gnulib module unictype/ctype-alnum
3376
3377## begin gnulib module unictype/ctype-alpha
3378
3379if LIBUNISTRING_COMPILE_UNICTYPE_CTYPE_ALPHA
3380libgnu_a_SOURCES += unictype/ctype_alpha.c
3381endif
3382
3383EXTRA_DIST += unictype/bitmap.h unictype/ctype_alpha.h
3384
3385## end gnulib module unictype/ctype-alpha
3386
3387## begin gnulib module unictype/ctype-blank
3388
3389if LIBUNISTRING_COMPILE_UNICTYPE_CTYPE_BLANK
3390libgnu_a_SOURCES += unictype/ctype_blank.c
3391endif
3392
3393EXTRA_DIST += unictype/bitmap.h unictype/ctype_blank.h
3394
3395## end gnulib module unictype/ctype-blank
3396
3397## begin gnulib module unictype/ctype-cntrl
3398
3399if LIBUNISTRING_COMPILE_UNICTYPE_CTYPE_CNTRL
3400libgnu_a_SOURCES += unictype/ctype_cntrl.c
3401endif
3402
3403EXTRA_DIST += unictype/bitmap.h unictype/ctype_cntrl.h
3404
3405## end gnulib module unictype/ctype-cntrl
3406
3407## begin gnulib module unictype/ctype-digit
3408
3409if LIBUNISTRING_COMPILE_UNICTYPE_CTYPE_DIGIT
3410libgnu_a_SOURCES += unictype/ctype_digit.c
3411endif
3412
3413EXTRA_DIST += unictype/bitmap.h unictype/ctype_digit.h
3414
3415## end gnulib module unictype/ctype-digit
3416
3417## begin gnulib module unictype/ctype-graph
3418
3419if LIBUNISTRING_COMPILE_UNICTYPE_CTYPE_GRAPH
3420libgnu_a_SOURCES += unictype/ctype_graph.c
3421endif
3422
3423EXTRA_DIST += unictype/bitmap.h unictype/ctype_graph.h
3424
3425## end gnulib module unictype/ctype-graph
3426
3427## begin gnulib module unictype/ctype-lower
3428
3429if LIBUNISTRING_COMPILE_UNICTYPE_CTYPE_LOWER
3430libgnu_a_SOURCES += unictype/ctype_lower.c
3431endif
3432
3433EXTRA_DIST += unictype/bitmap.h unictype/ctype_lower.h
3434
3435## end gnulib module unictype/ctype-lower
3436
3437## begin gnulib module unictype/ctype-print
3438
3439if LIBUNISTRING_COMPILE_UNICTYPE_CTYPE_PRINT
3440libgnu_a_SOURCES += unictype/ctype_print.c
3441endif
3442
3443EXTRA_DIST += unictype/bitmap.h unictype/ctype_print.h
3444
3445## end gnulib module unictype/ctype-print
3446
3447## begin gnulib module unictype/ctype-punct
3448
3449if LIBUNISTRING_COMPILE_UNICTYPE_CTYPE_PUNCT
3450libgnu_a_SOURCES += unictype/ctype_punct.c
3451endif
3452
3453EXTRA_DIST += unictype/bitmap.h unictype/ctype_punct.h
3454
3455## end gnulib module unictype/ctype-punct
3456
3457## begin gnulib module unictype/ctype-space
3458
3459if LIBUNISTRING_COMPILE_UNICTYPE_CTYPE_SPACE
3460libgnu_a_SOURCES += unictype/ctype_space.c
3461endif
3462
3463EXTRA_DIST += unictype/bitmap.h unictype/ctype_space.h
3464
3465## end gnulib module unictype/ctype-space
3466
3467## begin gnulib module unictype/ctype-upper
3468
3469if LIBUNISTRING_COMPILE_UNICTYPE_CTYPE_UPPER
3470libgnu_a_SOURCES += unictype/ctype_upper.c
3471endif
3472
3473EXTRA_DIST += unictype/bitmap.h unictype/ctype_upper.h
3474
3475## end gnulib module unictype/ctype-upper
3476
3477## begin gnulib module unictype/ctype-xdigit
3478
3479if LIBUNISTRING_COMPILE_UNICTYPE_CTYPE_XDIGIT
3480libgnu_a_SOURCES += unictype/ctype_xdigit.c
3481endif
3482
3483EXTRA_DIST += unictype/bitmap.h unictype/ctype_xdigit.h
3484
3485## end gnulib module unictype/ctype-xdigit
3486
3487## begin gnulib module uninorm/base
3488
3489BUILT_SOURCES += $(LIBUNISTRING_UNINORM_H)
3490
3491uninorm.h: uninorm.in.h
3492 $(gl_V_at)$(SED_HEADER_STDOUT) \
3493 -e 's|@''HAVE_UNISTRING_WOE32DLL_H''@|$(HAVE_UNISTRING_WOE32DLL_H)|g' \
3494 -e 's/@''GNULIB_UNINORM_NFD_DLL_VARIABLE''@/$(GL_GNULIB_UNINORM_NFD_DLL_VARIABLE)/g' \
3495 -e 's/@''GNULIB_UNINORM_NFC_DLL_VARIABLE''@/$(GL_GNULIB_UNINORM_NFC_DLL_VARIABLE)/g' \
3496 -e 's/@''GNULIB_UNINORM_NFKD_DLL_VARIABLE''@/$(GL_GNULIB_UNINORM_NFKD_DLL_VARIABLE)/g' \
3497 -e 's/@''GNULIB_UNINORM_NFKC_DLL_VARIABLE''@/$(GL_GNULIB_UNINORM_NFKC_DLL_VARIABLE)/g' \
3498 $(srcdir)/uninorm.in.h > $@-t
3499 $(AM_V_at)mv $@-t $@
3500MOSTLYCLEANFILES += uninorm.h uninorm.h-t
3501
3502EXTRA_DIST += uninorm.in.h
3503
3504## end gnulib module uninorm/base
3505
3506## begin gnulib module unistd-h
2658 3507
2659BUILT_SOURCES += unistd.h 3508BUILT_SOURCES += unistd.h
2660libgnu_a_SOURCES += unistd.c 3509libgnu_a_SOURCES += unistd.c
@@ -2830,11 +3679,13 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2830 -e 's|@''REPLACE_GETDOMAINNAME''@|$(REPLACE_GETDOMAINNAME)|g' \ 3679 -e 's|@''REPLACE_GETDOMAINNAME''@|$(REPLACE_GETDOMAINNAME)|g' \
2831 -e 's|@''REPLACE_GETDTABLESIZE''@|$(REPLACE_GETDTABLESIZE)|g' \ 3680 -e 's|@''REPLACE_GETDTABLESIZE''@|$(REPLACE_GETDTABLESIZE)|g' \
2832 -e 's|@''REPLACE_GETENTROPY''@|$(REPLACE_GETENTROPY)|g' \ 3681 -e 's|@''REPLACE_GETENTROPY''@|$(REPLACE_GETENTROPY)|g' \
3682 -e 's|@''REPLACE_GETLOGIN''@|$(REPLACE_GETLOGIN)|g' \
2833 -e 's|@''REPLACE_GETLOGIN_R''@|$(REPLACE_GETLOGIN_R)|g' \ 3683 -e 's|@''REPLACE_GETLOGIN_R''@|$(REPLACE_GETLOGIN_R)|g' \
2834 -e 's|@''REPLACE_GETGROUPS''@|$(REPLACE_GETGROUPS)|g' \ 3684 -e 's|@''REPLACE_GETGROUPS''@|$(REPLACE_GETGROUPS)|g' \
2835 -e 's|@''REPLACE_GETPAGESIZE''@|$(REPLACE_GETPAGESIZE)|g' \ 3685 -e 's|@''REPLACE_GETPAGESIZE''@|$(REPLACE_GETPAGESIZE)|g' \
2836 -e 's|@''REPLACE_GETPASS''@|$(REPLACE_GETPASS)|g' \ 3686 -e 's|@''REPLACE_GETPASS''@|$(REPLACE_GETPASS)|g' \
2837 -e 's|@''REPLACE_GETPASS_FOR_GETPASS_GNU''@|$(REPLACE_GETPASS_FOR_GETPASS_GNU)|g' \ 3687 -e 's|@''REPLACE_GETPASS_FOR_GETPASS_GNU''@|$(REPLACE_GETPASS_FOR_GETPASS_GNU)|g' \
3688 -e 's|@''REPLACE_GETUSERSHELL''@|$(REPLACE_GETUSERSHELL)|g' \
2838 -e 's|@''REPLACE_ISATTY''@|$(REPLACE_ISATTY)|g' \ 3689 -e 's|@''REPLACE_ISATTY''@|$(REPLACE_ISATTY)|g' \
2839 -e 's|@''REPLACE_LCHOWN''@|$(REPLACE_LCHOWN)|g' \ 3690 -e 's|@''REPLACE_LCHOWN''@|$(REPLACE_LCHOWN)|g' \
2840 -e 's|@''REPLACE_LINK''@|$(REPLACE_LINK)|g' \ 3691 -e 's|@''REPLACE_LINK''@|$(REPLACE_LINK)|g' \
@@ -2870,7 +3721,43 @@ MOSTLYCLEANFILES += unistd.h unistd.h-t1 unistd.h-t2 unistd.h-t3 unistd.h-t4
2870 3721
2871EXTRA_DIST += unistd.in.h 3722EXTRA_DIST += unistd.in.h
2872 3723
2873## end gnulib module unistd 3724## end gnulib module unistd-h
3725
3726## begin gnulib module unitypes-h
3727
3728BUILT_SOURCES += $(LIBUNISTRING_UNITYPES_H)
3729
3730unitypes.h: unitypes.in.h
3731 $(gl_V_at)$(SED_HEADER_TO_AT_t) $(srcdir)/unitypes.in.h
3732 $(AM_V_at)mv $@-t $@
3733MOSTLYCLEANFILES += unitypes.h unitypes.h-t
3734
3735EXTRA_DIST += unitypes.in.h
3736
3737## end gnulib module unitypes-h
3738
3739## begin gnulib module uniwidth/base
3740
3741BUILT_SOURCES += $(LIBUNISTRING_UNIWIDTH_H)
3742
3743uniwidth.h: uniwidth.in.h
3744 $(gl_V_at)$(SED_HEADER_TO_AT_t) $(srcdir)/uniwidth.in.h
3745 $(AM_V_at)mv $@-t $@
3746MOSTLYCLEANFILES += uniwidth.h uniwidth.h-t
3747
3748EXTRA_DIST += localcharset.h uniwidth.in.h
3749
3750## end gnulib module uniwidth/base
3751
3752## begin gnulib module uniwidth/width
3753
3754if LIBUNISTRING_COMPILE_UNIWIDTH_WIDTH
3755libgnu_a_SOURCES += uniwidth/width.c
3756endif
3757
3758EXTRA_DIST += unictype/bitmap.h uniwidth/cjk.h uniwidth/width0.h uniwidth/width2.h
3759
3760## end gnulib module uniwidth/width
2874 3761
2875## begin gnulib module unlocked-io-internal 3762## begin gnulib module unlocked-io-internal
2876 3763
@@ -2921,7 +3808,13 @@ EXTRA_libgnu_a_SOURCES += vsnprintf.c
2921 3808
2922## end gnulib module vsnprintf 3809## end gnulib module vsnprintf
2923 3810
2924## begin gnulib module wchar 3811## begin gnulib module vsnzprintf
3812
3813libgnu_a_SOURCES += vsnzprintf.c
3814
3815## end gnulib module vsnzprintf
3816
3817## begin gnulib module wchar-h
2925 3818
2926BUILT_SOURCES += wchar.h 3819BUILT_SOURCES += wchar.h
2927 3820
@@ -3046,6 +3939,7 @@ wchar.h: wchar.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
3046 -e 's|@''REPLACE_WCSWIDTH''@|$(REPLACE_WCSWIDTH)|g' \ 3939 -e 's|@''REPLACE_WCSWIDTH''@|$(REPLACE_WCSWIDTH)|g' \
3047 -e 's|@''REPLACE_WCSFTIME''@|$(REPLACE_WCSFTIME)|g' \ 3940 -e 's|@''REPLACE_WCSFTIME''@|$(REPLACE_WCSFTIME)|g' \
3048 -e 's|@''REPLACE_WCSCMP''@|$(REPLACE_WCSCMP)|g' \ 3941 -e 's|@''REPLACE_WCSCMP''@|$(REPLACE_WCSCMP)|g' \
3942 -e 's|@''REPLACE_WCSNCAT''@|$(REPLACE_WCSNCAT)|g' \
3049 -e 's|@''REPLACE_WCSNCMP''@|$(REPLACE_WCSNCMP)|g' \ 3943 -e 's|@''REPLACE_WCSNCMP''@|$(REPLACE_WCSNCMP)|g' \
3050 -e 's|@''REPLACE_WCSSTR''@|$(REPLACE_WCSSTR)|g' \ 3944 -e 's|@''REPLACE_WCSSTR''@|$(REPLACE_WCSSTR)|g' \
3051 -e 's|@''REPLACE_WCSTOK''@|$(REPLACE_WCSTOK)|g' \ 3945 -e 's|@''REPLACE_WCSTOK''@|$(REPLACE_WCSTOK)|g' \
@@ -3061,7 +3955,7 @@ MOSTLYCLEANFILES += wchar.h wchar.h-t1 wchar.h-t2 wchar.h-t3
3061 3955
3062EXTRA_DIST += wchar.in.h 3956EXTRA_DIST += wchar.in.h
3063 3957
3064## end gnulib module wchar 3958## end gnulib module wchar-h
3065 3959
3066## begin gnulib module wcrtomb 3960## begin gnulib module wcrtomb
3067 3961
@@ -3130,6 +4024,14 @@ EXTRA_DIST += wctype.in.h
3130 4024
3131## end gnulib module wctype-h 4025## end gnulib module wctype-h
3132 4026
4027## begin gnulib module wcwidth
4028
4029if GL_COND_OBJ_WCWIDTH
4030libgnu_a_SOURCES += wcwidth.c
4031endif
4032
4033## end gnulib module wcwidth
4034
3133## begin gnulib module windows-mutex 4035## begin gnulib module windows-mutex
3134 4036
3135if GL_COND_OBJ_WINDOWS_MUTEX 4037if GL_COND_OBJ_WINDOWS_MUTEX
@@ -3209,5 +4111,5 @@ mostlyclean-local: mostlyclean-generic
3209 : 4111 :
3210distclean-local: distclean-gnulib-libobjs 4112distclean-local: distclean-gnulib-libobjs
3211distclean-gnulib-libobjs: 4113distclean-gnulib-libobjs:
3212 -rm -f @gl_LIBOBJDEPS@ 4114 -rm -f @gl_libgnu_LIBOBJDEPS@
3213maintainer-clean-local: distclean-gnulib-libobjs 4115maintainer-clean-local: distclean-gnulib-libobjs
diff --git a/gl/_Noreturn.h b/gl/_Noreturn.h
index 7326bd47..d42f15ee 100644
--- a/gl/_Noreturn.h
+++ b/gl/_Noreturn.h
@@ -1,5 +1,5 @@
1/* A C macro for declaring that a function does not return. 1/* A C macro for declaring that a function does not return.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 2 Copyright (C) 2011-2025 Free Software Foundation, Inc.
3 3
4 This program is free software: you can redistribute it and/or modify it 4 This program is free software: you can redistribute it and/or modify it
5 under the terms of the GNU Lesser General Public License as published 5 under the terms of the GNU Lesser General Public License as published
@@ -14,33 +14,26 @@
14 You should have received a copy of the GNU Lesser General Public License 14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16 16
17/* The _Noreturn keyword of C11.
18 Do not use [[noreturn]], because with it the syntax
19 extern _Noreturn void func (...);
20 would not be valid; such a declaration would be valid only with 'extern'
21 and '_Noreturn' swapped, or without the 'extern' keyword. However, some
22 AIX system header files and several gnulib header files use precisely
23 this syntax with 'extern'. So even though C23 deprecates _Noreturn,
24 it is currently more portable to prefer it to [[noreturn]].
25
26 Also, do not try to work around LLVM bug 59792 (clang 15 or earlier).
27 This rare bug can be worked around by compiling with 'clang -D_Noreturn=',
28 though the workaround may generate many false-alarm warnings. */
17#ifndef _Noreturn 29#ifndef _Noreturn
18# if (defined __cplusplus \ 30# if ((!defined __cplusplus || defined __clang__) \
19 && ((201103 <= __cplusplus && !(__GNUC__ == 4 && __GNUC_MINOR__ == 7)) \ 31 && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0)))
20 || (defined _MSC_VER && 1900 <= _MSC_VER)) \
21 && 0)
22 /* [[noreturn]] is not practically usable, because with it the syntax
23 extern _Noreturn void func (...);
24 would not be valid; such a declaration would only be valid with 'extern'
25 and '_Noreturn' swapped, or without the 'extern' keyword. However, some
26 AIX system header files and several gnulib header files use precisely
27 this syntax with 'extern'. */
28# define _Noreturn [[noreturn]]
29# elif (defined __clang__ && __clang_major__ < 16 \
30 && defined _GL_WORK_AROUND_LLVM_BUG_59792)
31 /* Compile with -D_GL_WORK_AROUND_LLVM_BUG_59792 to work around
32 that rare LLVM bug, though you may get many false-alarm warnings. */
33# define _Noreturn
34# elif ((!defined __cplusplus || defined __clang__) \
35 && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) \
36 || (!defined __STRICT_ANSI__ \
37 && (4 < __GNUC__ + (7 <= __GNUC_MINOR__) \
38 || (defined __apple_build_version__ \
39 ? 6000000 <= __apple_build_version__ \
40 : 3 < __clang_major__ + (5 <= __clang_minor__))))))
41 /* _Noreturn works as-is. */ 32 /* _Noreturn works as-is. */
42# elif (2 < __GNUC__ + (8 <= __GNUC_MINOR__) || defined __clang__ \ 33# elif (2 < __GNUC__ + (8 <= __GNUC_MINOR__) || defined __clang__ \
43 || 0x5110 <= __SUNPRO_C) 34 || 0x5110 <= __SUNPRO_C)
35 /* Prefer __attribute__ ((__noreturn__)) to plain _Noreturn even if the
36 latter works, as 'gcc -std=gnu99 -Wpedantic' warns about _Noreturn. */
44# define _Noreturn __attribute__ ((__noreturn__)) 37# define _Noreturn __attribute__ ((__noreturn__))
45# elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0) 38# elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0)
46# define _Noreturn __declspec (noreturn) 39# define _Noreturn __declspec (noreturn)
diff --git a/gl/af_alg.c b/gl/af_alg.c
index 6fd08c28..cfa96954 100644
--- a/gl/af_alg.c
+++ b/gl/af_alg.c
@@ -1,5 +1,5 @@
1/* af_alg.c - Compute message digests from file streams and buffers. 1/* af_alg.c - Compute message digests from file streams and buffers.
2 Copyright (C) 2018-2024 Free Software Foundation, Inc. 2 Copyright (C) 2018-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/af_alg.h b/gl/af_alg.h
index ed933e12..236659bc 100644
--- a/gl/af_alg.h
+++ b/gl/af_alg.h
@@ -1,5 +1,5 @@
1/* af_alg.h - Compute message digests from file streams and buffers. 1/* af_alg.h - Compute message digests from file streams and buffers.
2 Copyright (C) 2018-2024 Free Software Foundation, Inc. 2 Copyright (C) 2018-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/alloca.in.h b/gl/alloca.in.h
index 6aa47df8..afb00caf 100644
--- a/gl/alloca.in.h
+++ b/gl/alloca.in.h
@@ -1,6 +1,6 @@
1/* Memory allocation on the stack. 1/* Memory allocation on the stack.
2 2
3 Copyright (C) 1995, 1999, 2001-2004, 2006-2024 Free Software Foundation, 3 Copyright (C) 1995, 1999, 2001-2004, 2006-2025 Free Software Foundation,
4 Inc. 4 Inc.
5 5
6 This file is free software: you can redistribute it and/or modify 6 This file is free software: you can redistribute it and/or modify
diff --git a/gl/arg-nonnull.h b/gl/arg-nonnull.h
index 46c711ca..747bb413 100644
--- a/gl/arg-nonnull.h
+++ b/gl/arg-nonnull.h
@@ -1,5 +1,5 @@
1/* A C macro for declaring that specific arguments must not be NULL. 1/* A C macro for declaring that specific arguments must not be NULL.
2 Copyright (C) 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2009-2025 Free Software Foundation, Inc.
3 3
4 This program is free software: you can redistribute it and/or modify it 4 This program is free software: you can redistribute it and/or modify it
5 under the terms of the GNU Lesser General Public License as published 5 under the terms of the GNU Lesser General Public License as published
diff --git a/gl/arpa_inet.c b/gl/arpa_inet.c
new file mode 100644
index 00000000..fae7c241
--- /dev/null
+++ b/gl/arpa_inet.c
@@ -0,0 +1,21 @@
1/* Inline functions for <arpa/inet.h>.
2
3 Copyright (C) 2024-2025 Free Software Foundation, Inc.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20#define _GL_ARPA_INET_INLINE _GL_EXTERN_INLINE
21#include <arpa/inet.h>
diff --git a/gl/arpa_inet.in.h b/gl/arpa_inet.in.h
index 523a448c..d7417bfd 100644
--- a/gl/arpa_inet.in.h
+++ b/gl/arpa_inet.in.h
@@ -1,6 +1,6 @@
1/* A GNU-like <arpa/inet.h>. 1/* A GNU-like <arpa/inet.h>.
2 2
3 Copyright (C) 2005-2006, 2008-2024 Free Software Foundation, Inc. 3 Copyright (C) 2005-2006, 2008-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -60,6 +60,53 @@
60# include <ws2tcpip.h> 60# include <ws2tcpip.h>
61#endif 61#endif
62 62
63#if !(@HAVE_DECL_HTONL@ || @HAVE_DECL_HTONS@ || @HAVE_DECL_NTOHL@ || @HAVE_DECL_NTOHS@)
64# include <endian.h>
65#endif
66
67_GL_INLINE_HEADER_BEGIN
68#ifndef _GL_ARPA_INET_INLINE
69# define _GL_ARPA_INET_INLINE _GL_INLINE
70#endif
71
72
73/* Host to network byte order. */
74
75#if !@HAVE_DECL_HTONS@
76_GL_ARPA_INET_INLINE uint16_t
77htons (uint16_t value)
78{
79 return htobe16 (value);
80}
81#endif
82
83#if !@HAVE_DECL_HTONL@
84_GL_ARPA_INET_INLINE uint32_t
85htonl (uint32_t value)
86{
87 return htobe32 (value);
88}
89#endif
90
91/* Network to host byte order. */
92
93#if !@HAVE_DECL_NTOHS@
94_GL_ARPA_INET_INLINE uint16_t
95ntohs (uint16_t value)
96{
97 return htobe16 (value);
98}
99#endif
100
101#if !@HAVE_DECL_NTOHL@
102_GL_ARPA_INET_INLINE uint32_t
103ntohl (uint32_t value)
104{
105 return htobe32 (value);
106}
107#endif
108
109
63/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ 110/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
64 111
65/* The definition of _GL_ARG_NONNULL is copied here. */ 112/* The definition of _GL_ARG_NONNULL is copied here. */
@@ -90,7 +137,7 @@
90# endif 137# endif
91_GL_FUNCDECL_RPL (inet_ntop, const char *, 138_GL_FUNCDECL_RPL (inet_ntop, const char *,
92 (int af, const void *restrict src, 139 (int af, const void *restrict src,
93 char *restrict dst, socklen_t cnt) 140 char *restrict dst, socklen_t cnt),
94 _GL_ARG_NONNULL ((2, 3))); 141 _GL_ARG_NONNULL ((2, 3)));
95_GL_CXXALIAS_RPL (inet_ntop, const char *, 142_GL_CXXALIAS_RPL (inet_ntop, const char *,
96 (int af, const void *restrict src, 143 (int af, const void *restrict src,
@@ -99,7 +146,7 @@ _GL_CXXALIAS_RPL (inet_ntop, const char *,
99# if !@HAVE_DECL_INET_NTOP@ 146# if !@HAVE_DECL_INET_NTOP@
100_GL_FUNCDECL_SYS (inet_ntop, const char *, 147_GL_FUNCDECL_SYS (inet_ntop, const char *,
101 (int af, const void *restrict src, 148 (int af, const void *restrict src,
102 char *restrict dst, socklen_t cnt) 149 char *restrict dst, socklen_t cnt),
103 _GL_ARG_NONNULL ((2, 3))); 150 _GL_ARG_NONNULL ((2, 3)));
104# endif 151# endif
105/* Need to cast, because on NonStop Kernel, the fourth parameter is 152/* Need to cast, because on NonStop Kernel, the fourth parameter is
@@ -126,14 +173,14 @@ _GL_WARN_ON_USE (inet_ntop, "inet_ntop is unportable - "
126# define inet_pton rpl_inet_pton 173# define inet_pton rpl_inet_pton
127# endif 174# endif
128_GL_FUNCDECL_RPL (inet_pton, int, 175_GL_FUNCDECL_RPL (inet_pton, int,
129 (int af, const char *restrict src, void *restrict dst) 176 (int af, const char *restrict src, void *restrict dst),
130 _GL_ARG_NONNULL ((2, 3))); 177 _GL_ARG_NONNULL ((2, 3)));
131_GL_CXXALIAS_RPL (inet_pton, int, 178_GL_CXXALIAS_RPL (inet_pton, int,
132 (int af, const char *restrict src, void *restrict dst)); 179 (int af, const char *restrict src, void *restrict dst));
133# else 180# else
134# if !@HAVE_DECL_INET_PTON@ 181# if !@HAVE_DECL_INET_PTON@
135_GL_FUNCDECL_SYS (inet_pton, int, 182_GL_FUNCDECL_SYS (inet_pton, int,
136 (int af, const char *restrict src, void *restrict dst) 183 (int af, const char *restrict src, void *restrict dst),
137 _GL_ARG_NONNULL ((2, 3))); 184 _GL_ARG_NONNULL ((2, 3)));
138# endif 185# endif
139_GL_CXXALIAS_SYS (inet_pton, int, 186_GL_CXXALIAS_SYS (inet_pton, int,
@@ -150,6 +197,7 @@ _GL_WARN_ON_USE (inet_pton, "inet_pton is unportable - "
150# endif 197# endif
151#endif 198#endif
152 199
200_GL_INLINE_HEADER_END
153 201
154#endif /* _@GUARD_PREFIX@_ARPA_INET_H */ 202#endif /* _@GUARD_PREFIX@_ARPA_INET_H */
155#endif /* _@GUARD_PREFIX@_ARPA_INET_H */ 203#endif /* _@GUARD_PREFIX@_ARPA_INET_H */
diff --git a/gl/asnprintf.c b/gl/asnprintf.c
index a6c09bc2..0488b6be 100644
--- a/gl/asnprintf.c
+++ b/gl/asnprintf.c
@@ -1,5 +1,5 @@
1/* Formatted output to strings. 1/* Formatted output to strings.
2 Copyright (C) 1999, 2002, 2006, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2002, 2006, 2009-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/asprintf.c b/gl/asprintf.c
index b0c33478..336700be 100644
--- a/gl/asprintf.c
+++ b/gl/asprintf.c
@@ -1,5 +1,5 @@
1/* Formatted output to strings. 1/* Formatted output to strings.
2 Copyright (C) 1999, 2002, 2006-2007, 2009-2024 Free Software Foundation, 2 Copyright (C) 1999, 2002, 2006-2007, 2009-2025 Free Software Foundation,
3 Inc. 3 Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/assert.in.h b/gl/assert.in.h
index 6e4995e1..87339abc 100644
--- a/gl/assert.in.h
+++ b/gl/assert.in.h
@@ -1,5 +1,5 @@
1/* Substitute for and wrapper around <assert.h> 1/* Substitute for and wrapper around <assert.h>
2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 2 Copyright (C) 2011-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/attribute.h b/gl/attribute.h
index 710341ba..c85412d9 100644
--- a/gl/attribute.h
+++ b/gl/attribute.h
@@ -1,6 +1,6 @@
1/* ATTRIBUTE_* macros for using attributes in GCC and similar compilers 1/* ATTRIBUTE_* macros for using attributes in GCC and similar compilers
2 2
3 Copyright 2020-2024 Free Software Foundation, Inc. 3 Copyright 2020-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -20,12 +20,50 @@
20/* Provide public ATTRIBUTE_* names for the private _GL_ATTRIBUTE_* 20/* Provide public ATTRIBUTE_* names for the private _GL_ATTRIBUTE_*
21 macros used within Gnulib. */ 21 macros used within Gnulib. */
22 22
23/* These attributes can be placed in two ways: 23/* The placement of these attributes depends on the kind of declaration
24 - At the start of a declaration (i.e. even before storage-class 24 and, in some cases, also on the programming language (C vs. C++).
25 specifiers!); then they apply to all entities that are declared 25
26 by the declaration. 26 In function declarations and function definitions:
27 - Immediately after the name of an entity being declared by the 27
28 declaration; then they apply to that entity only. */ 28 * ATTRIBUTE_NOTHROW must come after the parameter list.
29
30 * The macros
31 ATTRIBUTE_CONST
32 ATTRIBUTE_PURE
33 DEPRECATED
34 MAYBE_UNUSED
35 NODISCARD
36 REPRODUCIBLE
37 UNSEQUENCED
38 must come before the return type, and more precisely:
39 - In a function declaration/definition without a storage-class
40 specifier: at the beginning of the declaration/definition.
41 - In a function declaration/definition with a storage-class
42 specifier:
43 - In C: before the storage-class specifier.
44 - In C++: between the storage-class specifier and the return type.
45
46 * The other macros can be placed
47 - Either
48 - In a function declaration/definition without a storage-class
49 specifier: at the beginning of the declaration/definition.
50 - In a function declaration/definition with a storage-class
51 specifier: between the storage-class specifier and the return
52 type.
53 - Or, in a function declaration:
54 after the parameter list,
55 ∙ but after ATTRIBUTE_NOTHROW if present.
56
57 In other declarations, such as variable declarations:
58
59 * Either
60 - In C: before the storage-class specifier.
61 - In C++: between the storage-class specifier and the return type.
62 Then they apply to all entities that are declared by the declaration.
63
64 * Or immediately after the name of an entity being declared by the
65 declaration. Then they apply to that entity only.
66 */
29 67
30#ifndef _GL_ATTRIBUTE_H 68#ifndef _GL_ATTRIBUTE_H
31#define _GL_ATTRIBUTE_H 69#define _GL_ATTRIBUTE_H
@@ -48,9 +86,10 @@
48 _GL_ATTRIBUTE_FALLTHROUGH, _GL_ATTRIBUTE_FORMAT, _GL_ATTRIBUTE_LEAF, 86 _GL_ATTRIBUTE_FALLTHROUGH, _GL_ATTRIBUTE_FORMAT, _GL_ATTRIBUTE_LEAF,
49 _GL_ATTRIBUTE_MALLOC, _GL_ATTRIBUTE_MAY_ALIAS, _GL_ATTRIBUTE_MAYBE_UNUSED, 87 _GL_ATTRIBUTE_MALLOC, _GL_ATTRIBUTE_MAY_ALIAS, _GL_ATTRIBUTE_MAYBE_UNUSED,
50 _GL_ATTRIBUTE_NODISCARD, _GL_ATTRIBUTE_NOINLINE, _GL_ATTRIBUTE_NONNULL, 88 _GL_ATTRIBUTE_NODISCARD, _GL_ATTRIBUTE_NOINLINE, _GL_ATTRIBUTE_NONNULL,
51 _GL_ATTRIBUTE_NONSTRING, _GL_ATTRIBUTE_NOTHROW, _GL_ATTRIBUTE_PACKED, 89 _GL_ATTRIBUTE_NONNULL_IF_NONZERO, _GL_ATTRIBUTE_NONSTRING,
52 _GL_ATTRIBUTE_PURE, _GL_ATTRIBUTE_RETURNS_NONNULL, 90 _GL_ATTRIBUTE_NOTHROW, _GL_ATTRIBUTE_PACKED, _GL_ATTRIBUTE_PURE,
53 _GL_ATTRIBUTE_SENTINEL. */ 91 _GL_ATTRIBUTE_REPRODUCIBLE, _GL_ATTRIBUTE_RETURNS_NONNULL,
92 _GL_ATTRIBUTE_SENTINEL, _GL_ATTRIBUTE_UNSEQUENCED. */
54#if !_GL_CONFIG_H_INCLUDED 93#if !_GL_CONFIG_H_INCLUDED
55 #error "Please include config.h first." 94 #error "Please include config.h first."
56#endif 95#endif
@@ -88,7 +127,7 @@
88 is the size of the returned memory block. 127 is the size of the returned memory block.
89 ATTRIBUTE_ALLOC_SIZE ((M, N)) - Multiply the Mth and Nth arguments 128 ATTRIBUTE_ALLOC_SIZE ((M, N)) - Multiply the Mth and Nth arguments
90 to determine the size of the returned memory block. */ 129 to determine the size of the returned memory block. */
91/* Applies to: function, pointer to function, function types. */ 130/* Applies to: functions, pointer to functions, function types. */
92#define ATTRIBUTE_ALLOC_SIZE(args) _GL_ATTRIBUTE_ALLOC_SIZE (args) 131#define ATTRIBUTE_ALLOC_SIZE(args) _GL_ATTRIBUTE_ALLOC_SIZE (args)
93 132
94/* ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers 133/* ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers
@@ -132,6 +171,12 @@
132/* Applies to: functions. */ 171/* Applies to: functions. */
133#define ATTRIBUTE_NONNULL(args) _GL_ATTRIBUTE_NONNULL (args) 172#define ATTRIBUTE_NONNULL(args) _GL_ATTRIBUTE_NONNULL (args)
134 173
174/* ATTRIBUTE_NONNULL_IF_NONZERO (NP, NI) - Argument NP (a pointer)
175 must not be NULL if the argument NI (an integer) is != 0. */
176/* Applies to: functions. */
177#define ATTRIBUTE_NONNULL_IF_NONZERO(np, ni) _GL_ATTRIBUTE_NONNULL_IF_NONZERO (np, ni)
178
179
135/* The function's return value is a non-NULL pointer. */ 180/* The function's return value is a non-NULL pointer. */
136/* Applies to: functions. */ 181/* Applies to: functions. */
137#define ATTRIBUTE_RETURNS_NONNULL _GL_ATTRIBUTE_RETURNS_NONNULL 182#define ATTRIBUTE_RETURNS_NONNULL _GL_ATTRIBUTE_RETURNS_NONNULL
@@ -170,7 +215,7 @@
170/* Attributes regarding debugging information emitted by the compiler. */ 215/* Attributes regarding debugging information emitted by the compiler. */
171 216
172/* Omit the function from stack traces when debugging. */ 217/* Omit the function from stack traces when debugging. */
173/* Applies to: function. */ 218/* Applies to: functions. */
174#define ATTRIBUTE_ARTIFICIAL _GL_ATTRIBUTE_ARTIFICIAL 219#define ATTRIBUTE_ARTIFICIAL _GL_ATTRIBUTE_ARTIFICIAL
175 220
176/* Make the entity visible to debuggers etc., even with '-fwhole-program'. */ 221/* Make the entity visible to debuggers etc., even with '-fwhole-program'. */
@@ -192,25 +237,68 @@
192 237
193/* Always inline the function, and report an error if the compiler 238/* Always inline the function, and report an error if the compiler
194 cannot inline. */ 239 cannot inline. */
195/* Applies to: function. */ 240/* Applies to: functions. */
196#define ATTRIBUTE_ALWAYS_INLINE _GL_ATTRIBUTE_ALWAYS_INLINE 241#define ATTRIBUTE_ALWAYS_INLINE _GL_ATTRIBUTE_ALWAYS_INLINE
197 242
198/* It is OK for a compiler to omit duplicate calls with the same arguments. 243/* It is OK for a compiler to move calls to the function and to omit
244 calls to the function if another call has the same arguments or the
245 result is not used.
199 This attribute is safe for a function that neither depends on 246 This attribute is safe for a function that neither depends on
200 nor affects observable state, and always returns exactly once - 247 nor affects state, and always returns exactly once -
201 e.g., does not loop forever, and does not call longjmp. 248 e.g., does not raise an exception, call longjmp, or loop forever.
202 (This attribute is stricter than ATTRIBUTE_PURE.) */ 249 (This attribute is stricter than ATTRIBUTE_PURE because the
250 function cannot observe state. It is stricter than UNSEQUENCED
251 because the function must return exactly once and cannot depend on
252 state addressed by its arguments.) */
203/* Applies to: functions. */ 253/* Applies to: functions. */
204#define ATTRIBUTE_CONST _GL_ATTRIBUTE_CONST 254#define ATTRIBUTE_CONST _GL_ATTRIBUTE_CONST
205 255
206/* It is OK for a compiler to omit duplicate calls with the same 256/* It is OK for a compiler to move calls to the function and to omit duplicate
207 arguments if observable state is not changed between calls. 257 calls to the function with the same arguments, so long as the state
208 This attribute is safe for a function that does not affect 258 addressed by its arguments is the same.
209 observable state, and always returns exactly once. 259 This attribute is safe for a function that is effectless, idempotent,
210 (This attribute is looser than ATTRIBUTE_CONST.) */ 260 stateless, and independent; see ISO C 23 § 6.7.12.7 for a definition of
261 these terms.
262 (This attribute is stricter than REPRODUCIBLE because the function
263 must be stateless and independent. It is looser than ATTRIBUTE_CONST
264 because the function need not return exactly once and can depend
265 on state addressed by its arguments.)
266 See also <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2956.htm> and
267 <https://stackoverflow.com/questions/76847905/>.
268 ATTENTION! Efforts are underway to change the meaning of this attribute.
269 See <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3424.htm>. */
270/* Applies to: functions, pointer to functions, function type. */
271#define UNSEQUENCED _GL_ATTRIBUTE_UNSEQUENCED
272
273/* It is OK for a compiler to move calls to the function and to omit
274 calls to the function if another call has the same arguments or the
275 result is not used, and if observable state is the same.
276 This attribute is safe for a function that does not affect observable state
277 and always returns exactly once.
278 (This attribute is looser than ATTRIBUTE_CONST because the function
279 can depend on observable state. It is stricter than REPRODUCIBLE
280 because the function must return exactly once and cannot affect
281 state addressed by its arguments.) */
211/* Applies to: functions. */ 282/* Applies to: functions. */
212#define ATTRIBUTE_PURE _GL_ATTRIBUTE_PURE 283#define ATTRIBUTE_PURE _GL_ATTRIBUTE_PURE
213 284
285/* It is OK for a compiler to move calls to the function and to omit duplicate
286 calls to the function with the same arguments, so long as the state
287 addressed by its arguments is the same and is updated in time for
288 the rest of the program.
289 This attribute is safe for a function that is effectless and idempotent; see
290 ISO C 23 § 6.7.12.7 for a definition of these terms.
291 (This attribute is looser than UNSEQUENCED because the function need
292 not be stateless and idempotent. It is looser than ATTRIBUTE_PURE
293 because the function need not return exactly once and can affect
294 state addressed by its arguments.)
295 See also <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2956.htm> and
296 <https://stackoverflow.com/questions/76847905/>.
297 ATTENTION! Efforts are underway to change the meaning of this attribute.
298 See <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3424.htm>. */
299/* Applies to: functions, pointer to functions, function type. */
300#define REPRODUCIBLE _GL_ATTRIBUTE_REPRODUCIBLE
301
214/* The function is rarely executed. */ 302/* The function is rarely executed. */
215/* Applies to: functions. */ 303/* Applies to: functions. */
216#define ATTRIBUTE_COLD _GL_ATTRIBUTE_COLD 304#define ATTRIBUTE_COLD _GL_ATTRIBUTE_COLD
diff --git a/gl/base64.c b/gl/base64.c
index c8b3b76b..8a0edd4a 100644
--- a/gl/base64.c
+++ b/gl/base64.c
@@ -1,5 +1,5 @@
1/* base64.c -- Encode binary data using printable characters. 1/* base64.c -- Encode binary data using printable characters.
2 Copyright (C) 1999-2001, 2004-2006, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 1999-2001, 2004-2006, 2009-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -48,7 +48,7 @@
48/* Get imalloc. */ 48/* Get imalloc. */
49#include <ialloc.h> 49#include <ialloc.h>
50 50
51#include <intprops.h> 51#include <stdckdint.h>
52 52
53#include <string.h> 53#include <string.h>
54 54
@@ -59,7 +59,7 @@ to_uchar (char ch)
59 return ch; 59 return ch;
60} 60}
61 61
62static const char b64c[64] = 62static const char b64c[64] _GL_ATTRIBUTE_NONSTRING =
63 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 63 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
64 64
65/* Base64 encode IN array of size INLEN into OUT array. OUT needs 65/* Base64 encode IN array of size INLEN into OUT array. OUT needs
@@ -148,7 +148,7 @@ base64_encode_alloc (const char *in, idx_t inlen, char **out)
148 Treat negative INLEN as overflow, for better compatibility with 148 Treat negative INLEN as overflow, for better compatibility with
149 pre-2021-08-27 API, which used size_t. */ 149 pre-2021-08-27 API, which used size_t. */
150 idx_t in_over_3 = inlen / 3 + (inlen % 3 != 0), outlen; 150 idx_t in_over_3 = inlen / 3 + (inlen % 3 != 0), outlen;
151 if (! INT_MULTIPLY_OK (in_over_3, 4, &outlen) || inlen < 0) 151 if (ckd_mul (&outlen, in_over_3, 4) || inlen < 0)
152 { 152 {
153 *out = NULL; 153 *out = NULL;
154 return 0; 154 return 0;
diff --git a/gl/base64.h b/gl/base64.h
index 7691f6c4..cdafdac9 100644
--- a/gl/base64.h
+++ b/gl/base64.h
@@ -1,5 +1,5 @@
1/* base64.h -- Encode binary data using printable characters. 1/* base64.h -- Encode binary data using printable characters.
2 Copyright (C) 2004-2006, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2004-2006, 2009-2025 Free Software Foundation, Inc.
3 Written by Simon Josefsson. 3 Written by Simon Josefsson.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
@@ -27,7 +27,7 @@
27#include <idx.h> 27#include <idx.h>
28 28
29/* Pacify GCC in isubase64. */ 29/* Pacify GCC in isubase64. */
30#if defined __GNUC__ && 4 < __GNUC__ + (3 <= __GNUC_MINOR__) 30#if 4 < __GNUC__ + (3 <= __GNUC_MINOR__) && !defined __clang__
31# pragma GCC diagnostic ignored "-Wtype-limits" 31# pragma GCC diagnostic ignored "-Wtype-limits"
32#endif 32#endif
33 33
diff --git a/gl/basename-lgpl.c b/gl/basename-lgpl.c
index 256f8460..2aecb0dd 100644
--- a/gl/basename-lgpl.c
+++ b/gl/basename-lgpl.c
@@ -1,6 +1,6 @@
1/* basename.c -- return the last element in a file name 1/* basename.c -- return the last element in a file name
2 2
3 Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2024 Free Software 3 Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2025 Free Software
4 Foundation, Inc. 4 Foundation, Inc.
5 5
6 This file is free software: you can redistribute it and/or modify 6 This file is free software: you can redistribute it and/or modify
diff --git a/gl/basename-lgpl.h b/gl/basename-lgpl.h
index 2a56be98..120bd1cf 100644
--- a/gl/basename-lgpl.h
+++ b/gl/basename-lgpl.h
@@ -1,6 +1,6 @@
1/* Extract the last component (base name) of a file name. 1/* Extract the last component (base name) of a file name.
2 2
3 Copyright (C) 1998, 2001, 2003-2006, 2009-2024 Free Software Foundation, 3 Copyright (C) 1998, 2001, 2003-2006, 2009-2025 Free Software Foundation,
4 Inc. 4 Inc.
5 5
6 This file is free software: you can redistribute it and/or modify 6 This file is free software: you can redistribute it and/or modify
diff --git a/gl/basename.c b/gl/basename.c
index c5a6bdc9..9d2852d4 100644
--- a/gl/basename.c
+++ b/gl/basename.c
@@ -1,6 +1,6 @@
1/* basename.c -- return the last element in a file name 1/* basename.c -- return the last element in a file name
2 2
3 Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2024 Free Software 3 Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2025 Free Software
4 Foundation, Inc. 4 Foundation, Inc.
5 5
6 This program is free software: you can redistribute it and/or modify 6 This program is free software: you can redistribute it and/or modify
diff --git a/gl/btowc.c b/gl/btowc.c
index 8bf21aa6..891347de 100644
--- a/gl/btowc.c
+++ b/gl/btowc.c
@@ -1,5 +1,5 @@
1/* Convert unibyte character to wide character. 1/* Convert unibyte character to wide character.
2 Copyright (C) 2008, 2010-2024 Free Software Foundation, Inc. 2 Copyright (C) 2008, 2010-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2008. 3 Written by Bruno Haible <bruno@clisp.org>, 2008.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/byteswap.c b/gl/byteswap.c
new file mode 100644
index 00000000..97f7fc9e
--- /dev/null
+++ b/gl/byteswap.c
@@ -0,0 +1,21 @@
1/* Inline functions for <byteswap.h>.
2
3 Copyright 2024-2025 Free Software Foundation, Inc.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20#define _GL_BYTESWAP_INLINE _GL_EXTERN_INLINE
21#include <byteswap.h>
diff --git a/gl/byteswap.in.h b/gl/byteswap.in.h
index 8e49efad..6b4fbabf 100644
--- a/gl/byteswap.in.h
+++ b/gl/byteswap.in.h
@@ -1,5 +1,5 @@
1/* byteswap.h - Byte swapping 1/* byteswap.h - Byte swapping
2 Copyright (C) 2005, 2007, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005, 2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Oskar Liljeblad <oskar@osk.mine.nu>, 2005. 3 Written by Oskar Liljeblad <oskar@osk.mine.nu>, 2005.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
@@ -16,29 +16,103 @@
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 17
18#ifndef _GL_BYTESWAP_H 18#ifndef _GL_BYTESWAP_H
19#define _GL_BYTESWAP_H 19#define _GL_BYTESWAP_H 1
20
21/* This file uses _GL_INLINE. */
22#if !_GL_CONFIG_H_INCLUDED
23 #error "Please include config.h first."
24#endif
25
26/* Define this now, rather than after including stdint.h, in case
27 stdint.h recursively includes us. This is for Gnulib endian.h. */
28#ifndef _GL_BYTESWAP_INLINE
29# define _GL_BYTESWAP_INLINE _GL_INLINE
30#endif
31
32#include <stdint.h>
33
34_GL_INLINE_HEADER_BEGIN
35
36#ifdef __cplusplus
37extern "C" {
38#endif
39
40#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
41# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP16 true
42#elif defined __has_builtin
43# if __has_builtin (__builtin_bswap16)
44# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP16 true
45# endif
46#endif
47
48#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
49# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP32 true
50# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP64 true
51#elif defined __has_builtin
52# if __has_builtin (__builtin_bswap32)
53# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP32 true
54# endif
55# if __has_builtin (__builtin_bswap64)
56# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP64 true
57# endif
58#endif
20 59
21/* Given an unsigned 16-bit argument X, return the value corresponding to 60/* Given an unsigned 16-bit argument X, return the value corresponding to
22 X with reversed byte order. */ 61 X with reversed byte order. */
23#define bswap_16(x) ((((x) & 0x00FF) << 8) | \ 62_GL_BYTESWAP_INLINE uint_least16_t
24 (((x) & 0xFF00) >> 8)) 63bswap_16 (uint_least16_t x)
64{
65#ifdef _GL_BYTESWAP_HAS_BUILTIN_BSWAP16
66 return __builtin_bswap16 (x);
67#else
68 uint_fast16_t mask = 0xff;
69 return ( (x & mask << 8 * 1) >> 8 * 1
70 | (x & mask << 8 * 0) << 8 * 1);
71#endif
72}
25 73
26/* Given an unsigned 32-bit argument X, return the value corresponding to 74/* Given an unsigned 32-bit argument X, return the value corresponding to
27 X with reversed byte order. */ 75 X with reversed byte order. */
28#define bswap_32(x) ((((x) & 0x000000FF) << 24) | \ 76_GL_BYTESWAP_INLINE uint_least32_t
29 (((x) & 0x0000FF00) << 8) | \ 77bswap_32 (uint_least32_t x)
30 (((x) & 0x00FF0000) >> 8) | \ 78{
31 (((x) & 0xFF000000) >> 24)) 79#ifdef _GL_BYTESWAP_HAS_BUILTIN_BSWAP32
80 return __builtin_bswap32 (x);
81#else
82 uint_fast32_t mask = 0xff;
83 return ( (x & mask << 8 * 3) >> 8 * 3
84 | (x & mask << 8 * 2) >> 8 * 1
85 | (x & mask << 8 * 1) << 8 * 1
86 | (x & mask << 8 * 0) << 8 * 3);
87#endif
88}
32 89
90#ifdef UINT_LEAST64_MAX
33/* Given an unsigned 64-bit argument X, return the value corresponding to 91/* Given an unsigned 64-bit argument X, return the value corresponding to
34 X with reversed byte order. */ 92 X with reversed byte order. */
35#define bswap_64(x) ((((x) & 0x00000000000000FFULL) << 56) | \ 93_GL_BYTESWAP_INLINE uint_least64_t
36 (((x) & 0x000000000000FF00ULL) << 40) | \ 94bswap_64 (uint_least64_t x)
37 (((x) & 0x0000000000FF0000ULL) << 24) | \ 95{
38 (((x) & 0x00000000FF000000ULL) << 8) | \ 96# ifdef _GL_BYTESWAP_HAS_BUILTIN_BSWAP64
39 (((x) & 0x000000FF00000000ULL) >> 8) | \ 97 return __builtin_bswap64 (x);
40 (((x) & 0x0000FF0000000000ULL) >> 24) | \ 98# else
41 (((x) & 0x00FF000000000000ULL) >> 40) | \ 99 uint_fast64_t mask = 0xff;
42 (((x) & 0xFF00000000000000ULL) >> 56)) 100 return ( (x & mask << 8 * 7) >> 8 * 7
101 | (x & mask << 8 * 6) >> 8 * 5
102 | (x & mask << 8 * 5) >> 8 * 3
103 | (x & mask << 8 * 4) >> 8 * 1
104 | (x & mask << 8 * 3) << 8 * 1
105 | (x & mask << 8 * 2) << 8 * 3
106 | (x & mask << 8 * 1) << 8 * 5
107 | (x & mask << 8 * 0) << 8 * 7);
108# endif
109}
110#endif
111
112#ifdef __cplusplus
113}
114#endif
115
116_GL_INLINE_HEADER_END
43 117
44#endif /* _GL_BYTESWAP_H */ 118#endif /* _GL_BYTESWAP_H */
diff --git a/gl/c++defs.h b/gl/c++defs.h
index eb66967b..df98a5ae 100644
--- a/gl/c++defs.h
+++ b/gl/c++defs.h
@@ -1,5 +1,5 @@
1/* C++ compatible function declaration macros. 1/* C++ compatible function declaration macros.
2 Copyright (C) 2010-2024 Free Software Foundation, Inc. 2 Copyright (C) 2010-2025 Free Software Foundation, Inc.
3 3
4 This program is free software: you can redistribute it and/or modify it 4 This program is free software: you can redistribute it and/or modify it
5 under the terms of the GNU Lesser General Public License as published 5 under the terms of the GNU Lesser General Public License as published
@@ -93,11 +93,27 @@
93# define _GL_EXTERN_C extern 93# define _GL_EXTERN_C extern
94#endif 94#endif
95 95
96/* _GL_FUNCDECL_RPL (func, rettype, parameters_and_attributes); 96/* _GL_EXTERN_C_FUNC declaration;
97 performs the declaration of a function with C linkage. */
98#if defined __cplusplus
99# define _GL_EXTERN_C_FUNC extern "C"
100#else
101/* In C mode, omit the 'extern' keyword, because attributes in bracket syntax
102 are not allowed between 'extern' and the return type (see gnulib-common.m4).
103 */
104# define _GL_EXTERN_C_FUNC
105#endif
106
107/* _GL_FUNCDECL_RPL (func, rettype, parameters, [attributes]);
97 declares a replacement function, named rpl_func, with the given prototype, 108 declares a replacement function, named rpl_func, with the given prototype,
98 consisting of return type, parameters, and attributes. 109 consisting of return type, parameters, and attributes.
99 Example: 110 Although attributes are optional, the comma before them is required
100 _GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...) 111 for portability to C17 and earlier. The attribute _GL_ATTRIBUTE_NOTHROW,
112 if needed, must be placed after the _GL_FUNCDECL_RPL invocation,
113 at the end of the declaration.
114 Examples:
115 _GL_FUNCDECL_RPL (free, void, (void *ptr), ) _GL_ATTRIBUTE_NOTHROW;
116 _GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...),
101 _GL_ARG_NONNULL ((1))); 117 _GL_ARG_NONNULL ((1)));
102 118
103 Note: Attributes, such as _GL_ATTRIBUTE_DEPRECATED, are supported in front 119 Note: Attributes, such as _GL_ATTRIBUTE_DEPRECATED, are supported in front
@@ -106,20 +122,24 @@
106 [[...]] extern "C" <declaration>; 122 [[...]] extern "C" <declaration>;
107 is invalid syntax in C++.) 123 is invalid syntax in C++.)
108 */ 124 */
109#define _GL_FUNCDECL_RPL(func,rettype,parameters_and_attributes) \ 125#define _GL_FUNCDECL_RPL(func,rettype,parameters,...) \
110 _GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters_and_attributes) 126 _GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters, __VA_ARGS__)
111#define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters_and_attributes) \ 127#define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters,...) \
112 _GL_EXTERN_C rettype rpl_func parameters_and_attributes 128 _GL_EXTERN_C_FUNC __VA_ARGS__ rettype rpl_func parameters
113 129
114/* _GL_FUNCDECL_SYS (func, rettype, parameters_and_attributes); 130/* _GL_FUNCDECL_SYS (func, rettype, parameters, [attributes]);
115 declares the system function, named func, with the given prototype, 131 declares the system function, named func, with the given prototype,
116 consisting of return type, parameters, and attributes. 132 consisting of return type, parameters, and attributes.
117 Example: 133 Although attributes are optional, the comma before them is required
118 _GL_FUNCDECL_SYS (open, int, (const char *filename, int flags, ...) 134 for portability to C17 and earlier. The attribute _GL_ATTRIBUTE_NOTHROW,
119 _GL_ARG_NONNULL ((1))); 135 if needed, must be placed after the _GL_FUNCDECL_RPL invocation,
136 at the end of the declaration.
137 Examples:
138 _GL_FUNCDECL_SYS (getumask, mode_t, (void), ) _GL_ATTRIBUTE_NOTHROW;
139 _GL_FUNCDECL_SYS (posix_openpt, int, (int flags), _GL_ATTRIBUTE_NODISCARD);
120 */ 140 */
121#define _GL_FUNCDECL_SYS(func,rettype,parameters_and_attributes) \ 141#define _GL_FUNCDECL_SYS(func,rettype,parameters,...) \
122 _GL_EXTERN_C rettype func parameters_and_attributes 142 _GL_EXTERN_C_FUNC __VA_ARGS__ rettype func parameters
123 143
124/* _GL_CXXALIAS_RPL (func, rettype, parameters); 144/* _GL_CXXALIAS_RPL (func, rettype, parameters);
125 declares a C++ alias called GNULIB_NAMESPACE::func 145 declares a C++ alias called GNULIB_NAMESPACE::func
@@ -297,7 +317,7 @@
297 _GL_WARN_ON_USE (func, \ 317 _GL_WARN_ON_USE (func, \
298 "The symbol ::" #func " refers to the system function. " \ 318 "The symbol ::" #func " refers to the system function. " \
299 "Use " #namespace "::" #func " instead.") 319 "Use " #namespace "::" #func " instead.")
300# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING 320# elif (__GNUC__ >= 3 || defined __clang__) && GNULIB_STRICT_CHECKING
301# define _GL_CXXALIASWARN_2(func,namespace) \ 321# define _GL_CXXALIASWARN_2(func,namespace) \
302 extern __typeof__ (func) func 322 extern __typeof__ (func) func
303# else 323# else
diff --git a/gl/c-ctype.c b/gl/c-ctype.c
new file mode 100644
index 00000000..ecf2c083
--- /dev/null
+++ b/gl/c-ctype.c
@@ -0,0 +1,21 @@
1/* Character handling in C locale.
2
3 Copyright (C) 2003-2025 Free Software Foundation, Inc.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20#define C_CTYPE_INLINE _GL_EXTERN_INLINE
21#include "c-ctype.h"
diff --git a/gl/c-ctype.h b/gl/c-ctype.h
new file mode 100644
index 00000000..39063142
--- /dev/null
+++ b/gl/c-ctype.h
@@ -0,0 +1,366 @@
1/* Character handling in C locale.
2
3 These functions work like the corresponding functions in <ctype.h>,
4 except that they have the C (POSIX) locale hardwired, whereas the
5 <ctype.h> functions' behaviour depends on the current locale set via
6 setlocale.
7
8 Copyright (C) 2000-2003, 2006, 2008-2025 Free Software Foundation, Inc.
9
10 This file is free software: you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as
12 published by the Free Software Foundation; either version 2.1 of the
13 License, or (at your option) any later version.
14
15 This file is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public License
21 along with this program. If not, see <https://www.gnu.org/licenses/>. */
22
23#ifndef C_CTYPE_H
24#define C_CTYPE_H
25
26/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE. */
27#if !_GL_CONFIG_H_INCLUDED
28 #error "Please include config.h first."
29#endif
30
31_GL_INLINE_HEADER_BEGIN
32#ifndef C_CTYPE_INLINE
33# define C_CTYPE_INLINE _GL_INLINE
34#endif
35
36#ifdef __cplusplus
37extern "C" {
38#endif
39
40
41/* The functions defined in this file assume the "C" locale and a character
42 set without diacritics (ASCII-US or EBCDIC-US or something like that).
43 Even if the "C" locale on a particular system is an extension of the ASCII
44 character set (like on BeOS, where it is UTF-8, or on AmigaOS, where it
45 is ISO-8859-1), the functions in this file recognize only the ASCII
46 characters. */
47
48
49#if (' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
50 && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
51 && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
52 && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
53 && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
54 && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
55 && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
56 && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
57 && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
58 && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
59 && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
60 && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
61 && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
62 && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
63 && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
64 && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
65 && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
66 && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
67 && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
68 && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
69 && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
70 && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
71 && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)
72/* The character set is ASCII or one of its variants or extensions, not EBCDIC.
73 Testing the value of '\n' and '\r' is not relevant. */
74# define C_CTYPE_ASCII 1
75#elif ! (' ' == '\x40' && '0' == '\xf0' \
76 && 'A' == '\xc1' && 'J' == '\xd1' && 'S' == '\xe2' \
77 && 'a' == '\x81' && 'j' == '\x91' && 's' == '\xa2')
78# error "Only ASCII and EBCDIC are supported"
79#endif
80
81#if 'A' < 0
82# error "EBCDIC and char is signed -- not supported"
83#endif
84
85/* Cases for control characters. */
86
87#define _C_CTYPE_CNTRL \
88 case '\a': case '\b': case '\f': case '\n': \
89 case '\r': case '\t': case '\v': \
90 _C_CTYPE_OTHER_CNTRL
91
92/* ASCII control characters other than those with \-letter escapes. */
93
94#if C_CTYPE_ASCII
95# define _C_CTYPE_OTHER_CNTRL \
96 case '\x00': case '\x01': case '\x02': case '\x03': \
97 case '\x04': case '\x05': case '\x06': case '\x0e': \
98 case '\x0f': case '\x10': case '\x11': case '\x12': \
99 case '\x13': case '\x14': case '\x15': case '\x16': \
100 case '\x17': case '\x18': case '\x19': case '\x1a': \
101 case '\x1b': case '\x1c': case '\x1d': case '\x1e': \
102 case '\x1f': case '\x7f'
103#else
104 /* Use EBCDIC code page 1047's assignments for ASCII control chars;
105 assume all EBCDIC code pages agree about these assignments. */
106# define _C_CTYPE_OTHER_CNTRL \
107 case '\x00': case '\x01': case '\x02': case '\x03': \
108 case '\x07': case '\x0e': case '\x0f': case '\x10': \
109 case '\x11': case '\x12': case '\x13': case '\x18': \
110 case '\x19': case '\x1c': case '\x1d': case '\x1e': \
111 case '\x1f': case '\x26': case '\x27': case '\x2d': \
112 case '\x2e': case '\x32': case '\x37': case '\x3c': \
113 case '\x3d': case '\x3f'
114#endif
115
116/* Cases for lowercase hex letters, and lowercase letters, all offset by N. */
117
118#define _C_CTYPE_LOWER_A_THRU_F_N(N) \
119 case 'a' + (N): case 'b' + (N): case 'c' + (N): case 'd' + (N): \
120 case 'e' + (N): case 'f' + (N)
121#define _C_CTYPE_LOWER_N(N) \
122 _C_CTYPE_LOWER_A_THRU_F_N(N): \
123 case 'g' + (N): case 'h' + (N): case 'i' + (N): case 'j' + (N): \
124 case 'k' + (N): case 'l' + (N): case 'm' + (N): case 'n' + (N): \
125 case 'o' + (N): case 'p' + (N): case 'q' + (N): case 'r' + (N): \
126 case 's' + (N): case 't' + (N): case 'u' + (N): case 'v' + (N): \
127 case 'w' + (N): case 'x' + (N): case 'y' + (N): case 'z' + (N)
128
129/* Cases for hex letters, digits, lower, punct, and upper. */
130
131#define _C_CTYPE_A_THRU_F \
132 _C_CTYPE_LOWER_A_THRU_F_N (0): \
133 _C_CTYPE_LOWER_A_THRU_F_N ('A' - 'a')
134#define _C_CTYPE_DIGIT \
135 case '0': case '1': case '2': case '3': \
136 case '4': case '5': case '6': case '7': \
137 case '8': case '9'
138#define _C_CTYPE_LOWER _C_CTYPE_LOWER_N (0)
139#define _C_CTYPE_PUNCT \
140 case '!': case '"': case '#': case '$': \
141 case '%': case '&': case '\'': case '(': \
142 case ')': case '*': case '+': case ',': \
143 case '-': case '.': case '/': case ':': \
144 case ';': case '<': case '=': case '>': \
145 case '?': case '@': case '[': case '\\': \
146 case ']': case '^': case '_': case '`': \
147 case '{': case '|': case '}': case '~'
148#define _C_CTYPE_UPPER _C_CTYPE_LOWER_N ('A' - 'a')
149
150
151/* Function definitions. */
152
153/* Unlike the functions in <ctype.h>, which require an argument in the range
154 of the 'unsigned char' type, the functions here operate on values that are
155 in the 'unsigned char' range or in the 'char' range. In other words,
156 when you have a 'char' value, you need to cast it before using it as
157 argument to a <ctype.h> function:
158
159 const char *s = ...;
160 if (isalpha ((unsigned char) *s)) ...
161
162 but you don't need to cast it for the functions defined in this file:
163
164 const char *s = ...;
165 if (c_isalpha (*s)) ...
166 */
167
168C_CTYPE_INLINE bool
169c_isalnum (int c)
170{
171 switch (c)
172 {
173 _C_CTYPE_DIGIT:
174 _C_CTYPE_LOWER:
175 _C_CTYPE_UPPER:
176 return true;
177 default:
178 return false;
179 }
180}
181
182C_CTYPE_INLINE bool
183c_isalpha (int c)
184{
185 switch (c)
186 {
187 _C_CTYPE_LOWER:
188 _C_CTYPE_UPPER:
189 return true;
190 default:
191 return false;
192 }
193}
194
195/* The function isascii is not locale dependent.
196 Its use in EBCDIC is questionable. */
197C_CTYPE_INLINE bool
198c_isascii (int c)
199{
200 switch (c)
201 {
202 case ' ':
203 _C_CTYPE_CNTRL:
204 _C_CTYPE_DIGIT:
205 _C_CTYPE_LOWER:
206 _C_CTYPE_PUNCT:
207 _C_CTYPE_UPPER:
208 return true;
209 default:
210 return false;
211 }
212}
213
214C_CTYPE_INLINE bool
215c_isblank (int c)
216{
217 return c == ' ' || c == '\t';
218}
219
220C_CTYPE_INLINE bool
221c_iscntrl (int c)
222{
223 switch (c)
224 {
225 _C_CTYPE_CNTRL:
226 return true;
227 default:
228 return false;
229 }
230}
231
232C_CTYPE_INLINE bool
233c_isdigit (int c)
234{
235 switch (c)
236 {
237 _C_CTYPE_DIGIT:
238 return true;
239 default:
240 return false;
241 }
242}
243
244C_CTYPE_INLINE bool
245c_isgraph (int c)
246{
247 switch (c)
248 {
249 _C_CTYPE_DIGIT:
250 _C_CTYPE_LOWER:
251 _C_CTYPE_PUNCT:
252 _C_CTYPE_UPPER:
253 return true;
254 default:
255 return false;
256 }
257}
258
259C_CTYPE_INLINE bool
260c_islower (int c)
261{
262 switch (c)
263 {
264 _C_CTYPE_LOWER:
265 return true;
266 default:
267 return false;
268 }
269}
270
271C_CTYPE_INLINE bool
272c_isprint (int c)
273{
274 switch (c)
275 {
276 case ' ':
277 _C_CTYPE_DIGIT:
278 _C_CTYPE_LOWER:
279 _C_CTYPE_PUNCT:
280 _C_CTYPE_UPPER:
281 return true;
282 default:
283 return false;
284 }
285}
286
287C_CTYPE_INLINE bool
288c_ispunct (int c)
289{
290 switch (c)
291 {
292 _C_CTYPE_PUNCT:
293 return true;
294 default:
295 return false;
296 }
297}
298
299C_CTYPE_INLINE bool
300c_isspace (int c)
301{
302 switch (c)
303 {
304 case ' ': case '\t': case '\n': case '\v': case '\f': case '\r':
305 return true;
306 default:
307 return false;
308 }
309}
310
311C_CTYPE_INLINE bool
312c_isupper (int c)
313{
314 switch (c)
315 {
316 _C_CTYPE_UPPER:
317 return true;
318 default:
319 return false;
320 }
321}
322
323C_CTYPE_INLINE bool
324c_isxdigit (int c)
325{
326 switch (c)
327 {
328 _C_CTYPE_DIGIT:
329 _C_CTYPE_A_THRU_F:
330 return true;
331 default:
332 return false;
333 }
334}
335
336C_CTYPE_INLINE int
337c_tolower (int c)
338{
339 switch (c)
340 {
341 _C_CTYPE_UPPER:
342 return c - 'A' + 'a';
343 default:
344 return c;
345 }
346}
347
348C_CTYPE_INLINE int
349c_toupper (int c)
350{
351 switch (c)
352 {
353 _C_CTYPE_LOWER:
354 return c - 'a' + 'A';
355 default:
356 return c;
357 }
358}
359
360#ifdef __cplusplus
361}
362#endif
363
364_GL_INLINE_HEADER_END
365
366#endif /* C_CTYPE_H */
diff --git a/gl/c32is-impl.h b/gl/c32is-impl.h
new file mode 100644
index 00000000..8366035d
--- /dev/null
+++ b/gl/c32is-impl.h
@@ -0,0 +1,105 @@
1/* Test whether a 32-bit wide character belongs to a specific character class.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17/* Written by Bruno Haible <bruno@clisp.org>, 2020. */
18
19#include <wchar.h>
20#include <wctype.h>
21
22#ifdef __CYGWIN__
23# include <cygwin/version.h>
24#endif
25
26#if GNULIB_defined_mbstate_t
27# include "localcharset.h"
28# include "streq.h"
29#endif
30
31#if GL_CHAR32_T_IS_UNICODE
32# include "lc-charset-unicode.h"
33#endif
34
35#include "unictype.h"
36
37#if _GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t
38_GL_EXTERN_INLINE
39#endif
40int
41FUNC (wint_t wc)
42{
43 /* The char32_t encoding of a multibyte character is defined by the way
44 mbrtoc32() is defined. */
45
46#if GNULIB_defined_mbstate_t /* AIX, IRIX */
47 /* mbrtoc32() is defined on top of mbtowc() for the non-UTF-8 locales
48 and directly for the UTF-8 locales. */
49 if (wc != WEOF)
50 {
51 const char *encoding = locale_charset ();
52 if (STREQ_OPT (encoding, "UTF-8", 'U', 'T', 'F', '-', '8', 0, 0, 0, 0))
53 return UCS_FUNC (wc);
54 else
55 return WCHAR_FUNC (wc);
56 }
57 else
58 return 0;
59
60#elif HAVE_WORKING_MBRTOC32 && HAVE_WORKING_C32RTOMB /* glibc, Android */
61 /* mbrtoc32() is essentially defined by the system libc. */
62
63# if _GL_WCHAR_T_IS_UCS4
64 /* The char32_t encoding of a multibyte character is known to be the same as
65 the wchar_t encoding. */
66 return WCHAR_FUNC (wc);
67# else
68 /* The char32_t encoding of a multibyte character is known to be UCS-4,
69 different from the wchar_t encoding. */
70 if (wc != WEOF)
71 return UCS_FUNC (wc);
72 else
73 return 0;
74# endif
75
76#elif _GL_SMALL_WCHAR_T /* Cygwin, mingw, MSVC */
77 /* The wchar_t encoding is UTF-16.
78 The char32_t encoding is UCS-4. */
79
80# if defined __CYGWIN__ && CYGWIN_VERSION_DLL_MAJOR >= 1007
81 /* As an extension to POSIX, the iswalnum() function of Cygwin >= 1.7
82 supports also wc arguments outside the Unicode BMP, that is, outside
83 the 'wchar_t' range. See
84 <https://lists.gnu.org/archive/html/bug-gnulib/2011-02/msg00019.html>
85 = <https://cygwin.com/ml/cygwin/2011-02/msg00044.html>. */
86 return WCHAR_FUNC (wc);
87# else
88 if (wc == WEOF || wc == (wchar_t) wc)
89 /* wc is in the range for the isw* functions. */
90 return WCHAR_FUNC (wc);
91 else
92 return UCS_FUNC (wc);
93# endif
94
95#else /* macOS, FreeBSD, NetBSD, OpenBSD, HP-UX, Solaris, Minix, Android */
96 /* char32_t and wchar_t are equivalent. */
97 static_assert (sizeof (char32_t) == sizeof (wchar_t));
98
99# if GL_CHAR32_T_IS_UNICODE && GL_CHAR32_T_VS_WCHAR_T_NEEDS_CONVERSION
100 return UCS_FUNC (wc);
101# else
102 return WCHAR_FUNC (wc);
103# endif
104#endif
105}
diff --git a/gl/c32isalnum.c b/gl/c32isalnum.c
new file mode 100644
index 00000000..7d0ebcf5
--- /dev/null
+++ b/gl/c32isalnum.c
@@ -0,0 +1,26 @@
1/* Test 32-bit wide character for being alphanumeric.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19#define IN_C32ISALNUM
20/* Specification. */
21#include <uchar.h>
22
23#define FUNC c32isalnum
24#define WCHAR_FUNC iswalnum
25#define UCS_FUNC uc_is_alnum
26#include "c32is-impl.h"
diff --git a/gl/c32isalpha.c b/gl/c32isalpha.c
new file mode 100644
index 00000000..308fd76a
--- /dev/null
+++ b/gl/c32isalpha.c
@@ -0,0 +1,26 @@
1/* Test 32-bit wide character for being alphabetic.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19#define IN_C32ISALPHA
20/* Specification. */
21#include <uchar.h>
22
23#define FUNC c32isalpha
24#define WCHAR_FUNC iswalpha
25#define UCS_FUNC uc_is_alpha
26#include "c32is-impl.h"
diff --git a/gl/c32isblank.c b/gl/c32isblank.c
new file mode 100644
index 00000000..1a03c2db
--- /dev/null
+++ b/gl/c32isblank.c
@@ -0,0 +1,26 @@
1/* Test 32-bit wide character for being blank.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19#define IN_C32ISBLANK
20/* Specification. */
21#include <uchar.h>
22
23#define FUNC c32isblank
24#define WCHAR_FUNC iswblank
25#define UCS_FUNC uc_is_blank
26#include "c32is-impl.h"
diff --git a/gl/c32iscntrl.c b/gl/c32iscntrl.c
new file mode 100644
index 00000000..1d004087
--- /dev/null
+++ b/gl/c32iscntrl.c
@@ -0,0 +1,26 @@
1/* Test 32-bit wide character for being a control character.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19#define IN_C32ISCNTRL
20/* Specification. */
21#include <uchar.h>
22
23#define FUNC c32iscntrl
24#define WCHAR_FUNC iswcntrl
25#define UCS_FUNC uc_is_cntrl
26#include "c32is-impl.h"
diff --git a/gl/c32isdigit.c b/gl/c32isdigit.c
new file mode 100644
index 00000000..7d3bda81
--- /dev/null
+++ b/gl/c32isdigit.c
@@ -0,0 +1,26 @@
1/* Test 32-bit wide character for being a digit.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19#define IN_C32ISDIGIT
20/* Specification. */
21#include <uchar.h>
22
23#define FUNC c32isdigit
24#define WCHAR_FUNC iswdigit
25#define UCS_FUNC uc_is_digit
26#include "c32is-impl.h"
diff --git a/gl/c32isgraph.c b/gl/c32isgraph.c
new file mode 100644
index 00000000..8b68ae39
--- /dev/null
+++ b/gl/c32isgraph.c
@@ -0,0 +1,26 @@
1/* Test 32-bit wide character for being graphic.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19#define IN_C32ISGRAPH
20/* Specification. */
21#include <uchar.h>
22
23#define FUNC c32isgraph
24#define WCHAR_FUNC iswgraph
25#define UCS_FUNC uc_is_graph
26#include "c32is-impl.h"
diff --git a/gl/c32islower.c b/gl/c32islower.c
new file mode 100644
index 00000000..1ce08cf4
--- /dev/null
+++ b/gl/c32islower.c
@@ -0,0 +1,26 @@
1/* Test 32-bit wide character for being lowercase.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19#define IN_C32ISLOWER
20/* Specification. */
21#include <uchar.h>
22
23#define FUNC c32islower
24#define WCHAR_FUNC iswlower
25#define UCS_FUNC uc_is_lower
26#include "c32is-impl.h"
diff --git a/gl/c32isprint.c b/gl/c32isprint.c
new file mode 100644
index 00000000..d47ce1f8
--- /dev/null
+++ b/gl/c32isprint.c
@@ -0,0 +1,26 @@
1/* Test 32-bit wide character for being printable.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19#define IN_C32ISPRINT
20/* Specification. */
21#include <uchar.h>
22
23#define FUNC c32isprint
24#define WCHAR_FUNC iswprint
25#define UCS_FUNC uc_is_print
26#include "c32is-impl.h"
diff --git a/gl/c32ispunct.c b/gl/c32ispunct.c
new file mode 100644
index 00000000..41ac3d70
--- /dev/null
+++ b/gl/c32ispunct.c
@@ -0,0 +1,26 @@
1/* Test 32-bit wide character for being a punctuation or symbol character.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19#define IN_C32ISPUNCT
20/* Specification. */
21#include <uchar.h>
22
23#define FUNC c32ispunct
24#define WCHAR_FUNC iswpunct
25#define UCS_FUNC uc_is_punct
26#include "c32is-impl.h"
diff --git a/gl/c32isspace.c b/gl/c32isspace.c
new file mode 100644
index 00000000..2393142b
--- /dev/null
+++ b/gl/c32isspace.c
@@ -0,0 +1,26 @@
1/* Test 32-bit wide character for being white-space.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19#define IN_C32ISSPACE
20/* Specification. */
21#include <uchar.h>
22
23#define FUNC c32isspace
24#define WCHAR_FUNC iswspace
25#define UCS_FUNC uc_is_space
26#include "c32is-impl.h"
diff --git a/gl/c32isupper.c b/gl/c32isupper.c
new file mode 100644
index 00000000..bfe4a148
--- /dev/null
+++ b/gl/c32isupper.c
@@ -0,0 +1,26 @@
1/* Test 32-bit wide character for being uppercase.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19#define IN_C32ISUPPER
20/* Specification. */
21#include <uchar.h>
22
23#define FUNC c32isupper
24#define WCHAR_FUNC iswupper
25#define UCS_FUNC uc_is_upper
26#include "c32is-impl.h"
diff --git a/gl/c32isxdigit.c b/gl/c32isxdigit.c
new file mode 100644
index 00000000..b38d7f1f
--- /dev/null
+++ b/gl/c32isxdigit.c
@@ -0,0 +1,26 @@
1/* Test 32-bit wide character for being a hexadecimal digit.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19#define IN_C32ISXDIGIT
20/* Specification. */
21#include <uchar.h>
22
23#define FUNC c32isxdigit
24#define WCHAR_FUNC iswxdigit
25#define UCS_FUNC uc_is_xdigit
26#include "c32is-impl.h"
diff --git a/gl/c32to-impl.h b/gl/c32to-impl.h
new file mode 100644
index 00000000..a63a25b6
--- /dev/null
+++ b/gl/c32to-impl.h
@@ -0,0 +1,103 @@
1/* Case mapping of a 32-bit wide character.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17/* Written by Bruno Haible <bruno@clisp.org>, 2023. */
18
19#include <wchar.h>
20#include <wctype.h>
21
22#if GNULIB_defined_mbstate_t
23# include "localcharset.h"
24# include "streq.h"
25#endif
26
27#if GL_CHAR32_T_IS_UNICODE
28# include "lc-charset-unicode.h"
29#endif
30
31#include "unicase.h"
32
33#if _GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t
34_GL_EXTERN_INLINE
35#endif
36wint_t
37FUNC (wint_t wc)
38{
39 /* The char32_t encoding of a multibyte character is defined by the way
40 mbrtoc32() is defined. */
41
42#if GNULIB_defined_mbstate_t /* AIX, IRIX */
43 /* mbrtoc32() is defined on top of mbtowc() for the non-UTF-8 locales
44 and directly for the UTF-8 locales. */
45 if (wc != WEOF)
46 {
47 const char *encoding = locale_charset ();
48 if (STREQ_OPT (encoding, "UTF-8", 'U', 'T', 'F', '-', '8', 0, 0, 0, 0))
49 return UCS_FUNC (wc);
50 else
51 return WCHAR_FUNC (wc);
52 }
53 else
54 return wc;
55
56#elif HAVE_WORKING_MBRTOC32 && HAVE_WORKING_C32RTOMB /* glibc, Android */
57 /* mbrtoc32() is essentially defined by the system libc. */
58
59# if _GL_WCHAR_T_IS_UCS4
60 /* The char32_t encoding of a multibyte character is known to be the same as
61 the wchar_t encoding. */
62 return WCHAR_FUNC (wc);
63# else
64 /* The char32_t encoding of a multibyte character is known to be UCS-4,
65 different from the wchar_t encoding. */
66 if (wc != WEOF)
67 return UCS_FUNC (wc);
68 else
69 return wc;
70# endif
71
72#elif _GL_SMALL_WCHAR_T /* Cygwin, mingw, MSVC */
73 /* The wchar_t encoding is UTF-16.
74 The char32_t encoding is UCS-4. */
75
76# if defined _WIN32 && !defined __CYGWIN__
77 /* On native Windows, in the UTF-8 locale, towlower and towupper are
78 lacking (at least) the mappings for ISO-8859-1 characters, such as
79 0x00C9 <-> 0x00E9. Since it is expensive to test whether the locale
80 encoding is UTF-8, ignore the system's WCHAR_FUNC altogether. */
81 if (wc != WEOF)
82 return UCS_FUNC (wc);
83 else
84 return wc;
85# else
86 if (wc == WEOF || wc == (wchar_t) wc)
87 /* wc is in the range for the tow* functions. */
88 return WCHAR_FUNC (wc);
89 else
90 return UCS_FUNC (wc);
91# endif
92
93#else /* macOS, FreeBSD, NetBSD, OpenBSD, HP-UX, Solaris, Minix, Android */
94 /* char32_t and wchar_t are equivalent. */
95 static_assert (sizeof (char32_t) == sizeof (wchar_t));
96
97# if GL_CHAR32_T_IS_UNICODE && GL_CHAR32_T_VS_WCHAR_T_NEEDS_CONVERSION
98 return UCS_FUNC (wc);
99# else
100 return WCHAR_FUNC (wc);
101# endif
102#endif
103}
diff --git a/gl/c32tolower.c b/gl/c32tolower.c
new file mode 100644
index 00000000..a0b0523f
--- /dev/null
+++ b/gl/c32tolower.c
@@ -0,0 +1,26 @@
1/* Map a 32-bit wide character to lowercase.
2 Copyright (C) 2023-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19#define IN_C32TOLOWER
20/* Specification. */
21#include <uchar.h>
22
23#define FUNC c32tolower
24#define WCHAR_FUNC towlower
25#define UCS_FUNC uc_tolower
26#include "c32to-impl.h"
diff --git a/gl/c32width.c b/gl/c32width.c
new file mode 100644
index 00000000..442a432c
--- /dev/null
+++ b/gl/c32width.c
@@ -0,0 +1,102 @@
1/* Determine the number of screen columns needed for a 32-bit wide character.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17/* Written by Bruno Haible <bruno@clisp.org>, 2023. */
18
19#include <config.h>
20
21#define IN_C32WIDTH
22/* Specification. */
23#include <uchar.h>
24
25#include <wchar.h>
26
27#ifdef __CYGWIN__
28# include <cygwin/version.h>
29#endif
30
31#if GNULIB_defined_mbstate_t
32# include "streq.h"
33#endif
34
35#include "localcharset.h"
36
37#if GL_CHAR32_T_IS_UNICODE
38# include "lc-charset-unicode.h"
39#endif
40
41#include "uniwidth.h"
42
43#if _GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t
44_GL_EXTERN_INLINE
45#endif
46int
47c32width (char32_t wc)
48{
49 /* The char32_t encoding of a multibyte character is defined by the way
50 mbrtoc32() is defined. */
51
52#if GNULIB_defined_mbstate_t /* AIX, IRIX */
53 /* mbrtoc32() is defined on top of mbtowc() for the non-UTF-8 locales
54 and directly for the UTF-8 locales. */
55 const char *encoding = locale_charset ();
56 if (STREQ_OPT (encoding, "UTF-8", 'U', 'T', 'F', '-', '8', 0, 0, 0, 0))
57 return uc_width (wc, encoding);
58 else
59 return wcwidth (wc);
60
61#elif HAVE_WORKING_MBRTOC32 && HAVE_WORKING_C32RTOMB /* glibc, Android */
62 /* mbrtoc32() is essentially defined by the system libc. */
63
64# if _GL_WCHAR_T_IS_UCS4
65 /* The char32_t encoding of a multibyte character is known to be the same as
66 the wchar_t encoding. */
67 return wcwidth (wc);
68# else
69 /* The char32_t encoding of a multibyte character is known to be UCS-4,
70 different from the wchar_t encoding. */
71 return uc_width (wc, locale_charset ());
72# endif
73
74#elif _GL_SMALL_WCHAR_T /* Cygwin, mingw, MSVC */
75 /* The wchar_t encoding is UTF-16.
76 The char32_t encoding is UCS-4. */
77
78# if defined __CYGWIN__ && CYGWIN_VERSION_DLL_MAJOR >= 1007 && 0
79 /* As an extension to POSIX, the wcwidth() function of Cygwin >= 1.7
80 supports also wc arguments outside the Unicode BMP, that is, outside
81 the 'wchar_t' range. See
82 <https://www.cygwin.com/cgit/newlib-cygwin/commit/?id=098a75dc51caa98f369d98a9809d773bc45329aa>.
83 But the resulting values for these characters are not of good quality. */
84 return wcwidth (wc);
85# else
86 if (wc == (wchar_t) wc)
87 /* wc is in the range for the wcwidth function. */
88 return wcwidth (wc);
89 else
90 return uc_width (wc, locale_charset ());
91# endif
92
93#else /* macOS, FreeBSD, NetBSD, OpenBSD, HP-UX, Solaris, Minix, Android */
94 /* char32_t and wchar_t are equivalent. */
95 static_assert (sizeof (char32_t) == sizeof (wchar_t));
96
97# if GL_CHAR32_T_IS_UNICODE && GL_CHAR32_T_VS_WCHAR_T_NEEDS_CONVERSION
98 return uc_width (wc, locale_charset ());
99# endif
100 return wcwidth (wc);
101#endif
102}
diff --git a/gl/calloc.c b/gl/calloc.c
index 81dfd3ef..5258c5de 100644
--- a/gl/calloc.c
+++ b/gl/calloc.c
@@ -1,6 +1,6 @@
1/* calloc() function that is glibc compatible. 1/* calloc() function that is glibc compatible.
2 This wrapper function is required at least on Tru64 UNIX 5.1 and mingw. 2 This wrapper function is required at least on Tru64 UNIX 5.1 and mingw.
3 Copyright (C) 2004-2007, 2009-2024 Free Software Foundation, Inc. 3 Copyright (C) 2004-2007, 2009-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -17,17 +17,15 @@
17 17
18/* written by Jim Meyering and Bruno Haible */ 18/* written by Jim Meyering and Bruno Haible */
19 19
20/* Ensure that we call the system's calloc() below. */
21#define _GL_USE_STDLIB_ALLOC 1
20#include <config.h> 22#include <config.h>
21 23
22/* Specification. */ 24/* Specification. */
23#include <stdlib.h> 25#include <stdlib.h>
24 26
25#include <errno.h> 27#include <errno.h>
26 28#include <stdckdint.h>
27#include "xalloc-oversized.h"
28
29/* Call the system's calloc below. */
30#undef calloc
31 29
32/* Allocate and zero-fill an NxS-byte block of memory from the heap, 30/* Allocate and zero-fill an NxS-byte block of memory from the heap,
33 even if N or S is zero. */ 31 even if N or S is zero. */
@@ -35,14 +33,19 @@
35void * 33void *
36rpl_calloc (size_t n, size_t s) 34rpl_calloc (size_t n, size_t s)
37{ 35{
36#if !HAVE_MALLOC_0_NONNULL
38 if (n == 0 || s == 0) 37 if (n == 0 || s == 0)
39 n = s = 1; 38 n = s = 1;
39#endif
40 40
41 if (xalloc_oversized (n, s)) 41#if !HAVE_MALLOC_PTRDIFF
42 ptrdiff_t signed_n;
43 if (ckd_mul (&signed_n, n, s))
42 { 44 {
43 errno = ENOMEM; 45 errno = ENOMEM;
44 return NULL; 46 return NULL;
45 } 47 }
48#endif
46 49
47 void *result = calloc (n, s); 50 void *result = calloc (n, s);
48 51
diff --git a/gl/cdefs.h b/gl/cdefs.h
index d38382ad..dce5739d 100644
--- a/gl/cdefs.h
+++ b/gl/cdefs.h
@@ -1,4 +1,4 @@
1/* Copyright (C) 1992-2024 Free Software Foundation, Inc. 1/* Copyright (C) 1992-2025 Free Software Foundation, Inc.
2 Copyright The GNU Toolchain Authors. 2 Copyright The GNU Toolchain Authors.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 4
@@ -83,7 +83,7 @@
83# define __NTH(fct) __attribute__ ((__nothrow__ __LEAF)) fct 83# define __NTH(fct) __attribute__ ((__nothrow__ __LEAF)) fct
84# define __NTHNL(fct) __attribute__ ((__nothrow__)) fct 84# define __NTHNL(fct) __attribute__ ((__nothrow__)) fct
85# else 85# else
86# if defined __cplusplus && (__GNUC_PREREQ (2,8) || __clang_major >= 4) 86# if defined __cplusplus && (__GNUC_PREREQ (2,8) || __clang_major__ >= 4)
87# if __cplusplus >= 201103L 87# if __cplusplus >= 201103L
88# define __THROW noexcept (true) 88# define __THROW noexcept (true)
89# else 89# else
@@ -277,10 +277,10 @@
277*/ 277*/
278#endif 278#endif
279 279
280/* GCC and clang have various useful declarations that can be made with 280/* GCC, clang, and compatible compilers have various useful declarations
281 the '__attribute__' syntax. All of the ways we use this do fine if 281 that can be made with the '__attribute__' syntax. All of the ways we use
282 they are omitted for compilers that don't understand it. */ 282 this do fine if they are omitted for compilers that don't understand it. */
283#if !(defined __GNUC__ || defined __clang__) 283#if !(defined __GNUC__ || defined __clang__ || defined __TINYC__)
284# define __attribute__(xyz) /* Ignore */ 284# define __attribute__(xyz) /* Ignore */
285#endif 285#endif
286 286
@@ -482,7 +482,7 @@
482 run in pedantic mode if the uses are carefully marked using the 482 run in pedantic mode if the uses are carefully marked using the
483 `__extension__' keyword. But this is not generally available before 483 `__extension__' keyword. But this is not generally available before
484 version 2.8. */ 484 version 2.8. */
485#if !(__GNUC_PREREQ (2,8) || defined __clang__) 485#if ! (__GNUC_PREREQ (2,8) || defined __clang__ || 0x5150 <= __SUNPRO_C)
486# define __extension__ /* Ignore */ 486# define __extension__ /* Ignore */
487#endif 487#endif
488 488
@@ -497,7 +497,7 @@
497# endif 497# endif
498#endif 498#endif
499 499
500/* ISO C99 also allows to declare arrays as non-overlapping. The syntax is 500/* ISO C99 also allows declaring arrays as non-overlapping. The syntax is
501 array_name[restrict] 501 array_name[restrict]
502 GCC 3.1 and clang support this. 502 GCC 3.1 and clang support this.
503 This syntax is not usable in C++ mode. */ 503 This syntax is not usable in C++ mode. */
diff --git a/gl/cloexec.c b/gl/cloexec.c
index cdb0d740..8ab5591f 100644
--- a/gl/cloexec.c
+++ b/gl/cloexec.c
@@ -1,6 +1,6 @@
1/* cloexec.c - set or clear the close-on-exec descriptor flag 1/* cloexec.c - set or clear the close-on-exec descriptor flag
2 2
3 Copyright (C) 1991, 2004-2006, 2009-2024 Free Software Foundation, Inc. 3 Copyright (C) 1991, 2004-2006, 2009-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/cloexec.h b/gl/cloexec.h
index a7944d6d..0eb9fa09 100644
--- a/gl/cloexec.h
+++ b/gl/cloexec.h
@@ -1,6 +1,6 @@
1/* cloexec.c - set or clear the close-on-exec descriptor flag 1/* cloexec.c - set or clear the close-on-exec descriptor flag
2 2
3 Copyright (C) 2004, 2009-2024 Free Software Foundation, Inc. 3 Copyright (C) 2004, 2009-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/close.c b/gl/close.c
index 830fd820..3bcfc479 100644
--- a/gl/close.c
+++ b/gl/close.c
@@ -1,5 +1,5 @@
1/* close replacement. 1/* close replacement.
2 Copyright (C) 2008-2024 Free Software Foundation, Inc. 2 Copyright (C) 2008-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/dirname-lgpl.c b/gl/dirname-lgpl.c
index 8333c0eb..9e0ec565 100644
--- a/gl/dirname-lgpl.c
+++ b/gl/dirname-lgpl.c
@@ -1,6 +1,6 @@
1/* dirname.c -- return all but the last element in a file name 1/* dirname.c -- return all but the last element in a file name
2 2
3 Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2024 Free Software 3 Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2025 Free Software
4 Foundation, Inc. 4 Foundation, Inc.
5 5
6 This file is free software: you can redistribute it and/or modify 6 This file is free software: you can redistribute it and/or modify
diff --git a/gl/dirname.c b/gl/dirname.c
index 393ec1b4..e747fcaf 100644
--- a/gl/dirname.c
+++ b/gl/dirname.c
@@ -1,6 +1,6 @@
1/* dirname.c -- return all but the last element in a file name 1/* dirname.c -- return all but the last element in a file name
2 2
3 Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2024 Free Software 3 Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2025 Free Software
4 Foundation, Inc. 4 Foundation, Inc.
5 5
6 This program is free software: you can redistribute it and/or modify 6 This program is free software: you can redistribute it and/or modify
diff --git a/gl/dirname.h b/gl/dirname.h
index 33935ba9..d4d03f66 100644
--- a/gl/dirname.h
+++ b/gl/dirname.h
@@ -1,6 +1,6 @@
1/* Take file names apart into directory and base names. 1/* Take file names apart into directory and base names.
2 2
3 Copyright (C) 1998, 2001, 2003-2006, 2009-2024 Free Software Foundation, 3 Copyright (C) 1998, 2001, 2003-2006, 2009-2025 Free Software Foundation,
4 Inc. 4 Inc.
5 5
6 This file is free software: you can redistribute it and/or modify 6 This file is free software: you can redistribute it and/or modify
diff --git a/gl/dup2.c b/gl/dup2.c
index 916e113d..69b37196 100644
--- a/gl/dup2.c
+++ b/gl/dup2.c
@@ -1,6 +1,6 @@
1/* Duplicate an open file descriptor to a specified file descriptor. 1/* Duplicate an open file descriptor to a specified file descriptor.
2 2
3 Copyright (C) 1999, 2004-2007, 2009-2024 Free Software Foundation, Inc. 3 Copyright (C) 1999, 2004-2007, 2009-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/dynarray.h b/gl/dynarray.h
index 8940e81b..74471ea2 100644
--- a/gl/dynarray.h
+++ b/gl/dynarray.h
@@ -1,5 +1,5 @@
1/* Type-safe arrays which grow dynamically. 1/* Type-safe arrays which grow dynamically.
2 Copyright 2021-2024 Free Software Foundation, Inc. 2 Copyright 2021-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/errno.in.h b/gl/errno.in.h
index aa658e62..ba5dd371 100644
--- a/gl/errno.in.h
+++ b/gl/errno.in.h
@@ -1,6 +1,6 @@
1/* A POSIX-like <errno.h>. 1/* A POSIX-like <errno.h>.
2 2
3 Copyright (C) 2008-2024 Free Software Foundation, Inc. 3 Copyright (C) 2008-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -133,7 +133,7 @@
133 133
134/* These are intentionally the same values as the WSA* error numbers, defined 134/* These are intentionally the same values as the WSA* error numbers, defined
135 in <winsock2.h>. */ 135 in <winsock2.h>. */
136# define ESOCKTNOSUPPORT 10044 /* not required by POSIX */ 136# define ESOCKTNOSUPPORT 10044
137# define EPFNOSUPPORT 10046 /* not required by POSIX */ 137# define EPFNOSUPPORT 10046 /* not required by POSIX */
138# define ESHUTDOWN 10058 /* not required by POSIX */ 138# define ESHUTDOWN 10058 /* not required by POSIX */
139# define ETOOMANYREFS 10059 /* not required by POSIX */ 139# define ETOOMANYREFS 10059 /* not required by POSIX */
@@ -270,10 +270,17 @@
270# define GNULIB_defined_ENOTRECOVERABLE 1 270# define GNULIB_defined_ENOTRECOVERABLE 1
271# endif 271# endif
272 272
273/* On LynxOS, the macro EILSEQ is not defined. */
273# ifndef EILSEQ 274# ifndef EILSEQ
274# define EILSEQ 2015 275# define EILSEQ 2015
275# define GNULIB_defined_EILSEQ 1 276# define GNULIB_defined_EILSEQ 1
276# endif 277# endif
277 278
279/* On Haiku, the macro ESOCKTNOSUPPORT is not defined. */
280# ifndef ESOCKTNOSUPPORT
281# define ESOCKTNOSUPPORT 2016
282# define GNULIB_defined_ESOCKTNOSUPPORT 1
283# endif
284
278#endif /* _@GUARD_PREFIX@_ERRNO_H */ 285#endif /* _@GUARD_PREFIX@_ERRNO_H */
279#endif /* _@GUARD_PREFIX@_ERRNO_H */ 286#endif /* _@GUARD_PREFIX@_ERRNO_H */
diff --git a/gl/error.c b/gl/error.c
index c53dfeb6..9231c79c 100644
--- a/gl/error.c
+++ b/gl/error.c
@@ -1,25 +1,32 @@
1/* Error handler for noninteractive utilities 1/* Error handler for noninteractive utilities
2 Copyright (C) 1990-1998, 2000-2007, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 1990-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 4
5 This file is free software: you can redistribute it and/or modify 5 The GNU C Library is free software; you can redistribute it and/or
6 it under the terms of the GNU Lesser General Public License as 6 modify it under the terms of the GNU Lesser General Public
7 published by the Free Software Foundation; either version 2.1 of the 7 License as published by the Free Software Foundation; either
8 License, or (at your option) any later version. 8 version 2.1 of the License, or (at your option) any later version.
9 9
10 This file is distributed in the hope that it will be useful, 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 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 GNU Lesser General Public License for more details. 13 Lesser General Public License for more details.
14 14
15 You should have received a copy of the GNU Lesser General Public License 15 You should have received a copy of the GNU Lesser General Public
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
17 18
18/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */ 19/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
19 20
20#if !_LIBC 21#if !_LIBC
21# include <config.h> 22# include <config.h>
22# define _GL_NO_INLINE_ERROR 23# define _GL_NO_INLINE_ERROR
24# define __error_internal(status, err, fmt, args, flags) \
25 verror (status, err, fmt, args)
26# define __error_at_line_internal(status, err, file, line, fmt, args, flags) \
27 verror_at_line (status, err, file, line, fmt, args)
28# define error_tail(status, err, fmt, args, flags) \
29 error_tail (status, err, fmt, args)
23#endif 30#endif
24 31
25#include <error.h> 32#include <error.h>
@@ -31,7 +38,7 @@
31 38
32#if !_LIBC && ENABLE_NLS 39#if !_LIBC && ENABLE_NLS
33# include "gettext.h" 40# include "gettext.h"
34# define _(msgid) gettext (msgid) 41# define _(msgid) dgettext ("gnulib", msgid)
35#endif 42#endif
36 43
37#ifdef _LIBC 44#ifdef _LIBC
@@ -85,7 +92,7 @@ extern void __error_at_line (int status, int errnum, const char *file_name,
85# undef putc 92# undef putc
86# define putc(c, fp) _IO_putc (c, fp) 93# define putc(c, fp) _IO_putc (c, fp)
87 94
88# include <bits/libc-lock.h> 95# include <libc-lock.h>
89 96
90#else /* not _LIBC */ 97#else /* not _LIBC */
91 98
@@ -123,6 +130,13 @@ int strerror_r (int errnum, char *buf, size_t buflen);
123# if GNULIB_STRERROR_R_POSIX || HAVE_STRERROR_R || defined strerror_r 130# if GNULIB_STRERROR_R_POSIX || HAVE_STRERROR_R || defined strerror_r
124# define __strerror_r strerror_r 131# define __strerror_r strerror_r
125# endif /* GNULIB_STRERROR_R_POSIX || HAVE_STRERROR_R || defined strerror_r */ 132# endif /* GNULIB_STRERROR_R_POSIX || HAVE_STRERROR_R || defined strerror_r */
133
134# if GNULIB_defined_verror
135# undef verror
136# endif
137# if GNULIB_defined_verror_at_line
138# undef verror_at_line
139# endif
126#endif /* not _LIBC */ 140#endif /* not _LIBC */
127 141
128#if !_LIBC 142#if !_LIBC
@@ -151,8 +165,8 @@ flush_stdout (void)
151#if !_LIBC 165#if !_LIBC
152 int stdout_fd; 166 int stdout_fd;
153 167
154# if GNULIB_FREOPEN_SAFER 168# if GNULIB_FREOPEN_SAFER || GNULIB_XSTDOPEN
155 /* Use of gnulib's freopen-safer module normally ensures that 169 /* Gnulib's freopen-safer and/or xstdopen modules normally ensure that
156 fileno (stdout) == 1 170 fileno (stdout) == 1
157 whenever stdout is open. */ 171 whenever stdout is open. */
158 stdout_fd = STDOUT_FILENO; 172 stdout_fd = STDOUT_FILENO;
@@ -183,7 +197,7 @@ print_errno_message (int errnum)
183 if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0) 197 if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0)
184 s = errbuf; 198 s = errbuf;
185 else 199 else
186 s = 0; 200 s = NULL;
187# endif 201# endif
188#else 202#else
189 s = strerror (errnum); 203 s = strerror (errnum);
@@ -202,75 +216,18 @@ print_errno_message (int errnum)
202} 216}
203 217
204static void _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 0) _GL_ARG_NONNULL ((3)) 218static void _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 0) _GL_ARG_NONNULL ((3))
205error_tail (int status, int errnum, const char *message, va_list args) 219error_tail (int status, int errnum, const char *message, va_list args,
220 unsigned int mode_flags)
206{ 221{
207#if _LIBC 222#if _LIBC
208 if (_IO_fwide (stderr, 0) > 0) 223 int ret = __vfxprintf (stderr, message, args, mode_flags);
209 { 224 if (ret < 0 && errno == ENOMEM && _IO_fwide (stderr, 0) > 0)
210 size_t len = strlen (message) + 1; 225 /* Leave a trace in case the heap allocation of the message string
211 wchar_t *wmessage = NULL; 226 failed. */
212 mbstate_t st; 227 fputws_unlocked (L"out of memory\n", stderr);
213 size_t res; 228#else
214 const char *tmp; 229 vfprintf (stderr, message, args);
215 bool use_malloc = false;
216
217 while (1)
218 {
219 if (__libc_use_alloca (len * sizeof (wchar_t)))
220 wmessage = (wchar_t *) alloca (len * sizeof (wchar_t));
221 else
222 {
223 if (!use_malloc)
224 wmessage = NULL;
225
226 wchar_t *p = (wchar_t *) realloc (wmessage,
227 len * sizeof (wchar_t));
228 if (p == NULL)
229 {
230 free (wmessage);
231 fputws_unlocked (L"out of memory\n", stderr);
232 return;
233 }
234 wmessage = p;
235 use_malloc = true;
236 }
237
238 memset (&st, '\0', sizeof (st));
239 tmp = message;
240
241 res = mbsrtowcs (wmessage, &tmp, len, &st);
242 if (res != len)
243 break;
244
245 if (__builtin_expect (len >= SIZE_MAX / sizeof (wchar_t) / 2, 0))
246 {
247 /* This really should not happen if everything is fine. */
248 res = (size_t) -1;
249 break;
250 }
251
252 len *= 2;
253 }
254
255 if (res == (size_t) -1)
256 {
257 /* The string cannot be converted. */
258 if (use_malloc)
259 {
260 free (wmessage);
261 use_malloc = false;
262 }
263 wmessage = (wchar_t *) L"???";
264 }
265
266 __vfwprintf (stderr, wmessage, args);
267
268 if (use_malloc)
269 free (wmessage);
270 }
271 else
272#endif 230#endif
273 vfprintf (stderr, message, args);
274 231
275 ++error_message_count; 232 ++error_message_count;
276 if (errnum) 233 if (errnum)
@@ -291,16 +248,14 @@ error_tail (int status, int errnum, const char *message, va_list args)
291 If ERRNUM is nonzero, print its corresponding system error message. 248 If ERRNUM is nonzero, print its corresponding system error message.
292 Exit with status STATUS if it is nonzero. */ 249 Exit with status STATUS if it is nonzero. */
293void 250void
294error (int status, int errnum, const char *message, ...) 251__error_internal (int status, int errnum, const char *message,
252 va_list args, unsigned int mode_flags)
295{ 253{
296 va_list args; 254#if defined _LIBC
297
298#if defined _LIBC && defined __libc_ptf_call
299 /* We do not want this call to be cut short by a thread 255 /* We do not want this call to be cut short by a thread
300 cancellation. Therefore disable cancellation for now. */ 256 cancellation. Therefore disable cancellation for now. */
301 int state = PTHREAD_CANCEL_ENABLE; 257 int state = PTHREAD_CANCEL_ENABLE;
302 __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), 258 __pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state);
303 0);
304#endif 259#endif
305 260
306 flush_stdout (); 261 flush_stdout ();
@@ -318,28 +273,32 @@ error (int status, int errnum, const char *message, ...)
318#endif 273#endif
319 } 274 }
320 275
321 va_start (args, message); 276 error_tail (status, errnum, message, args, mode_flags);
322 error_tail (status, errnum, message, args);
323 va_end (args);
324 277
325#ifdef _LIBC 278#ifdef _LIBC
326 _IO_funlockfile (stderr); 279 _IO_funlockfile (stderr);
327# ifdef __libc_ptf_call 280 __pthread_setcancelstate (state, NULL);
328 __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
329# endif
330#endif 281#endif
331} 282}
283
284void
285error (int status, int errnum, const char *message, ...)
286{
287 va_list ap;
288 va_start (ap, message);
289 __error_internal (status, errnum, message, ap, 0);
290 va_end (ap);
291}
332 292
333/* Sometimes we want to have at most one error per line. This 293/* Sometimes we want to have at most one error per line. This
334 variable controls whether this mode is selected or not. */ 294 variable controls whether this mode is selected or not. */
335int error_one_per_line; 295int error_one_per_line;
336 296
337void 297void
338error_at_line (int status, int errnum, const char *file_name, 298__error_at_line_internal (int status, int errnum, const char *file_name,
339 unsigned int line_number, const char *message, ...) 299 unsigned int line_number, const char *message,
300 va_list args, unsigned int mode_flags)
340{ 301{
341 va_list args;
342
343 if (error_one_per_line) 302 if (error_one_per_line)
344 { 303 {
345 static const char *old_file_name; 304 static const char *old_file_name;
@@ -358,12 +317,11 @@ error_at_line (int status, int errnum, const char *file_name,
358 old_line_number = line_number; 317 old_line_number = line_number;
359 } 318 }
360 319
361#if defined _LIBC && defined __libc_ptf_call 320#if defined _LIBC
362 /* We do not want this call to be cut short by a thread 321 /* We do not want this call to be cut short by a thread
363 cancellation. Therefore disable cancellation for now. */ 322 cancellation. Therefore disable cancellation for now. */
364 int state = PTHREAD_CANCEL_ENABLE; 323 int state = PTHREAD_CANCEL_ENABLE;
365 __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), 324 __pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state);
366 0);
367#endif 325#endif
368 326
369 flush_stdout (); 327 flush_stdout ();
@@ -389,18 +347,25 @@ error_at_line (int status, int errnum, const char *file_name,
389 file_name, line_number); 347 file_name, line_number);
390#endif 348#endif
391 349
392 va_start (args, message); 350 error_tail (status, errnum, message, args, mode_flags);
393 error_tail (status, errnum, message, args);
394 va_end (args);
395 351
396#ifdef _LIBC 352#ifdef _LIBC
397 _IO_funlockfile (stderr); 353 _IO_funlockfile (stderr);
398# ifdef __libc_ptf_call 354 __pthread_setcancelstate (state, NULL);
399 __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
400# endif
401#endif 355#endif
402} 356}
403 357
358void
359error_at_line (int status, int errnum, const char *file_name,
360 unsigned int line_number, const char *message, ...)
361{
362 va_list ap;
363 va_start (ap, message);
364 __error_at_line_internal (status, errnum, file_name, line_number,
365 message, ap, 0);
366 va_end (ap);
367}
368
404#ifdef _LIBC 369#ifdef _LIBC
405/* Make the weak alias. */ 370/* Make the weak alias. */
406# undef error 371# undef error
diff --git a/gl/error.in.h b/gl/error.in.h
index 51f8cafd..6c512ec8 100644
--- a/gl/error.in.h
+++ b/gl/error.in.h
@@ -1,5 +1,5 @@
1/* Declarations for error-reporting functions. 1/* Declarations for error-reporting functions.
2 Copyright (C) 1995-1997, 2003, 2006, 2008-2024 Free Software Foundation, 2 Copyright (C) 1995-1997, 2003, 2006, 2008-2025 Free Software Foundation,
3 Inc. 3 Inc.
4 This file is part of the GNU C Library. 4 This file is part of the GNU C Library.
5 5
@@ -23,20 +23,23 @@
23 or error_at_line(...) invocations. */ 23 or error_at_line(...) invocations. */
24 24
25/* The include_next requires a split double-inclusion guard. */ 25/* The include_next requires a split double-inclusion guard. */
26#if @HAVE_ERROR_H@ 26#if @HAVE_ERROR_H@ && !defined __MINGW32__
27# @INCLUDE_NEXT@ @NEXT_ERROR_H@ 27# @INCLUDE_NEXT@ @NEXT_ERROR_H@
28#endif 28#endif
29 29
30#ifndef _@GUARD_PREFIX@_ERROR_H 30#ifndef _@GUARD_PREFIX@_ERROR_H
31#define _@GUARD_PREFIX@_ERROR_H 31#define _@GUARD_PREFIX@_ERROR_H
32 32
33/* This file uses _GL_ATTRIBUTE_ALWAYS_INLINE, _GL_ATTRIBUTE_FORMAT, 33/* This file uses _GL_ATTRIBUTE_ALWAYS_INLINE, _GL_ATTRIBUTE_COLD,
34 _GL_ATTRIBUTE_MAYBE_UNUSED. */ 34 _GL_ATTRIBUTE_FORMAT, _GL_ATTRIBUTE_MAYBE_UNUSED. */
35#if !_GL_CONFIG_H_INCLUDED 35#if !_GL_CONFIG_H_INCLUDED
36 #error "Please include config.h first." 36 #error "Please include config.h first."
37#endif 37#endif
38 38
39/* Get 'unreachable'. */ 39/* Get va_list. */
40#include <stdarg.h>
41
42/* Get 'gl_unreachable'. */
40#include <stddef.h> 43#include <stddef.h>
41 44
42/* Get _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, _GL_ATTRIBUTE_SPEC_PRINTF_SYSTEM. */ 45/* Get _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, _GL_ATTRIBUTE_SPEC_PRINTF_SYSTEM. */
@@ -54,11 +57,11 @@
54 It evaluates its arguments only once. 57 It evaluates its arguments only once.
55 Test case: Compile copy-file.c with "gcc -Wimplicit-fallthrough". */ 58 Test case: Compile copy-file.c with "gcc -Wimplicit-fallthrough". */
56#if defined __GNUC__ || defined __clang__ 59#if defined __GNUC__ || defined __clang__
57/* Use 'unreachable' to tell the compiler when the function call does not 60/* Use 'gl_unreachable' to tell the compiler when the function call does not
58 return. */ 61 return. */
59# define __gl_error_call1(function, status, ...) \ 62# define __gl_error_call1(function, status, ...) \
60 ((function) (status, __VA_ARGS__), \ 63 ((function) (status, __VA_ARGS__), \
61 (status) != 0 ? unreachable () : (void) 0) 64 (status) != 0 ? gl_unreachable () : (void) 0)
62/* If STATUS is a not a constant, the function call may or may not return; 65/* If STATUS is a not a constant, the function call may or may not return;
63 therefore -Wimplicit-fallthrough will produce a warning. Use a compound 66 therefore -Wimplicit-fallthrough will produce a warning. Use a compound
64 statement in order to evaluate STATUS only once. 67 statement in order to evaluate STATUS only once.
@@ -92,7 +95,8 @@ extern "C" {
92# define error rpl_error 95# define error rpl_error
93# endif 96# endif
94_GL_FUNCDECL_RPL (error, void, 97_GL_FUNCDECL_RPL (error, void,
95 (int __status, int __errnum, const char *__format, ...) 98 (int __status, int __errnum, const char *__format, ...),
99 _GL_ATTRIBUTE_COLD
96 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 3, 4))); 100 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 3, 4)));
97_GL_CXXALIAS_RPL (error, void, 101_GL_CXXALIAS_RPL (error, void,
98 (int __status, int __errnum, const char *__format, ...)); 102 (int __status, int __errnum, const char *__format, ...));
@@ -104,7 +108,8 @@ _GL_CXXALIAS_RPL (error, void,
104#else 108#else
105# if ! @HAVE_ERROR@ 109# if ! @HAVE_ERROR@
106_GL_FUNCDECL_SYS (error, void, 110_GL_FUNCDECL_SYS (error, void,
107 (int __status, int __errnum, const char *__format, ...) 111 (int __status, int __errnum, const char *__format, ...),
112 _GL_ATTRIBUTE_COLD
108 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 3, 4))); 113 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 3, 4)));
109# endif 114# endif
110_GL_CXXALIAS_SYS (error, void, 115_GL_CXXALIAS_SYS (error, void,
@@ -117,7 +122,7 @@ _GL_CXXALIAS_SYS (error, void,
117# pragma GCC diagnostic ignored "-Wattributes" 122# pragma GCC diagnostic ignored "-Wattributes"
118_GL_ATTRIBUTE_MAYBE_UNUSED 123_GL_ATTRIBUTE_MAYBE_UNUSED
119static void 124static void
120_GL_ATTRIBUTE_ALWAYS_INLINE 125_GL_ATTRIBUTE_ALWAYS_INLINE _GL_ATTRIBUTE_COLD
121_GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 3, 4)) 126_GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 3, 4))
122_gl_inline_error (int __status, int __errnum, const char *__format, ...) 127_gl_inline_error (int __status, int __errnum, const char *__format, ...)
123{ 128{
@@ -147,7 +152,8 @@ _GL_CXXALIASWARN (error);
147# endif 152# endif
148_GL_FUNCDECL_RPL (error_at_line, void, 153_GL_FUNCDECL_RPL (error_at_line, void,
149 (int __status, int __errnum, const char *__filename, 154 (int __status, int __errnum, const char *__filename,
150 unsigned int __lineno, const char *__format, ...) 155 unsigned int __lineno, const char *__format, ...),
156 _GL_ATTRIBUTE_COLD
151 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 5, 6))); 157 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 5, 6)));
152_GL_CXXALIAS_RPL (error_at_line, void, 158_GL_CXXALIAS_RPL (error_at_line, void,
153 (int __status, int __errnum, const char *__filename, 159 (int __status, int __errnum, const char *__filename,
@@ -161,7 +167,8 @@ _GL_CXXALIAS_RPL (error_at_line, void,
161# if ! @HAVE_ERROR_AT_LINE@ 167# if ! @HAVE_ERROR_AT_LINE@
162_GL_FUNCDECL_SYS (error_at_line, void, 168_GL_FUNCDECL_SYS (error_at_line, void,
163 (int __status, int __errnum, const char *__filename, 169 (int __status, int __errnum, const char *__filename,
164 unsigned int __lineno, const char *__format, ...) 170 unsigned int __lineno, const char *__format, ...),
171 _GL_ATTRIBUTE_COLD
165 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 5, 6))); 172 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 5, 6)));
166# endif 173# endif
167_GL_CXXALIAS_SYS (error_at_line, void, 174_GL_CXXALIAS_SYS (error_at_line, void,
@@ -175,7 +182,7 @@ _GL_CXXALIAS_SYS (error_at_line, void,
175# pragma GCC diagnostic ignored "-Wattributes" 182# pragma GCC diagnostic ignored "-Wattributes"
176_GL_ATTRIBUTE_MAYBE_UNUSED 183_GL_ATTRIBUTE_MAYBE_UNUSED
177static void 184static void
178_GL_ATTRIBUTE_ALWAYS_INLINE 185_GL_ATTRIBUTE_ALWAYS_INLINE _GL_ATTRIBUTE_COLD
179_GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 5, 6)) 186_GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 5, 6))
180_gl_inline_error_at_line (int __status, int __errnum, const char *__filename, 187_gl_inline_error_at_line (int __status, int __errnum, const char *__filename,
181 unsigned int __lineno, const char *__format, ...) 188 unsigned int __lineno, const char *__format, ...)
@@ -196,6 +203,44 @@ _gl_inline_error_at_line (int __status, int __errnum, const char *__filename,
196#endif 203#endif
197_GL_CXXALIASWARN (error_at_line); 204_GL_CXXALIASWARN (error_at_line);
198 205
206/* Print a message with 'vfprintf (stderr, FORMAT, ARGS)';
207 if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
208 If STATUS is nonzero, terminate the program with 'exit (STATUS)'.
209 Use the globals error_print_progname and error_message_count similarly
210 to error(). */
211
212extern void verror (int __status, int __errnum, const char *__format,
213 va_list __args)
214 _GL_ATTRIBUTE_COLD
215 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 3, 0));
216#ifndef _GL_NO_INLINE_ERROR
217# ifndef verror
218# define verror(status, ...) \
219 __gl_error_call (verror, status, __VA_ARGS__)
220# define GNULIB_defined_verror 1
221# endif
222#endif
223
224/* Print a message with 'vfprintf (stderr, FORMAT, ARGS)';
225 if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
226 If STATUS is nonzero, terminate the program with 'exit (STATUS)'.
227 If FNAME is not NULL, prepend the message with "FNAME:LINENO:".
228 Use the globals error_print_progname, error_message_count, and
229 error_one_per_line similarly to error_at_line(). */
230
231extern void verror_at_line (int __status, int __errnum, const char *__fname,
232 unsigned int __lineno, const char *__format,
233 va_list __args)
234 _GL_ATTRIBUTE_COLD
235 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 5, 0));
236#ifdef _GL_NO_INLINE_ERROR
237# ifndef verror_at_line
238# define verror_at_line(status, ...) \
239 __gl_error_call (verror_at_line, status, __VA_ARGS__)
240# define GNULIB_defined_verror_at_line 1
241# endif
242#endif
243
199/* If NULL, error will flush stdout, then print on stderr the program 244/* If NULL, error will flush stdout, then print on stderr the program
200 name, a colon and a space. Otherwise, error will call this 245 name, a colon and a space. Otherwise, error will call this
201 function without parameters instead. */ 246 function without parameters instead. */
diff --git a/gl/exitfail.c b/gl/exitfail.c
index 8a5962e8..5b37c10b 100644
--- a/gl/exitfail.c
+++ b/gl/exitfail.c
@@ -1,6 +1,6 @@
1/* Failure exit status 1/* Failure exit status
2 2
3 Copyright (C) 2002-2003, 2005-2007, 2009-2024 Free Software Foundation, Inc. 3 Copyright (C) 2002-2003, 2005-2007, 2009-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/exitfail.h b/gl/exitfail.h
index fa264b5c..9d6b1528 100644
--- a/gl/exitfail.h
+++ b/gl/exitfail.h
@@ -1,6 +1,6 @@
1/* Failure exit status 1/* Failure exit status
2 2
3 Copyright (C) 2002, 2009-2024 Free Software Foundation, Inc. 3 Copyright (C) 2002, 2009-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/fcntl.c b/gl/fcntl.c
index 7cd3a0f9..ecb18e50 100644
--- a/gl/fcntl.c
+++ b/gl/fcntl.c
@@ -1,6 +1,6 @@
1/* Provide file descriptor control. 1/* Provide file descriptor control.
2 2
3 Copyright (C) 2009-2024 Free Software Foundation, Inc. 3 Copyright (C) 2009-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -29,8 +29,7 @@
29#include <unistd.h> 29#include <unistd.h>
30 30
31#ifdef __KLIBC__ 31#ifdef __KLIBC__
32# define INCL_DOS 32# include <emx/io.h>
33# include <os2.h>
34#endif 33#endif
35 34
36#if defined _WIN32 && ! defined __CYGWIN__ 35#if defined _WIN32 && ! defined __CYGWIN__
@@ -562,7 +561,8 @@ klibc_fcntl (int fd, int action, /* arg */...)
562 if (result == -1 && (errno == EPERM || errno == ENOTSUP) 561 if (result == -1 && (errno == EPERM || errno == ENOTSUP)
563 && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode)) 562 && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
564 { 563 {
565 ULONG ulMode; 564 PLIBCFH pFH;
565 unsigned fFlags;
566 566
567 switch (action) 567 switch (action)
568 { 568 {
@@ -574,34 +574,41 @@ klibc_fcntl (int fd, int action, /* arg */...)
574 result = dup2 (fd, arg); 574 result = dup2 (fd, arg);
575 break; 575 break;
576 576
577 /* Using underlying APIs is right ? */
578 case F_GETFD: 577 case F_GETFD:
579 if (DosQueryFHState (fd, &ulMode)) 578 pFH = __libc_FH (fd);
580 break; 579 if (!pFH)
580 {
581 errno = EBADF;
582 break;
583 }
581 584
582 result = (ulMode & OPEN_FLAGS_NOINHERIT) ? FD_CLOEXEC : 0; 585 result = (pFH->fFlags & ((FD_CLOEXEC << __LIBC_FH_FDFLAGS_SHIFT )
586 | O_NOINHERIT)) ? FD_CLOEXEC : 0;
583 break; 587 break;
584 588
585 case F_SETFD: 589 case F_SETFD:
586 if (arg & ~FD_CLOEXEC) 590 if (arg & ~FD_CLOEXEC)
587 break; 591 break;
588 592
589 if (DosQueryFHState (fd, &ulMode)) 593 pFH = __libc_FH (fd);
590 break; 594 if (!pFH)
595 {
596 errno = EBADF;
597 break;
598 }
591 599
600 fFlags = pFH->fFlags;
592 if (arg & FD_CLOEXEC) 601 if (arg & FD_CLOEXEC)
593 ulMode |= OPEN_FLAGS_NOINHERIT; 602 fFlags |= (FD_CLOEXEC << __LIBC_FH_FDFLAGS_SHIFT) | O_NOINHERIT;
594 else 603 else
595 ulMode &= ~OPEN_FLAGS_NOINHERIT; 604 fFlags &= ~((FD_CLOEXEC << __LIBC_FH_FDFLAGS_SHIFT) | O_NOINHERIT);
596
597 /* Filter supported flags. */
598 ulMode &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR
599 | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT);
600 605
601 if (DosSetFHState (fd, ulMode)) 606 result = __libc_FHSetFlags (pFH, fd, fFlags);
602 break; 607 if (result < 0)
603 608 {
604 result = 0; 609 errno = -result;
610 result = -1;
611 }
605 break; 612 break;
606 613
607 case F_GETFL: 614 case F_GETFL:
diff --git a/gl/fcntl.in.h b/gl/fcntl.in.h
index eea3b954..c5068ed4 100644
--- a/gl/fcntl.in.h
+++ b/gl/fcntl.in.h
@@ -1,6 +1,6 @@
1/* Like <fcntl.h>, but with non-working flags defined to 0. 1/* Like <fcntl.h>, but with non-working flags defined to 0.
2 2
3 Copyright (C) 2006-2024 Free Software Foundation, Inc. 3 Copyright (C) 2006-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -22,8 +22,12 @@
22#endif 22#endif
23@PRAGMA_COLUMNS@ 23@PRAGMA_COLUMNS@
24 24
25#if defined __need_system_fcntl_h 25#if defined __need_system_fcntl_h || defined _@GUARD_PREFIX@_ALREADY_INCLUDING_FCNTL_H
26/* Special invocation convention. */ 26/* Special invocation convention:
27 - On Haiku we have a sequence of nested includes
28 <fcntl.h> -> <unistd.h> -> <fcntl.h>
29 In this situation, GNULIB_defined_O_NONBLOCK gets defined before the
30 system's definition of O_NONBLOCK is processed. */
27 31
28/* Needed before <sys/stat.h>. 32/* Needed before <sys/stat.h>.
29 May also define off_t to a 64-bit type on native Windows. */ 33 May also define off_t to a 64-bit type on native Windows. */
@@ -50,8 +54,11 @@
50 54
51#ifndef _@GUARD_PREFIX@_FCNTL_H 55#ifndef _@GUARD_PREFIX@_FCNTL_H
52 56
57#define _@GUARD_PREFIX@_ALREADY_INCLUDING_FCNTL_H
58
53/* Needed before <sys/stat.h>. 59/* Needed before <sys/stat.h>.
54 May also define off_t to a 64-bit type on native Windows. */ 60 May also define off_t to a 64-bit type on native Windows.
61 Also defines off64_t on macOS, NetBSD, OpenBSD, MSVC, Cygwin, Haiku. */
55#include <sys/types.h> 62#include <sys/types.h>
56/* On some systems other than glibc, <sys/stat.h> is a prerequisite of 63/* On some systems other than glibc, <sys/stat.h> is a prerequisite of
57 <fcntl.h>. On glibc systems, we would like to avoid namespace pollution. 64 <fcntl.h>. On glibc systems, we would like to avoid namespace pollution.
@@ -71,6 +78,8 @@
71# include <io.h> 78# include <io.h>
72#endif 79#endif
73 80
81#undef _@GUARD_PREFIX@_ALREADY_INCLUDING_FCNTL_H
82
74#ifndef _@GUARD_PREFIX@_FCNTL_H 83#ifndef _@GUARD_PREFIX@_FCNTL_H
75#define _@GUARD_PREFIX@_FCNTL_H 84#define _@GUARD_PREFIX@_FCNTL_H
76 85
@@ -99,7 +108,7 @@
99# undef creat 108# undef creat
100# define creat rpl_creat 109# define creat rpl_creat
101# endif 110# endif
102_GL_FUNCDECL_RPL (creat, int, (const char *filename, mode_t mode) 111_GL_FUNCDECL_RPL (creat, int, (const char *filename, mode_t mode),
103 _GL_ARG_NONNULL ((1))); 112 _GL_ARG_NONNULL ((1)));
104_GL_CXXALIAS_RPL (creat, int, (const char *filename, mode_t mode)); 113_GL_CXXALIAS_RPL (creat, int, (const char *filename, mode_t mode));
105# elif defined _WIN32 && !defined __CYGWIN__ 114# elif defined _WIN32 && !defined __CYGWIN__
@@ -140,14 +149,14 @@ _GL_CXXALIASWARN (creat);
140# undef fcntl 149# undef fcntl
141# define fcntl rpl_fcntl 150# define fcntl rpl_fcntl
142# endif 151# endif
143_GL_FUNCDECL_RPL (fcntl, int, (int fd, int action, ...)); 152_GL_FUNCDECL_RPL (fcntl, int, (int fd, int action, ...), );
144_GL_CXXALIAS_RPL (fcntl, int, (int fd, int action, ...)); 153_GL_CXXALIAS_RPL (fcntl, int, (int fd, int action, ...));
145# if !GNULIB_defined_rpl_fcntl 154# if !GNULIB_defined_rpl_fcntl
146# define GNULIB_defined_rpl_fcntl 1 155# define GNULIB_defined_rpl_fcntl 1
147# endif 156# endif
148# else 157# else
149# if !@HAVE_FCNTL@ 158# if !@HAVE_FCNTL@
150_GL_FUNCDECL_SYS (fcntl, int, (int fd, int action, ...)); 159_GL_FUNCDECL_SYS (fcntl, int, (int fd, int action, ...), );
151# if !GNULIB_defined_fcntl 160# if !GNULIB_defined_fcntl
152# define GNULIB_defined_fcntl 1 161# define GNULIB_defined_fcntl 1
153# endif 162# endif
@@ -169,7 +178,7 @@ _GL_WARN_ON_USE (fcntl, "fcntl is not always POSIX compliant - "
169# undef open 178# undef open
170# define open rpl_open 179# define open rpl_open
171# endif 180# endif
172_GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...) 181_GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...),
173 _GL_ARG_NONNULL ((1))); 182 _GL_ARG_NONNULL ((1)));
174_GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...)); 183_GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...));
175# elif defined _WIN32 && !defined __CYGWIN__ 184# elif defined _WIN32 && !defined __CYGWIN__
@@ -200,7 +209,9 @@ _GL_WARN_ON_USE (open, "open is not always POSIX compliant - "
200# undef open 209# undef open
201# define open _open 210# define open _open
202# endif 211# endif
203_GL_CXXALIAS_MDA (open, int, (const char *filename, int flags, ...)); 212/* Need to cast, because in MSVC the parameter list of _open as a C++ function
213 is (const char *, int, int = 0). */
214_GL_CXXALIAS_MDA_CAST (open, int, (const char *filename, int flags, ...));
204# else 215# else
205_GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...)); 216_GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...));
206# endif 217# endif
@@ -216,14 +227,14 @@ _GL_CXXALIASWARN (open);
216# define openat rpl_openat 227# define openat rpl_openat
217# endif 228# endif
218_GL_FUNCDECL_RPL (openat, int, 229_GL_FUNCDECL_RPL (openat, int,
219 (int fd, char const *file, int flags, /* mode_t mode */ ...) 230 (int fd, char const *file, int flags, /* mode_t mode */ ...),
220 _GL_ARG_NONNULL ((2))); 231 _GL_ARG_NONNULL ((2)));
221_GL_CXXALIAS_RPL (openat, int, 232_GL_CXXALIAS_RPL (openat, int,
222 (int fd, char const *file, int flags, /* mode_t mode */ ...)); 233 (int fd, char const *file, int flags, /* mode_t mode */ ...));
223# else 234# else
224# if !@HAVE_OPENAT@ 235# if !@HAVE_OPENAT@
225_GL_FUNCDECL_SYS (openat, int, 236_GL_FUNCDECL_SYS (openat, int,
226 (int fd, char const *file, int flags, /* mode_t mode */ ...) 237 (int fd, char const *file, int flags, /* mode_t mode */ ...),
227 _GL_ARG_NONNULL ((2))); 238 _GL_ARG_NONNULL ((2)));
228# endif 239# endif
229_GL_CXXALIAS_SYS (openat, int, 240_GL_CXXALIAS_SYS (openat, int,
@@ -304,7 +315,7 @@ _GL_WARN_ON_USE (openat, "openat is not portable - "
304#endif 315#endif
305 316
306#ifndef O_DIRECTORY 317#ifndef O_DIRECTORY
307# define O_DIRECTORY 0 318# define O_DIRECTORY 0x20000000 /* Try to not collide with system O_* flags. */
308#endif 319#endif
309 320
310#ifndef O_DSYNC 321#ifndef O_DSYNC
@@ -368,8 +379,12 @@ _GL_WARN_ON_USE (openat, "openat is not portable - "
368# define O_RSYNC 0 379# define O_RSYNC 0
369#endif 380#endif
370 381
382#if defined O_SEARCH && defined O_PATH && O_SEARCH == O_PATH
383# undef O_SEARCH /* musl mistakenly #defines O_SEARCH to O_PATH. */
384#endif
385
371#ifndef O_SEARCH 386#ifndef O_SEARCH
372# define O_SEARCH O_RDONLY /* This is often close enough in older systems. */ 387# define O_SEARCH O_RDONLY /* Often close enough in non-POSIX systems. */
373#endif 388#endif
374 389
375#ifndef O_SYNC 390#ifndef O_SYNC
diff --git a/gl/fd-hook.c b/gl/fd-hook.c
index 75bbe49c..4a5014eb 100644
--- a/gl/fd-hook.c
+++ b/gl/fd-hook.c
@@ -1,5 +1,5 @@
1/* Hook for making file descriptor functions close(), ioctl() extensible. 1/* Hook for making file descriptor functions close(), ioctl() extensible.
2 Copyright (C) 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2009. 3 Written by Bruno Haible <bruno@clisp.org>, 2009.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/fd-hook.h b/gl/fd-hook.h
index 2150460b..a960eaf3 100644
--- a/gl/fd-hook.h
+++ b/gl/fd-hook.h
@@ -1,5 +1,5 @@
1/* Hook for making file descriptor functions close(), ioctl() extensible. 1/* Hook for making file descriptor functions close(), ioctl() extensible.
2 Copyright (C) 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2009-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/fflush.c b/gl/fflush.c
index 36cc14d1..d8619082 100644
--- a/gl/fflush.c
+++ b/gl/fflush.c
@@ -1,5 +1,5 @@
1/* fflush.c -- allow flushing input streams 1/* fflush.c -- allow flushing input streams
2 Copyright (C) 2007-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -33,12 +33,15 @@
33 33
34#if defined _IO_EOF_SEEN || defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 34#if defined _IO_EOF_SEEN || defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1
35/* GNU libc, BeOS, Haiku, Linux libc5 */ 35/* GNU libc, BeOS, Haiku, Linux libc5 */
36# if !defined __HAIKU__
37# define fp_ fp
38# endif
36 39
37/* Clear the stream's ungetc buffer, preserving the value of ftello (fp). */ 40/* Clear the stream's ungetc buffer, preserving the value of ftello (fp). */
38static void 41static void
39clear_ungetc_buffer_preserving_position (FILE *fp) 42clear_ungetc_buffer_preserving_position (FILE *fp)
40{ 43{
41 if (fp->_flags & _IO_IN_BACKUP) 44 if (fp_->_flags & _IO_IN_BACKUP)
42 /* _IO_free_backup_area is a bit complicated. Simply call fseek. */ 45 /* _IO_free_backup_area is a bit complicated. Simply call fseek. */
43 fseeko (fp, 0, SEEK_CUR); 46 fseeko (fp, 0, SEEK_CUR);
44} 47}
@@ -50,7 +53,7 @@ static void
50clear_ungetc_buffer (FILE *fp) 53clear_ungetc_buffer (FILE *fp)
51{ 54{
52# if defined __sferror || defined __DragonFly__ || defined __ANDROID__ 55# if defined __sferror || defined __DragonFly__ || defined __ANDROID__
53 /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Minix 3, Android */ 56 /* FreeBSD, NetBSD, OpenBSD <= 7.7, DragonFly, Mac OS X, Cygwin, Minix 3, Android */
54 if (HASUB (fp)) 57 if (HASUB (fp))
55 { 58 {
56 fp_->_p += fp_->_r; 59 fp_->_p += fp_->_r;
@@ -75,7 +78,7 @@ clear_ungetc_buffer (FILE *fp)
75/* GNU libc, BeOS, Haiku, Linux libc5 */ 78/* GNU libc, BeOS, Haiku, Linux libc5 */
76 79
77# if (defined __sferror || defined __DragonFly__ || defined __ANDROID__) && defined __SNPT 80# if (defined __sferror || defined __DragonFly__ || defined __ANDROID__) && defined __SNPT
78/* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Minix 3, Android */ 81/* FreeBSD, NetBSD, OpenBSD <= 7.7, DragonFly, Mac OS X, Cygwin, Minix 3, Android */
79 82
80static int 83static int
81disable_seek_optimization (FILE *fp) 84disable_seek_optimization (FILE *fp)
@@ -98,7 +101,7 @@ update_fpos_cache (_GL_ATTRIBUTE_MAYBE_UNUSED FILE *fp,
98 _GL_ATTRIBUTE_MAYBE_UNUSED off_t pos) 101 _GL_ATTRIBUTE_MAYBE_UNUSED off_t pos)
99{ 102{
100# if defined __sferror || defined __DragonFly__ || defined __ANDROID__ 103# if defined __sferror || defined __DragonFly__ || defined __ANDROID__
101 /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Minix 3, Android */ 104 /* FreeBSD, NetBSD, OpenBSD <= 7.7, DragonFly, Mac OS X, Cygwin, Minix 3, Android */
102# if defined __CYGWIN__ || defined __ANDROID__ 105# if defined __CYGWIN__ || defined __ANDROID__
103 /* fp_->_offset is typed as an integer. */ 106 /* fp_->_offset is typed as an integer. */
104 fp_->_offset = pos; 107 fp_->_offset = pos;
@@ -203,7 +206,7 @@ rpl_fflush (FILE *stream)
203 } 206 }
204 207
205# if (defined __sferror || defined __DragonFly__ || defined __ANDROID__) && defined __SNPT 208# if (defined __sferror || defined __DragonFly__ || defined __ANDROID__) && defined __SNPT
206 /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Minix 3, Android */ 209 /* FreeBSD, NetBSD, OpenBSD <= 7.7, DragonFly, Mac OS X, Cygwin, Minix 3, Android */
207 210
208 { 211 {
209 /* Disable seek optimization for the next fseeko call. This tells the 212 /* Disable seek optimization for the next fseeko call. This tells the
diff --git a/gl/filename.h b/gl/filename.h
index 4f0f0fbc..e353363e 100644
--- a/gl/filename.h
+++ b/gl/filename.h
@@ -1,5 +1,5 @@
1/* Basic filename support macros. 1/* Basic filename support macros.
2 Copyright (C) 2001-2024 Free Software Foundation, Inc. 2 Copyright (C) 2001-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 4
5 The GNU C Library is free software; you can redistribute it and/or 5 The GNU C Library is free software; you can redistribute it and/or
diff --git a/gl/float+.h b/gl/float+.h
index 104f477f..37381146 100644
--- a/gl/float+.h
+++ b/gl/float+.h
@@ -1,5 +1,5 @@
1/* Supplemental information about the floating-point formats. 1/* Supplemental information about the floating-point formats.
2 Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2007. 3 Written by Bruno Haible <bruno@clisp.org>, 2007.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/float.c b/gl/float.c
index a9ea40b0..780a0d1c 100644
--- a/gl/float.c
+++ b/gl/float.c
@@ -1,5 +1,5 @@
1/* Auxiliary definitions for <float.h>. 1/* Auxiliary definitions for <float.h>.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 2 Copyright (C) 2011-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2011. 3 Written by Bruno Haible <bruno@clisp.org>, 2011.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
@@ -20,14 +20,101 @@
20/* Specification. */ 20/* Specification. */
21#include <float.h> 21#include <float.h>
22 22
23#if (defined _ARCH_PPC || defined _POWER) && (defined _AIX || defined __linux__) && (LDBL_MANT_DIG == 106) && defined __GNUC__ 23#if GNULIB_defined_long_double_union
24# if (defined _ARCH_PPC || defined _POWER) && (defined _AIX || defined __linux__) && (LDBL_MANT_DIG == 106) && defined __GNUC__
24const union gl_long_double_union gl_LDBL_MAX = 25const union gl_long_double_union gl_LDBL_MAX =
25 { { DBL_MAX, DBL_MAX / (double)134217728UL / (double)134217728UL } }; 26 { { DBL_MAX, DBL_MAX / 0x1p53 } };
26#elif defined __i386__ 27# elif defined __i386__
27const union gl_long_double_union gl_LDBL_MAX = 28const union gl_long_double_union gl_LDBL_MAX =
28 { { 0xFFFFFFFF, 0xFFFFFFFF, 32766 } }; 29 { { 0xFFFFFFFF, 0xFFFFFFFF, 32766 } };
29#else 30# endif
31# if defined __i386__ && (defined __FreeBSD__ || defined __DragonFly__)
32/* We can't even simply evaluate the formula (LDBL_MIN / 9223372036854775808.0L)
33 at run time, because it would require BEGIN_LONG_DOUBLE_ROUNDING /
34 END_LONG_DOUBLE_ROUNDING invocations. It simpler to just write down the
35 representation of LDBL_TRUE_MIN, based on
36 <https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format>. */
37const union gl_long_double_union gl_LDBL_TRUE_MIN =
38 { { 0x00000001, 0x00000000, 0 } };
39# endif
40#endif
41
42#if GNULIB_defined_FLT_SNAN
43/* Define like memory_positive_SNaNf(), see signed-snan.h and snan.h,
44 or like setpayloadsigf() with an arbitrary payload. */
45gl_FLT_SNAN_t gl_FLT_SNAN =
46# if FLT_MANT_DIG == 24
47# if defined __hppa || (defined __mips__ && !MIPS_NAN2008_FLOAT) || defined __sh__
48 /* sign bit: 0, 8 exponent bits: all 1, next bit: 1, payload: 0b10...0 */
49 { { 0x7FE00000U } }
50# else
51 /* sign bit: 0, 8 exponent bits: all 1, next bit: 0, payload: 0b10...0 */
52 { { 0x7FA00000U } }
53# endif
54# endif
55 ;
56#endif
57
58#if GNULIB_defined_DBL_SNAN
59/* Define like memory_positive_SNaNd(), see signed-snan.h and snan.h,
60 or like setpayloadsig() with an arbitrary payload. */
61gl_DBL_SNAN_t gl_DBL_SNAN =
62# if DBL_MANT_DIG == 53
63# if defined __hppa || (defined __mips__ && !MIPS_NAN2008_FLOAT) || defined __sh__
64 /* sign bit: 0, 11 exponent bits: all 1, next bit: 1, payload: 0b10...0 */
65 { { 0x7FFC000000000000ULL } }
66# else
67 /* sign bit: 0, 11 exponent bits: all 1, next bit: 0, payload: 0b10...0 */
68 { { 0x7FF4000000000000ULL } }
69# endif
70# endif
71 ;
72#endif
73
74#if GNULIB_defined_LDBL_SNAN
75# ifdef WORDS_BIGENDIAN
76# define TWO(hi,lo) { hi, lo }
77# else
78# define TWO(hi,lo) { lo, hi }
79# endif
80/* Define like memory_positive_SNaNl(), see signed-snan.h and snan.h,
81 or like setpayloadsigl() with an arbitrary payload. */
82gl_LDBL_SNAN_t gl_LDBL_SNAN =
83# if LDBL_MANT_DIG == 53 /* on arm, hppa, mips, sh, but also MSVC */
84# if defined __hppa || (defined __mips__ && !MIPS_NAN2008_FLOAT) || defined __sh__
85 /* sign bit: 0, 11 exponent bits: all 1, next bit: 1, payload: 0b10...0 */
86 { { 0x7FFC000000000000ULL } }
87# else
88 /* sign bit: 0, 11 exponent bits: all 1, next bit: 0, payload: 0b10...0 */
89 { { 0x7FF4000000000000ULL } }
90# endif
91# elif LDBL_MANT_DIG == 64 /* on i386, x86_64, ia64, m68k */
92# if defined __m68k__
93 /* sign bit: 0, 15 exponent bits: all 1, 16 gap bits: all 0,
94 always=1 bit: 1, next bit: 0, payload: 0b10...0 */
95 { { 0x7FFF0000ULL, 0xA0000000ULL, 0x00000000ULL } }
96# else
97 /* sign bit: 0, 15 exponent bits: all 1, always=1 bit: 1, next bit: 0, payload: 0b10...0
98 (see <https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format>) */
99 { TWO (0x00007FFFULL, 0xA000000000000000ULL) }
100# endif
101# elif LDBL_MANT_DIG == 106 /* on powerpc, powerpc64, powerpc64le */
102 /* most-significant double:
103 sign bit: 0, 11 exponent bits: all 1, next bit: 0, payload: 0b10...0,
104 least-significant double: 0.0 */
105 { { 0x7FF4000000000000ULL, 0ULL } }
106# elif LDBL_MANT_DIG == 113 /* on alpha, arm64, loongarch64, mips64, riscv64, s390x, sparc64 */
107# if (defined __mips__ && !MIPS_NAN2008_FLOAT)
108 /* sign bit: 0, 15 exponent bits: all 1, next bit: 1, payload: 0b10...0 */
109 { TWO (0x7FFFC00000000000ULL, 0ULL) }
110# else
111 /* sign bit: 0, 15 exponent bits: all 1, next bit: 0, payload: 0b10...0 */
112 { TWO (0x7FFF400000000000ULL, 0ULL) }
113# endif
114# endif
115 ;
116#endif
117
30/* This declaration is solely to ensure that after preprocessing 118/* This declaration is solely to ensure that after preprocessing
31 this file is never empty. */ 119 this file is never empty. */
32typedef int dummy; 120typedef int dummy;
33#endif
diff --git a/gl/float.in.h b/gl/float.in.h
index 73e8d406..d75a06e7 100644
--- a/gl/float.in.h
+++ b/gl/float.in.h
@@ -1,6 +1,6 @@
1/* A correct <float.h>. 1/* A correct <float.h>.
2 2
3 Copyright (C) 2007-2024 Free Software Foundation, Inc. 3 Copyright (C) 2007-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -28,6 +28,8 @@
28#ifndef _@GUARD_PREFIX@_FLOAT_H 28#ifndef _@GUARD_PREFIX@_FLOAT_H
29#define _@GUARD_PREFIX@_FLOAT_H 29#define _@GUARD_PREFIX@_FLOAT_H
30 30
31/* ============================ ISO C99 support ============================ */
32
31/* 'long double' properties. */ 33/* 'long double' properties. */
32 34
33#if defined __i386__ && (defined __BEOS__ || defined __OpenBSD__) 35#if defined __i386__ && (defined __BEOS__ || defined __OpenBSD__)
@@ -111,44 +113,38 @@ extern const union gl_long_double_union gl_LDBL_MAX;
111# define LDBL_MAX_10_EXP 4932 113# define LDBL_MAX_10_EXP 4932
112#endif 114#endif
113 115
114/* On AIX 7.1 with gcc 4.2, the values of LDBL_MIN_EXP, LDBL_MIN, LDBL_MAX are 116/* On PowerPC with gcc 15 when using __ibm128 long double, the value of
115 wrong. 117 LDBL_MIN_EXP, LDBL_MIN, LDBL_MAX, and LDBL_NORM_MAX are wrong. */
116 On Linux/PowerPC with gcc 4.4, the value of LDBL_MAX is wrong. */ 118#if (defined _ARCH_PPC && LDBL_MANT_DIG == 106 \
117#if (defined _ARCH_PPC || defined _POWER) && defined _AIX && (LDBL_MANT_DIG == 106) && defined __GNUC__ 119 && defined __GNUC__)
118# undef LDBL_MIN_EXP 120# undef LDBL_MIN_EXP
119# define LDBL_MIN_EXP DBL_MIN_EXP 121# define LDBL_MIN_EXP DBL_MIN_EXP
120# undef LDBL_MIN_10_EXP 122# undef LDBL_MIN_10_EXP
121# define LDBL_MIN_10_EXP DBL_MIN_10_EXP 123# define LDBL_MIN_10_EXP DBL_MIN_10_EXP
122# undef LDBL_MIN 124# undef LDBL_MIN
123# define LDBL_MIN 2.22507385850720138309023271733240406422e-308L /* DBL_MIN = 2^-1022 */ 125# define LDBL_MIN 2.22507385850720138309023271733240406422e-308L /* DBL_MIN = 2^-1022 */
124#endif
125#if (defined _ARCH_PPC || defined _POWER) && (defined _AIX || defined __linux__) && (LDBL_MANT_DIG == 106) && defined __GNUC__
126# undef LDBL_MAX 126# undef LDBL_MAX
127/* LDBL_MAX is represented as { 0x7FEFFFFF, 0xFFFFFFFF, 0x7C8FFFFF, 0xFFFFFFFF }. 127/* LDBL_MAX is 2**1024 - 2**918, represented as: { 0x7FEFFFFF, 0xFFFFFFFF,
128 It is not easy to define: 128 0x7C9FFFFF, 0xFFFFFFFF }.
129 #define LDBL_MAX 1.79769313486231580793728971405302307166e308L 129
130 is too small, whereas 130 Do not write it as a constant expression, as GCC would likely treat
131 #define LDBL_MAX 1.79769313486231580793728971405302307167e308L 131 that as infinity due to the vagaries of this platform's funky arithmetic.
132 is too large. Apparently a bug in GCC decimal-to-binary conversion. 132 Instead, define it through a reference to an external variable.
133 Also, I can't get values larger than 133 Like the following, but using a union to avoid type mismatches:
134 #define LDBL63 ((long double) (1ULL << 63))
135 #define LDBL882 (LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63)
136 #define LDBL945 (LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63)
137 #define LDBL1008 (LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63)
138 #define LDBL_MAX (LDBL1008 * 65535.0L + LDBL945 * (long double) 9223372036821221375ULL + LDBL882 * (long double) 4611686018427387904ULL)
139 which is represented as { 0x7FEFFFFF, 0xFFFFFFFF, 0x7C8FFFFF, 0xF8000000 }.
140 So, define it like this through a reference to an external variable
141 134
142 const double LDBL_MAX[2] = { DBL_MAX, DBL_MAX / (double)134217728UL / (double)134217728UL }; 135 const double LDBL_MAX[2] = { DBL_MAX, DBL_MAX / 0x1p53 };
143 extern const long double LDBL_MAX; 136 extern const long double LDBL_MAX;
144 137
145 or through a pointer cast 138 The following alternative would not work as well when GCC is optimizing:
146 139
147 #define LDBL_MAX \ 140 #define LDBL_MAX (*(long double const *) (double[])
148 (*(const long double *) (double[]) { DBL_MAX, DBL_MAX / (double)134217728UL / (double)134217728UL }) 141 { DBL_MAX, DBL_MAX / 0x1p53 })
149 142
150 Unfortunately, this is not a constant expression, and the latter expression 143 The following alternative would require GCC 6 or later:
151 does not work well when GCC is optimizing.. */ 144
145 #define LDBL_MAX __builtin_pack_longdouble (DBL_MAX, DBL_MAX / 0x1p53)
146
147 Unfortunately none of the alternatives are constant expressions. */
152# if !GNULIB_defined_long_double_union 148# if !GNULIB_defined_long_double_union
153union gl_long_double_union 149union gl_long_double_union
154 { 150 {
@@ -159,6 +155,8 @@ union gl_long_double_union
159# endif 155# endif
160extern const union gl_long_double_union gl_LDBL_MAX; 156extern const union gl_long_double_union gl_LDBL_MAX;
161# define LDBL_MAX (gl_LDBL_MAX.ld) 157# define LDBL_MAX (gl_LDBL_MAX.ld)
158# undef LDBL_NORM_MAX
159# define LDBL_NORM_MAX LDBL_MAX
162#endif 160#endif
163 161
164/* On IRIX 6.5, with cc, the value of LDBL_MANT_DIG is wrong. 162/* On IRIX 6.5, with cc, the value of LDBL_MANT_DIG is wrong.
@@ -179,6 +177,175 @@ extern const union gl_long_double_union gl_LDBL_MAX;
179# endif 177# endif
180#endif 178#endif
181 179
180/* On PowerPC platforms, 'long double' has a double-double representation.
181 Up to ISO C 17, this was outside the scope of ISO C because it can represent
182 numbers with mantissas of the form 1.<52 bits><many zeroes><52 bits>, such as
183 1.0L + 4.94065645841246544176568792868221e-324L = 1 + 2^-1074; see
184 ISO C 17 § 5.2.4.2.2.(3).
185 In ISO C 23, wording has been included that makes this 'long double'
186 representation compliant; see ISO C 23 § 5.2.5.3.3.(8)-(9). In this setting,
187 numbers with mantissas of the form 1.<52 bits><many zeroes><52 bits> are
188 called "unnormalized". And since LDBL_EPSILON must be normalized (per
189 ISO C 23 § 5.2.5.3.3.(33)), it must be 2^-105. */
190#if defined __powerpc__ && LDBL_MANT_DIG == 106
191# undef LDBL_EPSILON
192# define LDBL_EPSILON 2.46519032881566189191165176650870696773e-32L /* 2^-105 */
193#endif
194
195/* ============================ ISO C11 support ============================ */
196
197/* 'float' properties */
198
199#ifndef FLT_HAS_SUBNORM
200# define FLT_HAS_SUBNORM 1
201#endif
202#ifndef FLT_DECIMAL_DIG
203/* FLT_MANT_DIG = 24 => FLT_DECIMAL_DIG = 9 */
204# define FLT_DECIMAL_DIG ((int)(FLT_MANT_DIG * 0.3010299956639812 + 2))
205#endif
206#if defined _AIX && !defined __GNUC__
207/* On AIX, the value of FLT_TRUE_MIN in /usr/include/float.h is a 'double',
208 not a 'float'. */
209# undef FLT_TRUE_MIN
210#endif
211#ifndef FLT_TRUE_MIN
212/* FLT_MIN / 2^(FLT_MANT_DIG-1) */
213# define FLT_TRUE_MIN (FLT_MIN / 8388608.0f)
214#endif
215
216/* 'double' properties */
217
218#ifndef DBL_HAS_SUBNORM
219# define DBL_HAS_SUBNORM 1
220#endif
221#ifndef DBL_DECIMAL_DIG
222/* DBL_MANT_DIG = 53 => DBL_DECIMAL_DIG = 17 */
223# define DBL_DECIMAL_DIG ((int)(DBL_MANT_DIG * 0.3010299956639812 + 2))
224#endif
225#ifndef DBL_TRUE_MIN
226/* DBL_MIN / 2^(DBL_MANT_DIG-1) */
227# define DBL_TRUE_MIN (DBL_MIN / 4503599627370496.0)
228#endif
229
230/* 'long double' properties */
231
232#ifndef LDBL_HAS_SUBNORM
233# define LDBL_HAS_SUBNORM 1
234#endif
235#ifndef LDBL_DECIMAL_DIG
236/* LDBL_MANT_DIG = 53 => LDBL_DECIMAL_DIG = 17 */
237/* LDBL_MANT_DIG = 64 => LDBL_DECIMAL_DIG = 21 */
238/* LDBL_MANT_DIG = 106 => LDBL_DECIMAL_DIG = 33 */
239/* LDBL_MANT_DIG = 113 => LDBL_DECIMAL_DIG = 36 */
240# define LDBL_DECIMAL_DIG ((int)(LDBL_MANT_DIG * 0.3010299956639812 + 2))
241#endif
242#ifndef LDBL_TRUE_MIN
243/* LDBL_MIN / 2^(LDBL_MANT_DIG-1) */
244# if LDBL_MANT_DIG == 53
245# define LDBL_TRUE_MIN (LDBL_MIN / 4503599627370496.0L)
246# elif LDBL_MANT_DIG == 64
247# if defined __i386__ && (defined __FreeBSD__ || defined __DragonFly__)
248/* Work around FreeBSD/x86 problem mentioned above. */
249extern const union gl_long_double_union gl_LDBL_TRUE_MIN;
250# define LDBL_TRUE_MIN (gl_LDBL_TRUE_MIN.ld)
251# else
252# define LDBL_TRUE_MIN (LDBL_MIN / 9223372036854775808.0L)
253# endif
254# elif LDBL_MANT_DIG == 106
255# define LDBL_TRUE_MIN (LDBL_MIN / 40564819207303340847894502572032.0L)
256# elif LDBL_MANT_DIG == 113
257# define LDBL_TRUE_MIN (LDBL_MIN / 5192296858534827628530496329220096.0L)
258# endif
259#endif
260
261/* ============================ ISO C23 support ============================ */
262
263/* 'float' properties */
264
265#ifndef FLT_IS_IEC_60559
266# if defined __m68k__
267# define FLT_IS_IEC_60559 0
268# else
269# define FLT_IS_IEC_60559 1
270# endif
271#endif
272#ifndef FLT_NORM_MAX
273# define FLT_NORM_MAX FLT_MAX
274#endif
275#ifndef FLT_SNAN
276/* For sh, beware of <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111814>. */
277# if ((__GNUC__ + (__GNUC_MINOR__ >= 3) > 3) || defined __clang__) && !defined __sh__
278# define FLT_SNAN __builtin_nansf ("")
279# else
280typedef union { unsigned int word[1]; float value; } gl_FLT_SNAN_t;
281extern gl_FLT_SNAN_t gl_FLT_SNAN;
282# define FLT_SNAN (gl_FLT_SNAN.value)
283# define GNULIB_defined_FLT_SNAN 1
284# endif
285#endif
286
287/* 'double' properties */
288
289#ifndef DBL_IS_IEC_60559
290# if defined __m68k__
291# define DBL_IS_IEC_60559 0
292# else
293# define DBL_IS_IEC_60559 1
294# endif
295#endif
296#ifndef DBL_NORM_MAX
297# define DBL_NORM_MAX DBL_MAX
298#endif
299#ifndef DBL_SNAN
300/* For sh, beware of <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111814>. */
301# if ((__GNUC__ + (__GNUC_MINOR__ >= 3) > 3) || defined __clang__) && !defined __sh__
302# define DBL_SNAN __builtin_nans ("")
303# else
304typedef union { unsigned long long word[1]; double value; } gl_DBL_SNAN_t;
305extern gl_DBL_SNAN_t gl_DBL_SNAN;
306# define DBL_SNAN (gl_DBL_SNAN.value)
307# define GNULIB_defined_DBL_SNAN 1
308# endif
309#endif
310
311/* 'long double' properties */
312
313#ifndef LDBL_IS_IEC_60559
314# if defined __m68k__
315# define LDBL_IS_IEC_60559 0
316# elif LDBL_MANT_DIG == 53 || LDBL_MANT_DIG == 113
317# define LDBL_IS_IEC_60559 1
318# else
319# define LDBL_IS_IEC_60559 0
320# endif
321#endif
322#ifndef LDBL_NORM_MAX
323# ifdef __LDBL_NORM_MAX__
324# define LDBL_NORM_MAX __LDBL_NORM_MAX__
325# else
326# define LDBL_NORM_MAX LDBL_MAX
327# endif
328#endif
329#ifndef LDBL_SNAN
330/* For sh, beware of <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111814>. */
331# if ((__GNUC__ + (__GNUC_MINOR__ >= 3) > 3) || defined __clang__) && !defined __sh__
332# define LDBL_SNAN __builtin_nansl ("")
333# else
334# if LDBL_MANT_DIG == 53
335typedef union { unsigned long long word[1]; long double value; } gl_LDBL_SNAN_t;
336# elif defined __m68k__
337typedef union { unsigned int word[3]; long double value; } gl_LDBL_SNAN_t;
338# else
339typedef union { unsigned long long word[2]; long double value; } gl_LDBL_SNAN_t;
340# endif
341extern gl_LDBL_SNAN_t gl_LDBL_SNAN;
342# define LDBL_SNAN (gl_LDBL_SNAN.value)
343# define GNULIB_defined_LDBL_SNAN 1
344# endif
345#endif
346
347/* ================================= Other ================================= */
348
182#if @REPLACE_ITOLD@ 349#if @REPLACE_ITOLD@
183/* Pull in a function that fixes the 'int' to 'long double' conversion 350/* Pull in a function that fixes the 'int' to 'long double' conversion
184 of glibc 2.7. */ 351 of glibc 2.7. */
diff --git a/gl/floor.c b/gl/floor.c
index 392f2044..4d7fecae 100644
--- a/gl/floor.c
+++ b/gl/floor.c
@@ -1,5 +1,5 @@
1/* Round towards negative infinity. 1/* Round towards negative infinity.
2 Copyright (C) 2007, 2010-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2010-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/floorf.c b/gl/floorf.c
index f9785d0c..d210c297 100644
--- a/gl/floorf.c
+++ b/gl/floorf.c
@@ -1,5 +1,5 @@
1/* Round towards negative infinity. 1/* Round towards negative infinity.
2 Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/fopen.c b/gl/fopen.c
index d3b57a98..41587d2c 100644
--- a/gl/fopen.c
+++ b/gl/fopen.c
@@ -1,5 +1,5 @@
1/* Open a stream to a file. 1/* Open a stream to a file.
2 Copyright (C) 2007-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -19,12 +19,12 @@
19/* If the user's config.h happens to include <stdio.h>, let it include only 19/* If the user's config.h happens to include <stdio.h>, let it include only
20 the system's <stdio.h> here, so that orig_fopen doesn't recurse to 20 the system's <stdio.h> here, so that orig_fopen doesn't recurse to
21 rpl_fopen. */ 21 rpl_fopen. */
22#define _GL_ALREADY_INCLUDING_STDIO_H 22#define _GL_SKIP_GNULIB_STDIO_H
23#include <config.h> 23#include <config.h>
24 24
25/* Get the original definition of fopen. It might be defined as a macro. */ 25/* Get the original definition of fopen. It might be defined as a macro. */
26#include <stdio.h> 26#include <stdio.h>
27#undef _GL_ALREADY_INCLUDING_STDIO_H 27#undef _GL_SKIP_GNULIB_STDIO_H
28 28
29static FILE * 29static FILE *
30orig_fopen (const char *filename, const char *mode) 30orig_fopen (const char *filename, const char *mode)
diff --git a/gl/fpurge.c b/gl/fpurge.c
index 52a3dcef..0b69da3f 100644
--- a/gl/fpurge.c
+++ b/gl/fpurge.c
@@ -1,5 +1,5 @@
1/* Flushing buffers of a FILE stream. 1/* Flushing buffers of a FILE stream.
2 Copyright (C) 2007-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -37,7 +37,7 @@ fpurge (FILE *fp)
37 /* The __fpurge function does not have a return value. */ 37 /* The __fpurge function does not have a return value. */
38 return 0; 38 return 0;
39 39
40#elif HAVE_FPURGE /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin >= 1.7 */ 40#elif HAVE_FPURGE /* FreeBSD, NetBSD, 2.0 <= OpenBSD <= 7.7, DragonFly, Mac OS X, Cygwin >= 1.7 */
41 41
42 /* Call the system's fpurge function. */ 42 /* Call the system's fpurge function. */
43# undef fpurge 43# undef fpurge
@@ -46,7 +46,7 @@ fpurge (FILE *fp)
46# endif 46# endif
47 int result = fpurge (fp); 47 int result = fpurge (fp);
48# if defined __sferror || defined __DragonFly__ || defined __ANDROID__ 48# if defined __sferror || defined __DragonFly__ || defined __ANDROID__
49 /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Minix 3, Android */ 49 /* FreeBSD, NetBSD, OpenBSD <= 7.7, DragonFly, Mac OS X, Cygwin, Minix 3, Android */
50 if (result == 0) 50 if (result == 0)
51 /* Correct the invariants that fpurge broke. 51 /* Correct the invariants that fpurge broke.
52 <stdio.h> on BSD systems says: 52 <stdio.h> on BSD systems says:
@@ -76,7 +76,7 @@ fpurge (FILE *fp)
76 } 76 }
77 return 0; 77 return 0;
78# elif defined __sferror || defined __DragonFly__ || defined __ANDROID__ 78# elif defined __sferror || defined __DragonFly__ || defined __ANDROID__
79 /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Minix 3, Android */ 79 /* FreeBSD, NetBSD, OpenBSD < 2.0, DragonFly, Mac OS X, Cygwin, Minix 3, Android */
80 fp_->_p = fp_->_bf._base; 80 fp_->_p = fp_->_bf._base;
81 fp_->_r = 0; 81 fp_->_r = 0;
82 fp_->_w = ((fp_->_flags & (__SLBF | __SNBF | __SRD)) == 0 /* fully buffered and not currently reading? */ 82 fp_->_w = ((fp_->_flags & (__SLBF | __SNBF | __SRD)) == 0 /* fully buffered and not currently reading? */
diff --git a/gl/freading.c b/gl/freading.c
index c80d9aa8..6a60d6b3 100644
--- a/gl/freading.c
+++ b/gl/freading.c
@@ -1,5 +1,5 @@
1/* Retrieve information about a FILE stream. 1/* Retrieve information about a FILE stream.
2 Copyright (C) 2007-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -25,6 +25,10 @@
25 <https://sourceware.org/bugzilla/show_bug.cgi?id=4359> */ 25 <https://sourceware.org/bugzilla/show_bug.cgi?id=4359> */
26#if !(HAVE___FREADING && (!defined __GLIBC__ || defined __UCLIBC__ || __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 7))) 26#if !(HAVE___FREADING && (!defined __GLIBC__ || defined __UCLIBC__ || __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 7)))
27 27
28/* This code is not compiled on systems that have a working __freading function,
29 namely glibc >= 2.7, OpenBSD >= 7.6, Solaris >= 7, UnixWare >= 7.1.4.MP4,
30 Cygwin >= 1.7.34, Android API >= 28, musl libc, Haiku >= hrev58760. */
31
28bool 32bool
29freading (FILE *fp) 33freading (FILE *fp)
30{ 34{
@@ -37,7 +41,7 @@ freading (FILE *fp)
37 || ((fp->_flags & (_IO_NO_READS | _IO_CURRENTLY_PUTTING)) == 0 41 || ((fp->_flags & (_IO_NO_READS | _IO_CURRENTLY_PUTTING)) == 0
38 && fp->_IO_read_base != NULL)); 42 && fp->_IO_read_base != NULL));
39# elif defined __sferror || defined __DragonFly__ || defined __ANDROID__ 43# elif defined __sferror || defined __DragonFly__ || defined __ANDROID__
40 /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin < 1.7.34, Minix 3, Android */ 44 /* FreeBSD, NetBSD, OpenBSD < 7.6, DragonFly, Mac OS X, Cygwin < 1.7.34, Minix 3, Android */
41 return (fp_->_flags & __SRD) != 0; 45 return (fp_->_flags & __SRD) != 0;
42# elif defined __EMX__ /* emx+gcc */ 46# elif defined __EMX__ /* emx+gcc */
43 return (fp->_flags & _IOREAD) != 0; 47 return (fp->_flags & _IOREAD) != 0;
diff --git a/gl/freading.h b/gl/freading.h
index 943354f5..405a651e 100644
--- a/gl/freading.h
+++ b/gl/freading.h
@@ -1,5 +1,5 @@
1/* Retrieve information about a FILE stream. 1/* Retrieve information about a FILE stream.
2 Copyright (C) 2007-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/free.c b/gl/free.c
index 2f0c40ba..98ceafd7 100644
--- a/gl/free.c
+++ b/gl/free.c
@@ -1,6 +1,6 @@
1/* Make free() preserve errno. 1/* Make free() preserve errno.
2 2
3 Copyright (C) 2003, 2006, 2009-2024 Free Software Foundation, Inc. 3 Copyright (C) 2003, 2006, 2009-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/fseek.c b/gl/fseek.c
index cebc1749..a5857650 100644
--- a/gl/fseek.c
+++ b/gl/fseek.c
@@ -1,5 +1,5 @@
1/* An fseek() function that, together with fflush(), is POSIX compliant. 1/* An fseek() function that, together with fflush(), is POSIX compliant.
2 Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/fseeko.c b/gl/fseeko.c
index 2c3b053a..ecd2f83a 100644
--- a/gl/fseeko.c
+++ b/gl/fseeko.c
@@ -1,5 +1,5 @@
1/* An fseeko() function that, together with fflush(), is POSIX compliant. 1/* An fseeko() function that, together with fflush(), is POSIX compliant.
2 Copyright (C) 2007-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -48,12 +48,15 @@ fseeko (FILE *fp, off_t offset, int whence)
48 48
49 /* These tests are based on fpurge.c. */ 49 /* These tests are based on fpurge.c. */
50#if defined _IO_EOF_SEEN || defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 50#if defined _IO_EOF_SEEN || defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1
51# if !defined __HAIKU__
52# define fp_ fp
53# endif
51 /* GNU libc, BeOS, Haiku, Linux libc5 */ 54 /* GNU libc, BeOS, Haiku, Linux libc5 */
52 if (fp->_IO_read_end == fp->_IO_read_ptr 55 if (fp_->_IO_read_end == fp_->_IO_read_ptr
53 && fp->_IO_write_ptr == fp->_IO_write_base 56 && fp_->_IO_write_ptr == fp_->_IO_write_base
54 && fp->_IO_save_base == NULL) 57 && fp_->_IO_save_base == NULL)
55#elif defined __sferror || defined __DragonFly__ || defined __ANDROID__ 58#elif defined __sferror || defined __DragonFly__ || defined __ANDROID__
56 /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Minix 3, Android */ 59 /* FreeBSD, NetBSD, OpenBSD <= 7.7, DragonFly, Mac OS X, Cygwin, Minix 3, Android */
57# if defined __SL64 && defined __SCLE /* Cygwin */ 60# if defined __SL64 && defined __SCLE /* Cygwin */
58 if ((fp->_flags & __SL64) == 0) 61 if ((fp->_flags & __SL64) == 0)
59 { 62 {
@@ -101,6 +104,9 @@ fseeko (FILE *fp, off_t offset, int whence)
101#elif defined EPLAN9 /* Plan9 */ 104#elif defined EPLAN9 /* Plan9 */
102 if (fp->rp == fp->buf 105 if (fp->rp == fp->buf
103 && fp->wp == fp->buf) 106 && fp->wp == fp->buf)
107#elif defined __OpenBSD__ && !defined __sferror /* OpenBSD >= 7.8 */
108 /* fseeko and fflush work as advertised. */
109 if (0)
104#elif FUNC_FFLUSH_STDIN < 0 && 200809 <= _POSIX_VERSION 110#elif FUNC_FFLUSH_STDIN < 0 && 200809 <= _POSIX_VERSION
105 /* Cross-compiling to some other system advertising conformance to 111 /* Cross-compiling to some other system advertising conformance to
106 POSIX.1-2008 or later. Assume fseeko and fflush work as advertised. 112 POSIX.1-2008 or later. Assume fseeko and fflush work as advertised.
@@ -118,7 +124,7 @@ fseeko (FILE *fp, off_t offset, int whence)
118 if (pos == -1) 124 if (pos == -1)
119 { 125 {
120#if defined __sferror || defined __DragonFly__ || defined __ANDROID__ 126#if defined __sferror || defined __DragonFly__ || defined __ANDROID__
121 /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Minix 3, Android */ 127 /* FreeBSD, NetBSD, OpenBSD <= 7.7, DragonFly, Mac OS X, Cygwin, Minix 3, Android */
122 fp_->_flags &= ~__SOFF; 128 fp_->_flags &= ~__SOFF;
123#endif 129#endif
124 return -1; 130 return -1;
@@ -126,10 +132,10 @@ fseeko (FILE *fp, off_t offset, int whence)
126 132
127#if defined _IO_EOF_SEEN || defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 133#if defined _IO_EOF_SEEN || defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1
128 /* GNU libc, BeOS, Haiku, Linux libc5 */ 134 /* GNU libc, BeOS, Haiku, Linux libc5 */
129 fp->_flags &= ~_IO_EOF_SEEN; 135 fp_->_flags &= ~_IO_EOF_SEEN;
130 fp->_offset = pos; 136 fp_->_offset = pos;
131#elif defined __sferror || defined __DragonFly__ || defined __ANDROID__ 137#elif defined __sferror || defined __DragonFly__ || defined __ANDROID__
132 /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Minix 3, Android */ 138 /* FreeBSD, NetBSD, OpenBSD <= 7.7, DragonFly, Mac OS X, Cygwin, Minix 3, Android */
133# if defined __CYGWIN__ || (defined __NetBSD__ && __NetBSD_Version__ >= 600000000) || defined __minix 139# if defined __CYGWIN__ || (defined __NetBSD__ && __NetBSD_Version__ >= 600000000) || defined __minix
134 /* fp_->_offset is typed as an integer. */ 140 /* fp_->_offset is typed as an integer. */
135 fp_->_offset = pos; 141 fp_->_offset = pos;
diff --git a/gl/fseterr.c b/gl/fseterr.c
new file mode 100644
index 00000000..a01ef2af
--- /dev/null
+++ b/gl/fseterr.c
@@ -0,0 +1,84 @@
1/* Set the error indicator of a stream.
2 Copyright (C) 2007-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19/* Specification. */
20#include "fseterr.h"
21
22#include <errno.h>
23
24#include "stdio-impl.h"
25
26/* This file is not used on systems that have the __fseterr function,
27 namely OpenBSD >= 7.6, musl libc, Haiku >= hrev58760. */
28
29void
30fseterr (FILE *fp)
31{
32 /* Most systems provide FILE as a struct and the necessary bitmask in
33 <stdio.h>, because they need it for implementing getc() and putc() as
34 fast macros. */
35#if defined _IO_EOF_SEEN || defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1
36 /* GNU libc, BeOS, Haiku, Linux libc5 */
37 fp->_flags |= _IO_ERR_SEEN;
38#elif defined __sferror || defined __DragonFly__ || defined __ANDROID__
39 /* FreeBSD, NetBSD, OpenBSD < 7.6, DragonFly, Mac OS X, Cygwin, Minix 3, Android */
40 fp_->_flags |= __SERR;
41#elif defined __EMX__ /* emx+gcc */
42 fp->_flags |= _IOERR;
43#elif defined __minix /* Minix */
44 fp->_flags |= _IOERR;
45#elif defined _IOERR /* AIX, HP-UX, IRIX, OSF/1, Solaris, OpenServer, UnixWare, mingw, MSVC, NonStop Kernel, OpenVMS */
46 fp_->_flag |= _IOERR;
47#elif defined __UCLIBC__ /* uClibc */
48 fp->__modeflags |= __FLAG_ERROR;
49#elif defined __QNX__ /* QNX */
50 fp->_Mode |= 0x200 /* _MERR */;
51#elif defined __MINT__ /* Atari FreeMiNT */
52 fp->__error = 1;
53#elif defined EPLAN9 /* Plan9 */
54 if (fp->state != 0 /* CLOSED */)
55 fp->state = 5 /* ERR */;
56#elif 0 /* unknown */
57 /* Portable fallback, based on an idea by Rich Felker.
58 Wow! 6 system calls for something that is just a bit operation!
59 Not activated on any system, because there is no way to repair FP when
60 the sequence of system calls fails, and library code should not call
61 abort(). */
62 int saved_errno;
63 int fd;
64 int fd2;
65
66 saved_errno = errno;
67 fflush (fp);
68 fd = fileno (fp);
69 fd2 = dup (fd);
70 if (fd2 >= 0)
71 {
72 close (fd);
73 fputc ('\0', fp); /* This should set the error indicator. */
74 fflush (fp); /* Or this. */
75 if (dup2 (fd2, fd) < 0)
76 /* Whee... we botched the stream and now cannot restore it! */
77 abort ();
78 close (fd2);
79 }
80 errno = saved_errno;
81#else
82 #error "Please port gnulib fseterr.c to your platform! Look at the definitions of ferror and clearerr on your system, then report this to bug-gnulib."
83#endif
84}
diff --git a/gl/fseterr.h b/gl/fseterr.h
new file mode 100644
index 00000000..57c30ef3
--- /dev/null
+++ b/gl/fseterr.h
@@ -0,0 +1,55 @@
1/* Set the error indicator of a stream.
2 Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#ifndef _FSETERR_H
18#define _FSETERR_H
19
20/* This file uses HAVE___FSETERR. */
21#if !_GL_CONFIG_H_INCLUDED
22 #error "Please include config.h first."
23#endif
24
25#include <stdio.h>
26
27/* Set the error indicator of the stream FP.
28 The "error indicator" is set when an I/O operation on the stream fails, and
29 is cleared (together with the "end-of-file" indicator) by clearerr (FP). */
30
31#if HAVE___FSETERR /* musl libc */
32
33/* Haiku has __fseterr but does not declare it. */
34# if defined __HAIKU__
35extern void __fseterr (FILE *fp);
36# endif
37
38# include <stdio_ext.h>
39# define fseterr(fp) __fseterr (fp)
40
41#else
42
43# ifdef __cplusplus
44extern "C" {
45# endif
46
47extern void fseterr (FILE *fp);
48
49# ifdef __cplusplus
50}
51# endif
52
53#endif
54
55#endif /* _FSETERR_H */
diff --git a/gl/fstat.c b/gl/fstat.c
index 205d5aab..200e672e 100644
--- a/gl/fstat.c
+++ b/gl/fstat.c
@@ -1,5 +1,5 @@
1/* fstat() replacement. 1/* fstat() replacement.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 2 Copyright (C) 2011-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/fsusage.c b/gl/fsusage.c
index 97d0eef7..e26bda88 100644
--- a/gl/fsusage.c
+++ b/gl/fsusage.c
@@ -1,6 +1,6 @@
1/* fsusage.c -- return space usage of mounted file systems 1/* fsusage.c -- return space usage of mounted file systems
2 2
3 Copyright (C) 1991-1992, 1996, 1998-1999, 2002-2006, 2009-2024 Free Software 3 Copyright (C) 1991-1992, 1996, 1998-1999, 2002-2006, 2009-2025 Free Software
4 Foundation, Inc. 4 Foundation, Inc.
5 5
6 This file is free software: you can redistribute it and/or modify 6 This file is free software: you can redistribute it and/or modify
diff --git a/gl/fsusage.h b/gl/fsusage.h
index da878590..00d9067e 100644
--- a/gl/fsusage.h
+++ b/gl/fsusage.h
@@ -1,6 +1,6 @@
1/* fsusage.h -- declarations for file system space usage info 1/* fsusage.h -- declarations for file system space usage info
2 2
3 Copyright (C) 1991-1992, 1997, 2003-2006, 2009-2024 Free Software 3 Copyright (C) 1991-1992, 1997, 2003-2006, 2009-2025 Free Software
4 Foundation, Inc. 4 Foundation, Inc.
5 5
6 This file is free software: you can redistribute it and/or modify 6 This file is free software: you can redistribute it and/or modify
diff --git a/gl/ftell.c b/gl/ftell.c
index 21cab439..96648d5a 100644
--- a/gl/ftell.c
+++ b/gl/ftell.c
@@ -1,5 +1,5 @@
1/* An ftell() function that works around platform bugs. 1/* An ftell() function that works around platform bugs.
2 Copyright (C) 2007-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/ftello.c b/gl/ftello.c
index 64119aab..b0a20bf3 100644
--- a/gl/ftello.c
+++ b/gl/ftello.c
@@ -1,5 +1,5 @@
1/* An ftello() function that works around platform bugs. 1/* An ftello() function that works around platform bugs.
2 Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -20,7 +20,7 @@
20#include <stdio.h> 20#include <stdio.h>
21 21
22#include <errno.h> 22#include <errno.h>
23#include "intprops.h" 23#include <stdckdint.h>
24 24
25/* Get lseek. */ 25/* Get lseek. */
26#include <unistd.h> 26#include <unistd.h>
@@ -34,7 +34,10 @@ ftello (FILE *fp)
34# undef ftell 34# undef ftell
35# define ftello ftell 35# define ftello ftell
36#endif 36#endif
37#if _GL_WINDOWS_64_BIT_OFF_T 37#if (defined _WIN32 && !defined __CYGWIN__) \
38 /* We need to test _FILE_OFFSET_BITS for mingw-w64 */ \
39 /* and _GL_WINDOWS_64_BIT_OFF_T for MSVC. */ \
40 && (_FILE_OFFSET_BITS == 64 || _GL_WINDOWS_64_BIT_OFF_T)
38# undef ftello 41# undef ftello
39# if HAVE__FTELLI64 /* msvc, mingw64 */ 42# if HAVE__FTELLI64 /* msvc, mingw64 */
40# define ftello _ftelli64 43# define ftello _ftelli64
@@ -97,7 +100,7 @@ ftello (FILE *fp)
97 100
98 /* Compute pos + buffered, with overflow check. */ 101 /* Compute pos + buffered, with overflow check. */
99 off_t sum; 102 off_t sum;
100 if (! INT_ADD_OK (pos, buffered, &sum)) 103 if (ckd_add (&sum, pos, buffered))
101 { 104 {
102 errno = EOVERFLOW; 105 errno = EOVERFLOW;
103 return -1; 106 return -1;
diff --git a/gl/gai_strerror.c b/gl/gai_strerror.c
index 37092e29..9c5f1419 100644
--- a/gl/gai_strerror.c
+++ b/gl/gai_strerror.c
@@ -1,4 +1,4 @@
1/* Copyright (C) 1997, 2001-2002, 2004-2006, 2008-2024 Free Software 1/* Copyright (C) 1997, 2001-2002, 2004-2006, 2008-2025 Free Software
2 Foundation, Inc. 2 Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 Contributed by Philip Blundell <pjb27@cam.ac.uk>, 1997. 4 Contributed by Philip Blundell <pjb27@cam.ac.uk>, 1997.
@@ -27,8 +27,8 @@
27# include <libintl.h> 27# include <libintl.h>
28#else 28#else
29# include "gettext.h" 29# include "gettext.h"
30# define _(String) gettext (String) 30# define _(msgid) dgettext ("gnulib", msgid)
31# define N_(String) String 31# define N_(msgid) msgid
32#endif 32#endif
33 33
34#if HAVE_DECL_GAI_STRERROR 34#if HAVE_DECL_GAI_STRERROR
diff --git a/gl/getaddrinfo.c b/gl/getaddrinfo.c
index bf5d61f3..a8c45c21 100644
--- a/gl/getaddrinfo.c
+++ b/gl/getaddrinfo.c
@@ -1,5 +1,5 @@
1/* Get address information (partial implementation). 1/* Get address information (partial implementation).
2 Copyright (C) 1997, 2001-2002, 2004-2024 Free Software Foundation, Inc. 2 Copyright (C) 1997, 2001-2002, 2004-2025 Free Software Foundation, Inc.
3 Contributed by Simon Josefsson <simon@josefsson.org>. 3 Contributed by Simon Josefsson <simon@josefsson.org>.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
@@ -40,8 +40,8 @@
40#include <stdio.h> 40#include <stdio.h>
41 41
42#include "gettext.h" 42#include "gettext.h"
43#define _(String) gettext (String) 43#define _(msgid) dgettext ("gnulib", msgid)
44#define N_(String) String 44#define N_(msgid) msgid
45 45
46/* BeOS has AF_INET, but not PF_INET. */ 46/* BeOS has AF_INET, but not PF_INET. */
47#ifndef PF_INET 47#ifndef PF_INET
@@ -54,7 +54,7 @@
54 54
55#if HAVE_GETADDRINFO 55#if HAVE_GETADDRINFO
56 56
57/* Override with cdecl calling convention. */ 57/* Override with cdecl calling convention and mingw fix. */
58 58
59int 59int
60getaddrinfo (const char *restrict nodename, 60getaddrinfo (const char *restrict nodename,
@@ -63,6 +63,10 @@ getaddrinfo (const char *restrict nodename,
63 struct addrinfo **restrict res) 63 struct addrinfo **restrict res)
64# undef getaddrinfo 64# undef getaddrinfo
65{ 65{
66 if (hints && (hints->ai_flags & AI_NUMERICSERV) != 0
67 && servname && !(*servname >= '0' && *servname <= '9'))
68 return EAI_NONAME;
69
66 return getaddrinfo (nodename, servname, hints, res); 70 return getaddrinfo (nodename, servname, hints, res);
67} 71}
68 72
@@ -169,16 +173,43 @@ validate_family (int family)
169{ 173{
170 /* FIXME: Support more families. */ 174 /* FIXME: Support more families. */
171# if HAVE_IPV4 175# if HAVE_IPV4
172 if (family == PF_INET) 176 if (family == PF_INET)
173 return true; 177 return true;
174# endif 178# endif
175# if HAVE_IPV6 179# if HAVE_IPV6
176 if (family == PF_INET6) 180 if (family == PF_INET6)
177 return true; 181 return true;
178# endif 182# endif
179 if (family == PF_UNSPEC) 183 if (family == PF_UNSPEC)
180 return true; 184 return true;
181 return false; 185 return false;
186}
187
188static bool
189is_numeric_host (const char *host, int family)
190{
191# if HAVE_IPV4
192 if (family == PF_INET || family == PF_UNSPEC)
193 {
194 /* glibc supports IPv4 addresses in numbers-and-dots notation, that is,
195 also hexadecimal and octal number formats and formats that don't
196 require all four bytes to be explicitly written, via inet_aton().
197 But POSIX doesn't require support for these legacy formats. Therefore
198 we are free to use inet_pton() instead of inet_aton(). */
199 struct in_addr addr;
200 if (inet_pton (AF_INET, host, &addr))
201 return true;
202 }
203# endif
204# if HAVE_IPV6
205 if (family == PF_INET6 || family == PF_UNSPEC)
206 {
207 struct in6_addr addr;
208 if (inet_pton (AF_INET6, host, &addr))
209 return true;
210 }
211# endif
212 return false;
182} 213}
183 214
184/* Translate name of a service location and/or a service name to set of 215/* Translate name of a service location and/or a service name to set of
@@ -210,10 +241,17 @@ getaddrinfo (const char *restrict nodename,
210 241
211# ifdef WINDOWS_NATIVE 242# ifdef WINDOWS_NATIVE
212 if (use_win32_p ()) 243 if (use_win32_p ())
213 return getaddrinfo_ptr (nodename, servname, hints, res); 244 {
245 if (hints && (hints->ai_flags & AI_NUMERICSERV) != 0
246 && servname && !(*servname >= '0' && *servname <= '9'))
247 return EAI_NONAME;
248 return getaddrinfo_ptr (nodename, servname, hints, res);
249 }
214# endif 250# endif
215 251
216 if (hints && (hints->ai_flags & ~(AI_CANONNAME|AI_PASSIVE))) 252 if (hints
253 && (hints->ai_flags
254 & ~(AI_CANONNAME | AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV)))
217 /* FIXME: Support more flags. */ 255 /* FIXME: Support more flags. */
218 return EAI_BADFLAGS; 256 return EAI_BADFLAGS;
219 257
@@ -225,12 +263,18 @@ getaddrinfo (const char *restrict nodename,
225 /* FIXME: Support other socktype. */ 263 /* FIXME: Support other socktype. */
226 return EAI_SOCKTYPE; /* FIXME: Better return code? */ 264 return EAI_SOCKTYPE; /* FIXME: Better return code? */
227 265
228 if (!nodename) 266 if (nodename != NULL)
267 {
268 if (hints && (hints->ai_flags & AI_NUMERICHOST) != 0
269 && !is_numeric_host (nodename, hints->ai_family))
270 return EAI_NONAME;
271 }
272 else
229 { 273 {
230 if (!(hints->ai_flags & AI_PASSIVE)) 274 if (!(hints->ai_flags & AI_PASSIVE))
231 return EAI_NONAME; 275 return EAI_NONAME;
232 276
233# ifdef HAVE_IPV6 277# if HAVE_IPV6
234 nodename = (hints->ai_family == AF_INET6) ? "::" : "0.0.0.0"; 278 nodename = (hints->ai_family == AF_INET6) ? "::" : "0.0.0.0";
235# else 279# else
236 nodename = "0.0.0.0"; 280 nodename = "0.0.0.0";
diff --git a/gl/getdelim.c b/gl/getdelim.c
index 58063b15..2576d376 100644
--- a/gl/getdelim.c
+++ b/gl/getdelim.c
@@ -1,5 +1,5 @@
1/* getdelim.c --- Implementation of replacement getdelim function. 1/* getdelim.c --- Implementation of replacement getdelim function.
2 Copyright (C) 1994, 1996-1998, 2001, 2003, 2005-2024 Free Software 2 Copyright (C) 1994, 1996-1998, 2001, 2003, 2005-2025 Free Software
3 Foundation, Inc. 3 Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/getdtablesize.c b/gl/getdtablesize.c
index 762c100b..b98fbb70 100644
--- a/gl/getdtablesize.c
+++ b/gl/getdtablesize.c
@@ -1,5 +1,5 @@
1/* getdtablesize() function: Return maximum possible file descriptor value + 1. 1/* getdtablesize() function: Return maximum possible file descriptor value + 1.
2 Copyright (C) 2008-2024 Free Software Foundation, Inc. 2 Copyright (C) 2008-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2008. 3 Written by Bruno Haible <bruno@clisp.org>, 2008.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/gethostname.c b/gl/gethostname.c
index c075b6df..8f0ceafc 100644
--- a/gl/gethostname.c
+++ b/gl/gethostname.c
@@ -1,6 +1,6 @@
1/* gethostname emulation for SysV and POSIX.1. 1/* gethostname emulation for SysV and POSIX.1.
2 2
3 Copyright (C) 1992, 2003, 2006, 2008-2024 Free Software Foundation, Inc. 3 Copyright (C) 1992, 2003, 2006, 2008-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/getline.c b/gl/getline.c
index 2d03b646..0921dd95 100644
--- a/gl/getline.c
+++ b/gl/getline.c
@@ -1,5 +1,5 @@
1/* getline.c --- Implementation of replacement getline function. 1/* getline.c --- Implementation of replacement getline function.
2 Copyright (C) 2005-2007, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2007, 2009-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/getloadavg.c b/gl/getloadavg.c
index c940e4c7..752ec1f5 100644
--- a/gl/getloadavg.c
+++ b/gl/getloadavg.c
@@ -1,6 +1,6 @@
1/* Get the system load averages. 1/* Get the system load averages.
2 2
3 Copyright (C) 1985-1989, 1991-1995, 1997, 1999-2000, 2003-2024 Free Software 3 Copyright (C) 1985-1989, 1991-1995, 1997, 1999-2000, 2003-2025 Free Software
4 Foundation, Inc. 4 Foundation, Inc.
5 5
6 NOTE: The canonical source of this file is maintained with gnulib. 6 NOTE: The canonical source of this file is maintained with gnulib.
@@ -47,8 +47,6 @@
47 N_NAME_POINTER The nlist n_name element is a pointer, 47 N_NAME_POINTER The nlist n_name element is a pointer,
48 not an array. 48 not an array.
49 HAVE_STRUCT_NLIST_N_UN_N_NAME 'n_un.n_name' is member of 'struct nlist'. 49 HAVE_STRUCT_NLIST_N_UN_N_NAME 'n_un.n_name' is member of 'struct nlist'.
50 LINUX_LDAV_FILE [__linux__, __ANDROID__, __CYGWIN__]: File
51 containing load averages.
52 50
53 Specific system predefines this file uses, aside from setting 51 Specific system predefines this file uses, aside from setting
54 default values if not emacs: 52 default values if not emacs:
@@ -65,8 +63,7 @@
65 UMAX4_3 63 UMAX4_3
66 VMS 64 VMS
67 _WIN32 Native Windows (possibly also defined on Cygwin) 65 _WIN32 Native Windows (possibly also defined on Cygwin)
68 __linux__, __ANDROID__ Linux: assumes /proc file system mounted. 66 __linux__, __ANDROID__ Linux: assumes sysinfo() call.
69 Support from Michael K. Johnson.
70 __CYGWIN__ Cygwin emulates linux /proc/loadavg. 67 __CYGWIN__ Cygwin emulates linux /proc/loadavg.
71 __NetBSD__ NetBSD: assumes /kern file system mounted. 68 __NetBSD__ NetBSD: assumes /kern file system mounted.
72 69
@@ -108,10 +105,10 @@
108# endif 105# endif
109 106
110/* Same issues as for NeXT apply to the HURD-based GNU system. */ 107/* Same issues as for NeXT apply to the HURD-based GNU system. */
111# ifdef __GNU__ 108# if defined __gnu_hurd__ || defined NeXT
112# undef BSD 109# undef BSD
113# undef FSCALE 110# undef FSCALE
114# endif /* __GNU__ */ 111# endif /* __gnu_hurd__ || NeXT */
115 112
116/* Set values that are different from the defaults, which are 113/* Set values that are different from the defaults, which are
117 set a little farther down with #ifndef. */ 114 set a little farther down with #ifndef. */
@@ -143,7 +140,7 @@
143# define SUNOS_5 140# define SUNOS_5
144# endif 141# endif
145 142
146# if defined (__osf__) && (defined (__alpha) || defined (__alpha__)) 143# if defined (__osf__) && defined (__alpha)
147# define OSF_ALPHA 144# define OSF_ALPHA
148# include <sys/mbuf.h> 145# include <sys/mbuf.h>
149# include <sys/socket.h> 146# include <sys/socket.h>
@@ -312,8 +309,7 @@
312# endif 309# endif
313# endif 310# endif
314 311
315# if defined (__GNU__) && !defined (NeXT) 312# if defined __gnu_hurd__ && !defined NeXT
316/* Note that NeXT Openstep defines __GNU__ even though it should not. */
317/* GNU system acts much like NeXT, for load average purposes, 313/* GNU system acts much like NeXT, for load average purposes,
318 but not exactly. */ 314 but not exactly. */
319# define NeXT 315# define NeXT
@@ -358,6 +354,11 @@
358# include <sys/dg_sys_info.h> 354# include <sys/dg_sys_info.h>
359# endif 355# endif
360 356
357# if defined __linux__ || defined __ANDROID__
358# include <sys/param.h>
359# include <sys/sysinfo.h>
360# endif
361
361# if (defined __linux__ || defined __ANDROID__ \ 362# if (defined __linux__ || defined __ANDROID__ \
362 || defined __CYGWIN__ || defined SUNOS_5 \ 363 || defined __CYGWIN__ || defined SUNOS_5 \
363 || (defined LOAD_AVE_TYPE && ! defined __VMS)) 364 || (defined LOAD_AVE_TYPE && ! defined __VMS))
@@ -498,20 +499,33 @@ getloadavg (double loadavg[], int nelem)
498 } 499 }
499# endif 500# endif
500 501
501# if !defined (LDAV_DONE) && (defined __linux__ || defined __ANDROID__ || defined __CYGWIN__) 502# if (!defined LDAV_DONE \
502 /* Linux without glibc, Android, Cygwin */ 503 && (defined __ANDROID__ ? 13 <= __ANDROID_API__ : defined __linux__))
504 /* non-Android Linux without glibc, Android 3.2+, Cygwin */
503# define LDAV_DONE 505# define LDAV_DONE
504# undef LOAD_AVE_TYPE 506# undef LOAD_AVE_TYPE
505 507
506# ifndef LINUX_LDAV_FILE 508 {
507# define LINUX_LDAV_FILE "/proc/loadavg" 509 struct sysinfo info;
508# endif 510 if (sysinfo (&info) < 0)
511 return -1;
512 loadavg[0] = info.loads[0] / (double)(1U << SI_LOAD_SHIFT);
513 loadavg[1] = info.loads[1] / (double)(1U << SI_LOAD_SHIFT);
514 loadavg[2] = info.loads[2] / (double)(1U << SI_LOAD_SHIFT);
515 elem = 3;
516 }
517# endif /* __ANDROID__ ? 13 <= __ANDROID_API__ : __linux__ */
518
519# if !defined (LDAV_DONE) && defined __CYGWIN__
520 /* Cygwin */
521# define LDAV_DONE
522# undef LOAD_AVE_TYPE
509 523
510 char ldavgbuf[3 * (INT_STRLEN_BOUND (int) + sizeof ".00 ")]; 524 char ldavgbuf[3 * (INT_STRLEN_BOUND (int) + sizeof ".00 ")];
511 char const *ptr = ldavgbuf; 525 char const *ptr = ldavgbuf;
512 int fd, count, saved_errno; 526 int fd, count, saved_errno;
513 527
514 fd = open (LINUX_LDAV_FILE, O_RDONLY | O_CLOEXEC); 528 fd = open ("/proc/loadavg", O_RDONLY | O_CLOEXEC);
515 if (fd == -1) 529 if (fd == -1)
516 return -1; 530 return -1;
517 count = read (fd, ldavgbuf, sizeof ldavgbuf - 1); 531 count = read (fd, ldavgbuf, sizeof ldavgbuf - 1);
@@ -554,7 +568,7 @@ getloadavg (double loadavg[], int nelem)
554 568
555 return elem; 569 return elem;
556 570
557# endif /* __linux__ || __ANDROID__ || __CYGWIN__ */ 571# endif /* __CYGWIN__ */
558 572
559# if !defined (LDAV_DONE) && defined (__NetBSD__) /* NetBSD < 0.9 */ 573# if !defined (LDAV_DONE) && defined (__NetBSD__) /* NetBSD < 0.9 */
560# define LDAV_DONE 574# define LDAV_DONE
diff --git a/gl/getopt-cdefs.in.h b/gl/getopt-cdefs.in.h
index a1d304d4..3a5d06be 100644
--- a/gl/getopt-cdefs.in.h
+++ b/gl/getopt-cdefs.in.h
@@ -1,5 +1,5 @@
1/* getopt-on-non-glibc compatibility macros. 1/* getopt-on-non-glibc compatibility macros.
2 Copyright (C) 1989-2024 Free Software Foundation, Inc. 2 Copyright (C) 1989-2025 Free Software Foundation, Inc.
3 This file is part of gnulib. 3 This file is part of gnulib.
4 Unlike most of the getopt implementation, it is NOT shared 4 Unlike most of the getopt implementation, it is NOT shared
5 with the GNU C Library. 5 with the GNU C Library.
@@ -46,10 +46,14 @@
46# endif 46# endif
47#endif 47#endif
48 48
49#if defined __clang__
50 /* clang really only groks GNU C 4.2, regardless of its value of __GNUC__. */
51# undef __GNUC_PREREQ
52# define __GNUC_PREREQ(maj, min) ((maj) < 4 + ((min) <= 2))
53#endif
49#ifndef __GNUC_PREREQ 54#ifndef __GNUC_PREREQ
50# if defined __GNUC__ && defined __GNUC_VERSION__ 55# if defined __GNUC__ && defined __GNUC_MINOR__
51# define __GNUC_PREREQ(maj, min) \ 56# define __GNUC_PREREQ(maj, min) ((maj) < __GNUC__ + ((min) <= __GNUC_MINOR__))
52 ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
53# else 57# else
54# define __GNUC_PREREQ(maj, min) 0 58# define __GNUC_PREREQ(maj, min) 0
55# endif 59# endif
diff --git a/gl/getopt-core.h b/gl/getopt-core.h
index 12d09a25..51ac213d 100644
--- a/gl/getopt-core.h
+++ b/gl/getopt-core.h
@@ -1,5 +1,5 @@
1/* Declarations for getopt (basic, portable features only). 1/* Declarations for getopt (basic, portable features only).
2 Copyright (C) 1989-2024 Free Software Foundation, Inc. 2 Copyright (C) 1989-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library and is also part of gnulib. 3 This file is part of the GNU C Library and is also part of gnulib.
4 Patches to this file should be submitted to both projects. 4 Patches to this file should be submitted to both projects.
5 5
diff --git a/gl/getopt-ext.h b/gl/getopt-ext.h
index e4b499d4..92b66a3b 100644
--- a/gl/getopt-ext.h
+++ b/gl/getopt-ext.h
@@ -1,5 +1,5 @@
1/* Declarations for getopt (GNU extensions). 1/* Declarations for getopt (GNU extensions).
2 Copyright (C) 1989-2024 Free Software Foundation, Inc. 2 Copyright (C) 1989-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library and is also part of gnulib. 3 This file is part of the GNU C Library and is also part of gnulib.
4 Patches to this file should be submitted to both projects. 4 Patches to this file should be submitted to both projects.
5 5
diff --git a/gl/getopt-pfx-core.h b/gl/getopt-pfx-core.h
index 78b7816a..7c5ea094 100644
--- a/gl/getopt-pfx-core.h
+++ b/gl/getopt-pfx-core.h
@@ -1,5 +1,5 @@
1/* getopt (basic, portable features) gnulib wrapper header. 1/* getopt (basic, portable features) gnulib wrapper header.
2 Copyright (C) 1989-2024 Free Software Foundation, Inc. 2 Copyright (C) 1989-2025 Free Software Foundation, Inc.
3 This file is part of gnulib. 3 This file is part of gnulib.
4 Unlike most of the getopt implementation, it is NOT shared 4 Unlike most of the getopt implementation, it is NOT shared
5 with the GNU C Library. 5 with the GNU C Library.
@@ -31,6 +31,16 @@
31 functions and variables. Renaming avoids problems with some 31 functions and variables. Renaming avoids problems with some
32 compilers and linkers. */ 32 compilers and linkers. */
33#ifdef __GETOPT_PREFIX 33#ifdef __GETOPT_PREFIX
34
35/* Include platform-dependent header files that may declare getopt() and
36 friends. */
37# if defined _AIX || defined __hpux || defined __sun || defined __QNX__
38# include <stdio.h>
39# endif
40# if defined MUSL_LIBC || (defined __FreeBSD__ || defined __DragonFly__) || defined __NetBSD__ || defined __OpenBSD__ || (defined __APPLE__ && defined __MACH__) || defined _AIX || defined __sun || defined __minix || defined __HAIKU__
41# include <unistd.h>
42# endif
43
34# ifndef __GETOPT_ID 44# ifndef __GETOPT_ID
35# define __GETOPT_CONCAT(x, y) x ## y 45# define __GETOPT_CONCAT(x, y) x ## y
36# define __GETOPT_XCONCAT(x, y) __GETOPT_CONCAT (x, y) 46# define __GETOPT_XCONCAT(x, y) __GETOPT_CONCAT (x, y)
diff --git a/gl/getopt-pfx-ext.h b/gl/getopt-pfx-ext.h
index f001c11e..a61c68c7 100644
--- a/gl/getopt-pfx-ext.h
+++ b/gl/getopt-pfx-ext.h
@@ -1,5 +1,5 @@
1/* getopt (GNU extensions) gnulib wrapper header. 1/* getopt (GNU extensions) gnulib wrapper header.
2 Copyright (C) 1989-2024 Free Software Foundation, Inc. 2 Copyright (C) 1989-2025 Free Software Foundation, Inc.
3 This file is part of gnulib. 3 This file is part of gnulib.
4 Unlike most of the getopt implementation, it is NOT shared 4 Unlike most of the getopt implementation, it is NOT shared
5 with the GNU C Library. 5 with the GNU C Library.
@@ -38,11 +38,9 @@
38# endif 38# endif
39# undef getopt_long 39# undef getopt_long
40# undef getopt_long_only 40# undef getopt_long_only
41# undef option
42# undef _getopt_internal 41# undef _getopt_internal
43# define getopt_long __GETOPT_ID (getopt_long) 42# define getopt_long __GETOPT_ID (getopt_long)
44# define getopt_long_only __GETOPT_ID (getopt_long_only) 43# define getopt_long_only __GETOPT_ID (getopt_long_only)
45# define option __GETOPT_ID (option)
46# define _getopt_internal __GETOPT_ID (getopt_internal) 44# define _getopt_internal __GETOPT_ID (getopt_internal)
47 45
48/* The system's getopt.h may have already included getopt-ext.h to 46/* The system's getopt.h may have already included getopt-ext.h to
diff --git a/gl/getopt.c b/gl/getopt.c
index f66f119e..6b155e6c 100644
--- a/gl/getopt.c
+++ b/gl/getopt.c
@@ -1,5 +1,5 @@
1/* Getopt for GNU. 1/* Getopt for GNU.
2 Copyright (C) 1987-2024 Free Software Foundation, Inc. 2 Copyright (C) 1987-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library and is also part of gnulib. 3 This file is part of the GNU C Library and is also part of gnulib.
4 Patches to this file should be submitted to both projects. 4 Patches to this file should be submitted to both projects.
5 5
@@ -42,7 +42,7 @@
42# define funlockfile(fp) _IO_funlockfile (fp) 42# define funlockfile(fp) _IO_funlockfile (fp)
43#else 43#else
44# include "gettext.h" 44# include "gettext.h"
45# define _(msgid) gettext (msgid) 45# define _(msgid) dgettext ("gnulib", msgid)
46/* When used standalone, flockfile and funlockfile might not be 46/* When used standalone, flockfile and funlockfile might not be
47 available. */ 47 available. */
48# if (!defined _POSIX_THREAD_SAFE_FUNCTIONS \ 48# if (!defined _POSIX_THREAD_SAFE_FUNCTIONS \
@@ -723,7 +723,7 @@ _getopt_internal (int argc, char **argv, const char *optstring,
723 return result; 723 return result;
724} 724}
725 725
726/* glibc gets a LSB-compliant getopt and a POSIX-complaint __posix_getopt. 726/* glibc gets a LSB-compliant getopt and a POSIX-compliant __posix_getopt.
727 Standalone applications just get a POSIX-compliant getopt. 727 Standalone applications just get a POSIX-compliant getopt.
728 POSIX and LSB both require these functions to take 'char *const *argv' 728 POSIX and LSB both require these functions to take 'char *const *argv'
729 even though this is incorrect (because of the permutation). */ 729 even though this is incorrect (because of the permutation). */
@@ -732,7 +732,7 @@ _getopt_internal (int argc, char **argv, const char *optstring,
732 NAME (int argc, char *const *argv, const char *optstring) \ 732 NAME (int argc, char *const *argv, const char *optstring) \
733 { \ 733 { \
734 return _getopt_internal (argc, (char **)argv, optstring, \ 734 return _getopt_internal (argc, (char **)argv, optstring, \
735 0, 0, 0, POSIXLY_CORRECT); \ 735 NULL, NULL, 0, POSIXLY_CORRECT); \
736 } 736 }
737 737
738#ifdef _LIBC 738#ifdef _LIBC
diff --git a/gl/getopt.in.h b/gl/getopt.in.h
index c2411a75..4a87a2d5 100644
--- a/gl/getopt.in.h
+++ b/gl/getopt.in.h
@@ -1,5 +1,5 @@
1/* Declarations for getopt. 1/* Declarations for getopt.
2 Copyright (C) 1989-2024 Free Software Foundation, Inc. 2 Copyright (C) 1989-2025 Free Software Foundation, Inc.
3 This file is part of gnulib. 3 This file is part of gnulib.
4 Unlike most of the getopt implementation, it is NOT shared 4 Unlike most of the getopt implementation, it is NOT shared
5 with the GNU C Library, which supplies a different version of 5 with the GNU C Library, which supplies a different version of
@@ -30,7 +30,12 @@
30 <getopt.h>; our definitions will be present soon enough. */ 30 <getopt.h>; our definitions will be present soon enough. */
31#if @HAVE_GETOPT_H@ 31#if @HAVE_GETOPT_H@
32# define _GL_SYSTEM_GETOPT 32# define _GL_SYSTEM_GETOPT
33/* Rename the system's 'struct option' to 'struct sys_option',
34 so that we don't have to rename ours to 'struct rpl_option'
35 (which would cause significant trouble in C++ mode). */
36# define option sys_option
33# @INCLUDE_NEXT@ @NEXT_GETOPT_H@ 37# @INCLUDE_NEXT@ @NEXT_GETOPT_H@
38# undef option
34# undef _GL_SYSTEM_GETOPT 39# undef _GL_SYSTEM_GETOPT
35#endif 40#endif
36 41
diff --git a/gl/getopt1.c b/gl/getopt1.c
index c42d29f8..c8566845 100644
--- a/gl/getopt1.c
+++ b/gl/getopt1.c
@@ -1,5 +1,5 @@
1/* getopt_long and getopt_long_only entry points for GNU getopt. 1/* getopt_long and getopt_long_only entry points for GNU getopt.
2 Copyright (C) 1987-2024 Free Software Foundation, Inc. 2 Copyright (C) 1987-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library and is also part of gnulib. 3 This file is part of the GNU C Library and is also part of gnulib.
4 Patches to this file should be submitted to both projects. 4 Patches to this file should be submitted to both projects.
5 5
diff --git a/gl/getopt_int.h b/gl/getopt_int.h
index c00c0b69..94c1945c 100644
--- a/gl/getopt_int.h
+++ b/gl/getopt_int.h
@@ -1,5 +1,5 @@
1/* Internal declarations for getopt. 1/* Internal declarations for getopt.
2 Copyright (C) 1989-2024 Free Software Foundation, Inc. 2 Copyright (C) 1989-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library and is also part of gnulib. 3 This file is part of the GNU C Library and is also part of gnulib.
4 Patches to this file should be submitted to both projects. 4 Patches to this file should be submitted to both projects.
5 5
diff --git a/gl/getprogname.c b/gl/getprogname.c
index 392a9a2f..4fe7c90d 100644
--- a/gl/getprogname.c
+++ b/gl/getprogname.c
@@ -1,5 +1,5 @@
1/* Program name management. 1/* Program name management.
2 Copyright (C) 2016-2024 Free Software Foundation, Inc. 2 Copyright (C) 2016-2025 Free Software Foundation, Inc.
3 3
4 This program is free software: you can redistribute it and/or modify 4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by 5 it under the terms of the GNU Lesser General Public License as published by
diff --git a/gl/getprogname.h b/gl/getprogname.h
index bee1c1a2..ee9bb286 100644
--- a/gl/getprogname.h
+++ b/gl/getprogname.h
@@ -1,5 +1,5 @@
1/* Program name management. 1/* Program name management.
2 Copyright (C) 2016-2024 Free Software Foundation, Inc. 2 Copyright (C) 2016-2025 Free Software Foundation, Inc.
3 3
4 This program is free software: you can redistribute it and/or modify 4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by 5 it under the terms of the GNU Lesser General Public License as published by
diff --git a/gl/gettext.h b/gl/gettext.h
index 39d5ae4d..0650abc9 100644
--- a/gl/gettext.h
+++ b/gl/gettext.h
@@ -1,6 +1,5 @@
1/* Convenience header for conditional use of GNU <libintl.h>. 1/* Convenience header for conditional use of GNU <libintl.h>.
2 Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2024 Free Software 2 Copyright (C) 1995-2025 Free Software Foundation, Inc.
3 Foundation, Inc.
4 3
5 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -18,6 +17,7 @@
18#ifndef _LIBGETTEXT_H 17#ifndef _LIBGETTEXT_H
19#define _LIBGETTEXT_H 1 18#define _LIBGETTEXT_H 1
20 19
20
21/* NLS can be disabled through the configure --disable-nls option 21/* NLS can be disabled through the configure --disable-nls option
22 or through "#define ENABLE NLS 0" before including this file. */ 22 or through "#define ENABLE NLS 0" before including this file. */
23#if defined ENABLE_NLS && ENABLE_NLS 23#if defined ENABLE_NLS && ENABLE_NLS
@@ -45,32 +45,90 @@
45 as well because people using "gettext.h" will not include <libintl.h>, 45 as well because people using "gettext.h" will not include <libintl.h>,
46 and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> 46 and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
47 is OK. */ 47 is OK. */
48#if defined(__sun) 48# if defined(__sun)
49# include <locale.h> 49# include <locale.h>
50#endif 50# endif
51 51
52/* Many header files from the libstdc++ coming with g++ 3.3 or newer include 52/* Many header files from the libstdc++ coming with g++ 3.3 or newer include
53 <libintl.h>, which chokes if dcgettext is defined as a macro. So include 53 <libintl.h>, which chokes if dcgettext is defined as a macro. So include
54 it now, to make later inclusions of <libintl.h> a NOP. */ 54 it now, to make later inclusions of <libintl.h> a NOP. */
55#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) 55# if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3)
56# include <cstdlib> 56# include <cstdlib>
57# if (__GLIBC__ >= 2 && !defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H 57# if (__GLIBC__ >= 2 && !defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H
58# include <libintl.h> 58# include <libintl.h>
59# endif
59# endif 60# endif
60#endif
61 61
62/* Disabled NLS. 62/* Disabled NLS. */
63 The casts to 'const char *' serve the purpose of producing warnings 63# if defined __GNUC__ && !defined __clang__ && !defined __cplusplus
64 for invalid uses of the value returned from these functions. 64/* Use inline functions, to avoid warnings
65 On pre-ANSI systems without 'const', the config.h file is supposed to 65 warning: format not a string literal and no format arguments
66 contain "#define const". */ 66 that don't occur with enabled NLS. */
67# undef gettext 67/* The return type 'const char *' serves the purpose of producing warnings
68# define gettext(Msgid) ((const char *) (Msgid)) 68 for invalid uses of the value returned from these functions. */
69# undef dgettext 69# if __GNUC__ >= 9
70# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) 70# pragma GCC diagnostic push
71# undef dcgettext 71# pragma GCC diagnostic ignored "-Wbuiltin-declaration-mismatch"
72# define dcgettext(Domainname, Msgid, Category) \ 72# endif
73 ((void) (Category), dgettext (Domainname, Msgid)) 73# if __GNUC__ + (__GNUC_MINOR__ >= 2) > 4
74__attribute__ ((__always_inline__, __gnu_inline__))
75# else
76__attribute__ ((__always_inline__))
77# endif
78extern inline
79# if !defined(__sun)
80const
81# endif
82char *
83gettext (const char *msgid)
84{
85 return msgid;
86}
87# if __GNUC__ + (__GNUC_MINOR__ >= 2) > 4
88__attribute__ ((__always_inline__, __gnu_inline__))
89# else
90__attribute__ ((__always_inline__))
91# endif
92extern inline
93# if !defined(__sun)
94const
95# endif
96char *
97dgettext (const char *domain, const char *msgid)
98{
99 (void) domain;
100 return msgid;
101}
102# if __GNUC__ + (__GNUC_MINOR__ >= 2) > 4
103__attribute__ ((__always_inline__, __gnu_inline__))
104# else
105__attribute__ ((__always_inline__))
106# endif
107extern inline
108# if !defined(__sun)
109const
110# endif
111char *
112dcgettext (const char *domain, const char *msgid, int category)
113{
114 (void) domain;
115 (void) category;
116 return msgid;
117}
118# if __GNUC__ >= 9
119# pragma GCC diagnostic pop
120# endif
121# else
122/* The casts to 'const char *' serve the purpose of producing warnings
123 for invalid uses of the value returned from these functions. */
124# undef gettext
125# define gettext(Msgid) ((const char *) (Msgid))
126# undef dgettext
127# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid))
128# undef dcgettext
129# define dcgettext(Domainname, Msgid, Category) \
130 ((void) (Category), dgettext (Domainname, Msgid))
131# endif
74# undef ngettext 132# undef ngettext
75# define ngettext(Msgid1, Msgid2, N) \ 133# define ngettext(Msgid1, Msgid2, N) \
76 ((N) == 1 \ 134 ((N) == 1 \
@@ -93,12 +151,14 @@
93 151
94#endif 152#endif
95 153
154
96/* Prefer gnulib's setlocale override over libintl's setlocale override. */ 155/* Prefer gnulib's setlocale override over libintl's setlocale override. */
97#ifdef GNULIB_defined_setlocale 156#ifdef GNULIB_defined_setlocale
98# undef setlocale 157# undef setlocale
99# define setlocale rpl_setlocale 158# define setlocale rpl_setlocale
100#endif 159#endif
101 160
161
102/* A pseudo function call that serves as a marker for the automated 162/* A pseudo function call that serves as a marker for the automated
103 extraction of messages, but does not call gettext(). The run-time 163 extraction of messages, but does not call gettext(). The run-time
104 translation is done at a different place in the code. 164 translation is done at a different place in the code.
@@ -108,6 +168,7 @@
108 initializer for static 'char[]' or 'const char[]' variables. */ 168 initializer for static 'char[]' or 'const char[]' variables. */
109#define gettext_noop(String) String 169#define gettext_noop(String) String
110 170
171
111/* The separator between msgctxt and msgid in a .mo file. */ 172/* The separator between msgctxt and msgid in a .mo file. */
112#define GETTEXT_CONTEXT_GLUE "\004" 173#define GETTEXT_CONTEXT_GLUE "\004"
113 174
@@ -115,6 +176,9 @@
115 MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be 176 MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be
116 short and rarely need to change. 177 short and rarely need to change.
117 The letter 'p' stands for 'particular' or 'special'. */ 178 The letter 'p' stands for 'particular' or 'special'. */
179
180#include <locale.h> /* for LC_MESSAGES */
181
118#ifdef DEFAULT_TEXT_DOMAIN 182#ifdef DEFAULT_TEXT_DOMAIN
119# define pgettext(Msgctxt, Msgid) \ 183# define pgettext(Msgctxt, Msgid) \
120 pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) 184 pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
@@ -178,11 +242,12 @@ npgettext_aux (const char *domain,
178 return translation; 242 return translation;
179} 243}
180 244
245
181/* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID 246/* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID
182 can be arbitrary expressions. But for string literals these macros are 247 can be arbitrary expressions. But for string literals these macros are
183 less efficient than those above. */ 248 less efficient than those above. */
184 249
185#include <string.h> 250#include <string.h> /* for memcpy */
186 251
187/* GNULIB_NO_VLA can be defined to disable use of VLAs even if supported. 252/* GNULIB_NO_VLA can be defined to disable use of VLAs even if supported.
188 This relates to the -Wvla and -Wvla-larger-than warnings, enabled in 253 This relates to the -Wvla and -Wvla-larger-than warnings, enabled in
@@ -199,7 +264,7 @@ npgettext_aux (const char *domain,
199#endif 264#endif
200 265
201#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 266#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
202#include <stdlib.h> 267# include <stdlib.h> /* for malloc, free */
203#endif 268#endif
204 269
205#define pgettext_expr(Msgctxt, Msgid) \ 270#define pgettext_expr(Msgctxt, Msgid) \
@@ -297,4 +362,5 @@ dcnpgettext_expr (const char *domain,
297 return (n == 1 ? msgid : msgid_plural); 362 return (n == 1 ? msgid : msgid_plural);
298} 363}
299 364
365
300#endif /* _LIBGETTEXT_H */ 366#endif /* _LIBGETTEXT_H */
diff --git a/gl/gl_openssl.h b/gl/gl_openssl.h
index 06864732..dea70c1c 100644
--- a/gl/gl_openssl.h
+++ b/gl/gl_openssl.h
@@ -1,6 +1,6 @@
1/* Wrap openssl crypto hash routines in gnulib interface. -*- coding: utf-8 -*- 1/* Wrap openssl crypto hash routines in gnulib interface. -*- coding: utf-8 -*-
2 2
3 Copyright (C) 2013-2024 Free Software Foundation, Inc. 3 Copyright (C) 2013-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/glthread/lock.c b/gl/glthread/lock.c
index 6661ad6a..dace4fda 100644
--- a/gl/glthread/lock.c
+++ b/gl/glthread/lock.c
@@ -1,5 +1,5 @@
1/* Locking in multithreaded situations. 1/* Locking in multithreaded situations.
2 Copyright (C) 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -240,8 +240,6 @@ glthread_recursive_lock_destroy (gl_recursive_lock_t *lock)
240 return 0; 240 return 0;
241} 241}
242 242
243/* -------------------------- gl_once_t datatype -------------------------- */
244
245#endif 243#endif
246 244
247/* ========================================================================= */ 245/* ========================================================================= */
@@ -271,7 +269,7 @@ glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock)
271 /* Note: PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP is the only value that 269 /* Note: PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP is the only value that
272 causes the writer to be preferred. PTHREAD_RWLOCK_PREFER_WRITER_NP does not 270 causes the writer to be preferred. PTHREAD_RWLOCK_PREFER_WRITER_NP does not
273 do this; see 271 do this; see
274 http://man7.org/linux/man-pages/man3/pthread_rwlockattr_setkind_np.3.html */ 272 https://man7.org/linux/man-pages/man3/pthread_rwlockattr_setkind_np.3.html */
275 err = pthread_rwlockattr_setkind_np (&attributes, 273 err = pthread_rwlockattr_setkind_np (&attributes,
276 PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); 274 PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
277 if (err == 0) 275 if (err == 0)
@@ -698,46 +696,6 @@ glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
698 696
699# endif 697# endif
700 698
701/* -------------------------- gl_once_t datatype -------------------------- */
702
703static const pthread_once_t fresh_once = PTHREAD_ONCE_INIT;
704
705int
706glthread_once_singlethreaded (pthread_once_t *once_control)
707{
708 /* We don't know whether pthread_once_t is an integer type, a floating-point
709 type, a pointer type, or a structure type. */
710 char *firstbyte = (char *)once_control;
711 if (*firstbyte == *(const char *)&fresh_once)
712 {
713 /* First time use of once_control. Invert the first byte. */
714 *firstbyte = ~ *(const char *)&fresh_once;
715 return 1;
716 }
717 else
718 return 0;
719}
720
721# if !(PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK)
722
723int
724glthread_once_multithreaded (pthread_once_t *once_control,
725 void (*init_function) (void))
726{
727 int err = pthread_once (once_control, init_function);
728 if (err == ENOSYS)
729 {
730 /* This happens on FreeBSD 11: The pthread_once function in libc returns
731 ENOSYS. */
732 if (glthread_once_singlethreaded (once_control))
733 init_function ();
734 return 0;
735 }
736 return err;
737}
738
739# endif
740
741#endif 699#endif
742 700
743/* ========================================================================= */ 701/* ========================================================================= */
diff --git a/gl/glthread/lock.h b/gl/glthread/lock.h
index 2d5cb320..d6ccc202 100644
--- a/gl/glthread/lock.h
+++ b/gl/glthread/lock.h
@@ -1,5 +1,5 @@
1/* Locking in multithreaded situations. 1/* Locking in multithreaded situations.
2 Copyright (C) 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -64,13 +64,6 @@
64 Taking the lock: err = glthread_recursive_lock_lock (&name); 64 Taking the lock: err = glthread_recursive_lock_lock (&name);
65 Releasing the lock: err = glthread_recursive_lock_unlock (&name); 65 Releasing the lock: err = glthread_recursive_lock_unlock (&name);
66 De-initialization: err = glthread_recursive_lock_destroy (&name); 66 De-initialization: err = glthread_recursive_lock_destroy (&name);
67
68 Once-only execution:
69 Type: gl_once_t
70 Initializer: gl_once_define(extern, name)
71 Execution: gl_once (name, initfunction);
72 Equivalent functions with control of error handling:
73 Execution: err = glthread_once (&name, initfunction);
74*/ 67*/
75 68
76 69
@@ -88,17 +81,9 @@
88#include <errno.h> 81#include <errno.h>
89#include <stdlib.h> 82#include <stdlib.h>
90 83
91#if !defined c11_threads_in_use 84#include "glthread/once.h"
92# if HAVE_THREADS_H && USE_POSIX_THREADS_FROM_LIBC 85
93# define c11_threads_in_use() 1 86/* c11_threads_in_use() is defined in glthread/once.h. */
94# elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK
95# include <threads.h>
96# pragma weak thrd_exit
97# define c11_threads_in_use() (thrd_exit != NULL)
98# else
99# define c11_threads_in_use() 0
100# endif
101#endif
102 87
103/* ========================================================================= */ 88/* ========================================================================= */
104 89
@@ -195,14 +180,6 @@ extern int glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
195extern int glthread_recursive_lock_unlock (gl_recursive_lock_t *lock); 180extern int glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
196extern int glthread_recursive_lock_destroy (gl_recursive_lock_t *lock); 181extern int glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
197 182
198/* -------------------------- gl_once_t datatype -------------------------- */
199
200typedef once_flag gl_once_t;
201# define gl_once_define(STORAGECLASS, NAME) \
202 STORAGECLASS once_flag NAME = ONCE_FLAG_INIT;
203# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
204 (call_once (ONCE_CONTROL, INITFUNCTION), 0)
205
206# ifdef __cplusplus 183# ifdef __cplusplus
207} 184}
208# endif 185# endif
@@ -221,80 +198,7 @@ typedef once_flag gl_once_t;
221extern "C" { 198extern "C" {
222# endif 199# endif
223 200
224# if PTHREAD_IN_USE_DETECTION_HARD 201/* pthread_in_use() is defined in glthread/once.h. */
225
226/* The pthread_in_use() detection needs to be done at runtime. */
227# define pthread_in_use() \
228 glthread_in_use ()
229extern int glthread_in_use (void);
230
231# endif
232
233# if USE_POSIX_THREADS_WEAK
234
235/* Use weak references to the POSIX threads library. */
236
237/* Weak references avoid dragging in external libraries if the other parts
238 of the program don't use them. Here we use them, because we don't want
239 every program that uses libintl to depend on libpthread. This assumes
240 that libpthread would not be loaded after libintl; i.e. if libintl is
241 loaded first, by an executable that does not depend on libpthread, and
242 then a module is dynamically loaded that depends on libpthread, libintl
243 will not be multithread-safe. */
244
245/* The way to test at runtime whether libpthread is present is to test
246 whether a function pointer's value, such as &pthread_mutex_init, is
247 non-NULL. However, some versions of GCC have a bug through which, in
248 PIC mode, &foo != NULL always evaluates to true if there is a direct
249 call to foo(...) in the same function. To avoid this, we test the
250 address of a function in libpthread that we don't use. */
251
252# pragma weak pthread_mutex_init
253# pragma weak pthread_mutex_lock
254# pragma weak pthread_mutex_unlock
255# pragma weak pthread_mutex_destroy
256# pragma weak pthread_rwlock_init
257# pragma weak pthread_rwlock_rdlock
258# pragma weak pthread_rwlock_wrlock
259# pragma weak pthread_rwlock_unlock
260# pragma weak pthread_rwlock_destroy
261# pragma weak pthread_once
262# pragma weak pthread_cond_init
263# pragma weak pthread_cond_wait
264# pragma weak pthread_cond_signal
265# pragma weak pthread_cond_broadcast
266# pragma weak pthread_cond_destroy
267# pragma weak pthread_mutexattr_init
268# pragma weak pthread_mutexattr_settype
269# pragma weak pthread_mutexattr_destroy
270# pragma weak pthread_rwlockattr_init
271# if __GNU_LIBRARY__ > 1
272# pragma weak pthread_rwlockattr_setkind_np
273# endif
274# pragma weak pthread_rwlockattr_destroy
275# ifndef pthread_self
276# pragma weak pthread_self
277# endif
278
279# if !PTHREAD_IN_USE_DETECTION_HARD
280 /* Considering all platforms with USE_POSIX_THREADS_WEAK, only few symbols
281 can be used to determine whether libpthread is in use. These are:
282 pthread_mutexattr_gettype
283 pthread_rwlockattr_destroy
284 pthread_rwlockattr_init
285 */
286# pragma weak pthread_mutexattr_gettype
287# define pthread_in_use() \
288 (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
289# endif
290
291# else
292
293# if !PTHREAD_IN_USE_DETECTION_HARD
294# define pthread_in_use() 1
295# endif
296
297# endif
298 202
299/* -------------------------- gl_lock_t datatype -------------------------- */ 203/* -------------------------- gl_lock_t datatype -------------------------- */
300 204
@@ -510,26 +414,6 @@ extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *l
510 414
511# endif 415# endif
512 416
513/* -------------------------- gl_once_t datatype -------------------------- */
514
515typedef pthread_once_t gl_once_t;
516# define gl_once_define(STORAGECLASS, NAME) \
517 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
518# if PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK
519# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
520 (pthread_in_use () \
521 ? pthread_once (ONCE_CONTROL, INITFUNCTION) \
522 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
523# else
524# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
525 (pthread_in_use () \
526 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \
527 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
528extern int glthread_once_multithreaded (pthread_once_t *once_control,
529 void (*init_function) (void));
530# endif
531extern int glthread_once_singlethreaded (pthread_once_t *once_control);
532
533# ifdef __cplusplus 417# ifdef __cplusplus
534} 418}
535# endif 419# endif
@@ -546,7 +430,6 @@ extern int glthread_once_singlethreaded (pthread_once_t *once_control);
546# include "windows-mutex.h" 430# include "windows-mutex.h"
547# include "windows-rwlock.h" 431# include "windows-rwlock.h"
548# include "windows-recmutex.h" 432# include "windows-recmutex.h"
549# include "windows-once.h"
550 433
551# ifdef __cplusplus 434# ifdef __cplusplus
552extern "C" { 435extern "C" {
@@ -619,14 +502,6 @@ typedef glwthread_recmutex_t gl_recursive_lock_t;
619# define glthread_recursive_lock_destroy(LOCK) \ 502# define glthread_recursive_lock_destroy(LOCK) \
620 glwthread_recmutex_destroy (LOCK) 503 glwthread_recmutex_destroy (LOCK)
621 504
622/* -------------------------- gl_once_t datatype -------------------------- */
623
624typedef glwthread_once_t gl_once_t;
625# define gl_once_define(STORAGECLASS, NAME) \
626 STORAGECLASS gl_once_t NAME = GLWTHREAD_ONCE_INIT;
627# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
628 (glwthread_once (ONCE_CONTROL, INITFUNCTION), 0)
629
630# ifdef __cplusplus 505# ifdef __cplusplus
631} 506}
632# endif 507# endif
@@ -670,14 +545,6 @@ typedef int gl_recursive_lock_t;
670# define glthread_recursive_lock_unlock(NAME) 0 545# define glthread_recursive_lock_unlock(NAME) 0
671# define glthread_recursive_lock_destroy(NAME) 0 546# define glthread_recursive_lock_destroy(NAME) 0
672 547
673/* -------------------------- gl_once_t datatype -------------------------- */
674
675typedef int gl_once_t;
676# define gl_once_define(STORAGECLASS, NAME) \
677 STORAGECLASS gl_once_t NAME = 0;
678# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
679 (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
680
681#endif 548#endif
682 549
683/* ========================================================================= */ 550/* ========================================================================= */
@@ -784,16 +651,6 @@ typedef int gl_once_t;
784 } \ 651 } \
785 while (0) 652 while (0)
786 653
787/* -------------------------- gl_once_t datatype -------------------------- */
788
789#define gl_once(NAME, INITFUNCTION) \
790 do \
791 { \
792 if (glthread_once (&NAME, INITFUNCTION)) \
793 abort (); \
794 } \
795 while (0)
796
797/* ========================================================================= */ 654/* ========================================================================= */
798 655
799#endif /* _LOCK_H */ 656#endif /* _LOCK_H */
diff --git a/gl/glthread/once.c b/gl/glthread/once.c
new file mode 100644
index 00000000..53211af8
--- /dev/null
+++ b/gl/glthread/once.c
@@ -0,0 +1,80 @@
1/* Once-only initialization in multithreaded situations.
2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17/* Written by Bruno Haible <bruno@clisp.org>, 2005.
18 Based on GCC's gthr-posix.h, gthr-posix95.h. */
19
20#include <config.h>
21
22#include "glthread/once.h"
23
24/* ========================================================================= */
25
26#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
27
28#endif
29
30/* ========================================================================= */
31
32#if USE_POSIX_THREADS
33
34static const pthread_once_t fresh_once = PTHREAD_ONCE_INIT;
35
36int
37glthread_once_singlethreaded (pthread_once_t *once_control)
38{
39 /* We don't know whether pthread_once_t is an integer type, a floating-point
40 type, a pointer type, or a structure type. */
41 char *firstbyte = (char *)once_control;
42 if (*firstbyte == *(const char *)&fresh_once)
43 {
44 /* First time use of once_control. Invert the first byte. */
45 *firstbyte = ~ *(const char *)&fresh_once;
46 return 1;
47 }
48 else
49 return 0;
50}
51
52# if !(PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK)
53
54int
55glthread_once_multithreaded (pthread_once_t *once_control,
56 void (*init_function) (void))
57{
58 int err = pthread_once (once_control, init_function);
59 if (err == ENOSYS)
60 {
61 /* This happens on FreeBSD 11: The pthread_once function in libc returns
62 ENOSYS. */
63 if (glthread_once_singlethreaded (once_control))
64 init_function ();
65 return 0;
66 }
67 return err;
68}
69
70# endif
71
72#endif
73
74/* ========================================================================= */
75
76#if USE_WINDOWS_THREADS
77
78#endif
79
80/* ========================================================================= */
diff --git a/gl/glthread/once.h b/gl/glthread/once.h
new file mode 100644
index 00000000..943bd7a2
--- /dev/null
+++ b/gl/glthread/once.h
@@ -0,0 +1,272 @@
1/* Once-only initialization in multithreaded situations.
2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17/* Written by Bruno Haible <bruno@clisp.org>, 2005.
18 Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-win32.h. */
19
20/* This file contains once-only initialization primitives for use with a given
21 thread library.
22 It does not contain primitives for creating threads or for other
23 synchronization primitives.
24
25 Once-only execution:
26 Type: gl_once_t
27 Initializer: gl_once_define(extern, name)
28 Execution: gl_once (name, initfunction);
29 Equivalent functions with control of error handling:
30 Execution: err = glthread_once (&name, initfunction);
31*/
32
33
34#ifndef _ONCE_H
35#define _ONCE_H
36
37/* This file uses HAVE_THREADS_H. */
38#if !_GL_CONFIG_H_INCLUDED
39 #error "Please include config.h first."
40#endif
41
42#include <errno.h>
43#include <stdlib.h>
44
45#if !defined c11_threads_in_use
46# if HAVE_THREADS_H && USE_POSIX_THREADS_FROM_LIBC
47# define c11_threads_in_use() 1
48# elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK
49# include <threads.h>
50# pragma weak thrd_exit
51# define c11_threads_in_use() (thrd_exit != NULL)
52# else
53# define c11_threads_in_use() 0
54# endif
55#endif
56
57/* ========================================================================= */
58
59#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
60
61/* Use the ISO C threads library. */
62
63# include <threads.h>
64
65# ifdef __cplusplus
66extern "C" {
67# endif
68
69/* -------------------------- gl_once_t datatype -------------------------- */
70
71typedef once_flag gl_once_t;
72# define gl_once_define(STORAGECLASS, NAME) \
73 STORAGECLASS once_flag NAME = ONCE_FLAG_INIT;
74# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
75 (call_once (ONCE_CONTROL, INITFUNCTION), 0)
76
77# ifdef __cplusplus
78}
79# endif
80
81#endif
82
83/* ========================================================================= */
84
85#if USE_POSIX_THREADS
86
87/* Use the POSIX threads library. */
88
89# include <pthread.h>
90
91# ifdef __cplusplus
92extern "C" {
93# endif
94
95# if PTHREAD_IN_USE_DETECTION_HARD
96
97/* The pthread_in_use() detection needs to be done at runtime. */
98# define pthread_in_use() \
99 glthread_in_use ()
100extern int glthread_in_use (void);
101
102# endif
103
104# if USE_POSIX_THREADS_WEAK
105
106/* Use weak references to the POSIX threads library. */
107
108/* Weak references avoid dragging in external libraries if the other parts
109 of the program don't use them. Here we use them, because we don't want
110 every program that uses libintl to depend on libpthread. This assumes
111 that libpthread would not be loaded after libintl; i.e. if libintl is
112 loaded first, by an executable that does not depend on libpthread, and
113 then a module is dynamically loaded that depends on libpthread, libintl
114 will not be multithread-safe. */
115
116/* The way to test at runtime whether libpthread is present is to test
117 whether a function pointer's value, such as &pthread_mutex_init, is
118 non-NULL. However, some versions of GCC have a bug through which, in
119 PIC mode, &foo != NULL always evaluates to true if there is a direct
120 call to foo(...) in the same function. To avoid this, we test the
121 address of a function in libpthread that we don't use. */
122
123# pragma weak pthread_mutex_init
124# pragma weak pthread_mutex_lock
125# pragma weak pthread_mutex_unlock
126# pragma weak pthread_mutex_destroy
127/* Work around clang bug <https://github.com/llvm/llvm-project/issues/104670> */
128# ifndef pthread_rwlock_init
129# pragma weak pthread_rwlock_init
130# endif
131# pragma weak pthread_rwlock_rdlock
132# pragma weak pthread_rwlock_wrlock
133# pragma weak pthread_rwlock_unlock
134# pragma weak pthread_rwlock_destroy
135# pragma weak pthread_once
136# pragma weak pthread_cond_init
137# pragma weak pthread_cond_wait
138# pragma weak pthread_cond_signal
139# pragma weak pthread_cond_broadcast
140# pragma weak pthread_cond_destroy
141# pragma weak pthread_mutexattr_init
142# pragma weak pthread_mutexattr_settype
143# pragma weak pthread_mutexattr_destroy
144/* Work around clang bug <https://github.com/llvm/llvm-project/issues/104670> */
145# ifndef pthread_rwlockattr_init
146# pragma weak pthread_rwlockattr_init
147# endif
148# if __GNU_LIBRARY__ > 1
149# pragma weak pthread_rwlockattr_setkind_np
150# endif
151# pragma weak pthread_rwlockattr_destroy
152# ifndef pthread_self
153# pragma weak pthread_self
154# endif
155
156# if !PTHREAD_IN_USE_DETECTION_HARD
157 /* Considering all platforms with USE_POSIX_THREADS_WEAK, only few symbols
158 can be used to determine whether libpthread is in use. These are:
159 pthread_mutexattr_gettype
160 pthread_rwlockattr_destroy
161 pthread_rwlockattr_init
162 */
163# pragma weak pthread_mutexattr_gettype
164# define pthread_in_use() \
165 (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
166# endif
167
168# else
169
170# if !PTHREAD_IN_USE_DETECTION_HARD
171# define pthread_in_use() 1
172# endif
173
174# endif
175
176/* -------------------------- gl_once_t datatype -------------------------- */
177
178typedef pthread_once_t gl_once_t;
179# define gl_once_define(STORAGECLASS, NAME) \
180 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
181# if PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK
182# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
183 (pthread_in_use () \
184 ? pthread_once (ONCE_CONTROL, INITFUNCTION) \
185 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
186# else
187# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
188 (pthread_in_use () \
189 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \
190 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
191extern int glthread_once_multithreaded (pthread_once_t *once_control,
192 void (*init_function) (void));
193# endif
194extern int glthread_once_singlethreaded (pthread_once_t *once_control);
195
196# ifdef __cplusplus
197}
198# endif
199
200#endif
201
202/* ========================================================================= */
203
204#if USE_WINDOWS_THREADS
205
206# define WIN32_LEAN_AND_MEAN /* avoid including junk */
207# include <windows.h>
208
209# include "windows-once.h"
210
211# ifdef __cplusplus
212extern "C" {
213# endif
214
215/* We can use CRITICAL_SECTION directly, rather than the native Windows Event,
216 Mutex, Semaphore types, because
217 - we need only to synchronize inside a single process (address space),
218 not inter-process locking,
219 - we don't need to support trylock operations. (TryEnterCriticalSection
220 does not work on Windows 95/98/ME. Packages that need trylock usually
221 define their own mutex type.) */
222
223/* There is no way to statically initialize a CRITICAL_SECTION. It needs
224 to be done lazily, once only. For this we need spinlocks. */
225
226/* -------------------------- gl_once_t datatype -------------------------- */
227
228typedef glwthread_once_t gl_once_t;
229# define gl_once_define(STORAGECLASS, NAME) \
230 STORAGECLASS gl_once_t NAME = GLWTHREAD_ONCE_INIT;
231# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
232 (glwthread_once (ONCE_CONTROL, INITFUNCTION), 0)
233
234# ifdef __cplusplus
235}
236# endif
237
238#endif
239
240/* ========================================================================= */
241
242#if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS)
243
244/* Provide dummy implementation if threads are not supported. */
245
246/* -------------------------- gl_once_t datatype -------------------------- */
247
248typedef int gl_once_t;
249# define gl_once_define(STORAGECLASS, NAME) \
250 STORAGECLASS gl_once_t NAME = 0;
251# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
252 (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
253
254#endif
255
256/* ========================================================================= */
257
258/* Macros with built-in error handling. */
259
260/* -------------------------- gl_once_t datatype -------------------------- */
261
262#define gl_once(NAME, INITFUNCTION) \
263 do \
264 { \
265 if (glthread_once (&NAME, INITFUNCTION)) \
266 abort (); \
267 } \
268 while (0)
269
270/* ========================================================================= */
271
272#endif /* _ONCE_H */
diff --git a/gl/glthread/threadlib.c b/gl/glthread/threadlib.c
index 7a776768..a6f7688b 100644
--- a/gl/glthread/threadlib.c
+++ b/gl/glthread/threadlib.c
@@ -1,5 +1,5 @@
1/* Multithreading primitives. 1/* Multithreading primitives.
2 Copyright (C) 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/hard-locale.c b/gl/hard-locale.c
index 653c5809..767906d1 100644
--- a/gl/hard-locale.c
+++ b/gl/hard-locale.c
@@ -1,6 +1,6 @@
1/* hard-locale.c -- Determine whether a locale is hard. 1/* hard-locale.c -- Determine whether a locale is hard.
2 2
3 Copyright (C) 1997-1999, 2002-2004, 2006-2007, 2009-2024 Free Software 3 Copyright (C) 1997-1999, 2002-2004, 2006-2007, 2009-2025 Free Software
4 Foundation, Inc. 4 Foundation, Inc.
5 5
6 This file is free software: you can redistribute it and/or modify 6 This file is free software: you can redistribute it and/or modify
diff --git a/gl/hard-locale.h b/gl/hard-locale.h
index 5d40e522..29808da6 100644
--- a/gl/hard-locale.h
+++ b/gl/hard-locale.h
@@ -1,6 +1,6 @@
1/* Determine whether a locale is hard. 1/* Determine whether a locale is hard.
2 2
3 Copyright (C) 1999, 2003-2004, 2009-2024 Free Software Foundation, Inc. 3 Copyright (C) 1999, 2003-2004, 2009-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/ialloc.c b/gl/ialloc.c
index 8564a15b..881c8f04 100644
--- a/gl/ialloc.c
+++ b/gl/ialloc.c
@@ -1,6 +1,6 @@
1/* malloc with idx_t rather than size_t 1/* malloc with idx_t rather than size_t
2 2
3 Copyright 2021-2024 Free Software Foundation, Inc. 3 Copyright 2021-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/ialloc.h b/gl/ialloc.h
index 2aa94ae7..8bf5dd12 100644
--- a/gl/ialloc.h
+++ b/gl/ialloc.h
@@ -1,6 +1,6 @@
1/* ialloc.h -- malloc with idx_t rather than size_t 1/* ialloc.h -- malloc with idx_t rather than size_t
2 2
3 Copyright 2021-2024 Free Software Foundation, Inc. 3 Copyright 2021-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -29,9 +29,6 @@
29#include <errno.h> 29#include <errno.h>
30#include <stdint.h> 30#include <stdint.h>
31#include <stdlib.h> 31#include <stdlib.h>
32#if defined __CHERI_PURE_CAPABILITY__
33# include <cheri.h>
34#endif
35 32
36_GL_INLINE_HEADER_BEGIN 33_GL_INLINE_HEADER_BEGIN
37#ifndef IALLOC_INLINE 34#ifndef IALLOC_INLINE
@@ -68,19 +65,7 @@ IALLOC_INLINE
68void * 65void *
69irealloc (void *p, idx_t s) 66irealloc (void *p, idx_t s)
70{ 67{
71 if (s <= SIZE_MAX) 68 return s <= SIZE_MAX ? realloc (p, s) : _gl_alloc_nomem ();
72 {
73 /* Work around GNU realloc glitch by treating a zero size as if it
74 were 1, so that returning NULL is equivalent to failing. */
75 p = realloc (p, s | !s);
76#if defined __CHERI_PURE_CAPABILITY__
77 if (p != NULL)
78 p = cheri_bounds_set (p, s);
79#endif
80 return p;
81 }
82 else
83 return _gl_alloc_nomem ();
84} 69}
85 70
86/* icalloc (num, size) is like calloc (num, size). 71/* icalloc (num, size) is like calloc (num, size).
@@ -112,23 +97,9 @@ icalloc (idx_t n, idx_t s)
112IALLOC_INLINE void * 97IALLOC_INLINE void *
113ireallocarray (void *p, idx_t n, idx_t s) 98ireallocarray (void *p, idx_t n, idx_t s)
114{ 99{
115 if (n <= SIZE_MAX && s <= SIZE_MAX) 100 return (n <= SIZE_MAX && s <= SIZE_MAX
116 { 101 ? reallocarray (p, n, s)
117 /* Work around GNU reallocarray glitch by treating a zero size as if 102 : _gl_alloc_nomem ());
118 it were 1, so that returning NULL is equivalent to failing. */
119 size_t nx = n;
120 size_t sx = s;
121 if (n == 0 || s == 0)
122 nx = sx = 1;
123 p = reallocarray (p, nx, sx);
124#if defined __CHERI_PURE_CAPABILITY__
125 if (p != NULL && (n == 0 || s == 0))
126 p = cheri_bounds_set (p, 0);
127#endif
128 return p;
129 }
130 else
131 return _gl_alloc_nomem ();
132} 103}
133 104
134#ifdef __cplusplus 105#ifdef __cplusplus
diff --git a/gl/idpriv-droptemp.c b/gl/idpriv-droptemp.c
index eb882dea..ecaab836 100644
--- a/gl/idpriv-droptemp.c
+++ b/gl/idpriv-droptemp.c
@@ -1,5 +1,5 @@
1/* Dropping uid/gid privileges of the current process temporarily. 1/* Dropping uid/gid privileges of the current process temporarily.
2 Copyright (C) 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2009-2025 Free Software Foundation, Inc.
3 3
4 This program is free software: you can redistribute it and/or modify 4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
@@ -25,18 +25,18 @@
25 25
26/* The privileged uid and gid that the process had earlier. */ 26/* The privileged uid and gid that the process had earlier. */
27#if HAVE_GETUID 27#if HAVE_GETUID
28static int saved_uid = -1; 28static uid_t saved_uid = -1;
29#endif 29#endif
30#if HAVE_GETGID 30#if HAVE_GETGID
31static int saved_gid = -1; 31static gid_t saved_gid = -1;
32#endif 32#endif
33 33
34int 34int
35idpriv_temp_drop (void) 35idpriv_temp_drop (void)
36{ 36{
37#if HAVE_GETEUID && HAVE_GETEGID && (HAVE_SETRESUID || HAVE_SETREUID) && (HAVE_SETRESGID || HAVE_SETREGID) 37#if HAVE_GETEUID && HAVE_GETEGID && (HAVE_SETRESUID || HAVE_SETREUID) && (HAVE_SETRESGID || HAVE_SETREGID)
38 int uid = getuid (); 38 uid_t uid = getuid ();
39 int gid = getgid (); 39 gid_t gid = getgid ();
40 40
41 /* Find out about the privileged uid and gid at the first call. */ 41 /* Find out about the privileged uid and gid at the first call. */
42 if (saved_uid == -1) 42 if (saved_uid == -1)
@@ -124,8 +124,8 @@ int
124idpriv_temp_restore (void) 124idpriv_temp_restore (void)
125{ 125{
126#if HAVE_GETEUID && HAVE_GETEGID && (HAVE_SETRESUID || HAVE_SETREUID) && (HAVE_SETRESGID || HAVE_SETREGID) 126#if HAVE_GETEUID && HAVE_GETEGID && (HAVE_SETRESUID || HAVE_SETREUID) && (HAVE_SETRESGID || HAVE_SETREGID)
127 int uid = getuid (); 127 uid_t uid = getuid ();
128 int gid = getgid (); 128 gid_t gid = getgid ();
129 129
130 if (saved_uid == -1 || saved_gid == -1) 130 if (saved_uid == -1 || saved_gid == -1)
131 /* Caller error: idpriv_temp_drop was never invoked. */ 131 /* Caller error: idpriv_temp_drop was never invoked. */
diff --git a/gl/idpriv.h b/gl/idpriv.h
index a3ae5926..f4f8158e 100644
--- a/gl/idpriv.h
+++ b/gl/idpriv.h
@@ -1,5 +1,5 @@
1/* Dropping uid/gid privileges of the current process. 1/* Dropping uid/gid privileges of the current process.
2 Copyright (C) 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2009-2025 Free Software Foundation, Inc.
3 3
4 This program is free software: you can redistribute it and/or modify 4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
diff --git a/gl/idx.h b/gl/idx.h
index 43793f2d..639b6cf0 100644
--- a/gl/idx.h
+++ b/gl/idx.h
@@ -1,5 +1,5 @@
1/* A type for indices and sizes. 1/* A type for indices and sizes.
2 Copyright (C) 2020-2024 Free Software Foundation, Inc. 2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 4
5 The GNU C Library is free software; you can redistribute it and/or 5 The GNU C Library is free software; you can redistribute it and/or
diff --git a/gl/inet_ntop.c b/gl/inet_ntop.c
index 0a4ba20e..df3d9512 100644
--- a/gl/inet_ntop.c
+++ b/gl/inet_ntop.c
@@ -1,6 +1,6 @@
1/* inet_ntop.c -- convert IPv4 and IPv6 addresses from binary to text form 1/* inet_ntop.c -- convert IPv4 and IPv6 addresses from binary to text form
2 2
3 Copyright (C) 2005-2006, 2008-2024 Free Software Foundation, Inc. 3 Copyright (C) 2005-2006, 2008-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -117,7 +117,7 @@ inet_ntop (int af, const void *restrict src,
117 * 'dst' (as a const) 117 * 'dst' (as a const)
118 * notes: 118 * notes:
119 * (1) uses no statics 119 * (1) uses no statics
120 * (2) takes a u_char* not an in_addr as input 120 * (2) takes a 'unsigned char *' not an in_addr as input
121 * author: 121 * author:
122 * Paul Vixie, 1996. 122 * Paul Vixie, 1996.
123 */ 123 */
diff --git a/gl/inet_pton.c b/gl/inet_pton.c
new file mode 100644
index 00000000..74d55c43
--- /dev/null
+++ b/gl/inet_pton.c
@@ -0,0 +1,268 @@
1/* inet_pton.c -- convert IPv4 and IPv6 addresses from text to binary form
2
3 Copyright (C) 2006, 2008-2025 Free Software Foundation, Inc.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18/*
19 * Copyright (c) 1996,1999 by Internet Software Consortium.
20 *
21 * Permission to use, copy, modify, and distribute this software for any
22 * purpose with or without fee is hereby granted, provided that the above
23 * copyright notice and this permission notice appear in all copies.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
26 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
28 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
29 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
30 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
31 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
32 * SOFTWARE.
33 */
34
35#include <config.h>
36
37/* Specification. */
38#include <arpa/inet.h>
39
40#if HAVE_DECL_INET_PTON
41
42# undef inet_pton
43
44int
45rpl_inet_pton (int af, const char *restrict src, void *restrict dst)
46{
47 return inet_pton (af, src, dst);
48}
49
50#else
51
52# include <c-ctype.h>
53# include <string.h>
54# include <errno.h>
55
56# define NS_INADDRSZ 4
57# define NS_IN6ADDRSZ 16
58# define NS_INT16SZ 2
59
60/*
61 * WARNING: Don't even consider trying to compile this on a system where
62 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
63 */
64
65static int inet_pton4 (const char *src, unsigned char *dst);
66# if HAVE_IPV6
67static int inet_pton6 (const char *src, unsigned char *dst);
68# endif
69
70/* int
71 * inet_pton(af, src, dst)
72 * convert from presentation format (which usually means ASCII printable)
73 * to network format (which is usually some kind of binary format).
74 * return:
75 * 1 if the address was valid for the specified address family
76 * 0 if the address wasn't valid ('dst' is untouched in this case)
77 * -1 if some other error occurred ('dst' is untouched in this case, too)
78 * author:
79 * Paul Vixie, 1996.
80 */
81int
82inet_pton (int af, const char *restrict src, void *restrict dst)
83{
84 switch (af)
85 {
86 case AF_INET:
87 return (inet_pton4 (src, dst));
88
89# if HAVE_IPV6
90 case AF_INET6:
91 return (inet_pton6 (src, dst));
92# endif
93
94 default:
95 errno = EAFNOSUPPORT;
96 return (-1);
97 }
98 /* NOTREACHED */
99}
100
101/* int
102 * inet_pton4(src, dst)
103 * like inet_aton() but without all the hexadecimal, octal (with the
104 * exception of 0) and shorthand.
105 * return:
106 * 1 if 'src' is a valid dotted quad, else 0.
107 * notice:
108 * does not touch 'dst' unless it's returning 1.
109 * author:
110 * Paul Vixie, 1996.
111 */
112static int
113inet_pton4 (const char *restrict src, unsigned char *restrict dst)
114{
115 int saw_digit, octets, ch;
116 unsigned char tmp[NS_INADDRSZ], *tp;
117
118 saw_digit = 0;
119 octets = 0;
120 *(tp = tmp) = 0;
121 while ((ch = *src++) != '\0')
122 {
123
124 if (ch >= '0' && ch <= '9')
125 {
126 unsigned new = *tp * 10 + (ch - '0');
127
128 if (saw_digit && *tp == 0)
129 return (0);
130 if (new > 255)
131 return (0);
132 *tp = new;
133 if (!saw_digit)
134 {
135 if (++octets > 4)
136 return (0);
137 saw_digit = 1;
138 }
139 }
140 else if (ch == '.' && saw_digit)
141 {
142 if (octets == 4)
143 return (0);
144 *++tp = 0;
145 saw_digit = 0;
146 }
147 else
148 return (0);
149 }
150 if (octets < 4)
151 return (0);
152 memcpy (dst, tmp, NS_INADDRSZ);
153 return (1);
154}
155
156# if HAVE_IPV6
157
158/* int
159 * inet_pton6(src, dst)
160 * convert presentation level address to network order binary form.
161 * return:
162 * 1 if 'src' is a valid [RFC1884 2.2] address, else 0.
163 * notice:
164 * (1) does not touch 'dst' unless it's returning 1.
165 * (2) :: in a full address is silently ignored.
166 * credit:
167 * inspired by Mark Andrews.
168 * author:
169 * Paul Vixie, 1996.
170 */
171static int
172inet_pton6 (const char *restrict src, unsigned char *restrict dst)
173{
174 static const char xdigits[] = "0123456789abcdef";
175 unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
176 const char *curtok;
177 int ch, saw_xdigit;
178 unsigned val;
179
180 tp = memset (tmp, '\0', NS_IN6ADDRSZ);
181 endp = tp + NS_IN6ADDRSZ;
182 colonp = NULL;
183 /* Leading :: requires some special handling. */
184 if (*src == ':')
185 if (*++src != ':')
186 return (0);
187 curtok = src;
188 saw_xdigit = 0;
189 val = 0;
190 while ((ch = c_tolower (*src++)) != '\0')
191 {
192 const char *pch;
193
194 pch = strchr (xdigits, ch);
195 if (pch != NULL)
196 {
197 val <<= 4;
198 val |= (pch - xdigits);
199 if (val > 0xffff)
200 return (0);
201 saw_xdigit = 1;
202 continue;
203 }
204 if (ch == ':')
205 {
206 curtok = src;
207 if (!saw_xdigit)
208 {
209 if (colonp)
210 return (0);
211 colonp = tp;
212 continue;
213 }
214 else if (*src == '\0')
215 {
216 return (0);
217 }
218 if (tp + NS_INT16SZ > endp)
219 return (0);
220 *tp++ = (unsigned char) (val >> 8) & 0xff;
221 *tp++ = (unsigned char) val & 0xff;
222 saw_xdigit = 0;
223 val = 0;
224 continue;
225 }
226 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
227 inet_pton4 (curtok, tp) > 0)
228 {
229 tp += NS_INADDRSZ;
230 saw_xdigit = 0;
231 break; /* '\0' was seen by inet_pton4(). */
232 }
233 return (0);
234 }
235 if (saw_xdigit)
236 {
237 if (tp + NS_INT16SZ > endp)
238 return (0);
239 *tp++ = (unsigned char) (val >> 8) & 0xff;
240 *tp++ = (unsigned char) val & 0xff;
241 }
242 if (colonp != NULL)
243 {
244 /*
245 * Since some memmove()'s erroneously fail to handle
246 * overlapping regions, we'll do the shift by hand.
247 */
248 const int n = tp - colonp;
249 int i;
250
251 if (tp == endp)
252 return (0);
253 for (i = 1; i <= n; i++)
254 {
255 endp[-i] = colonp[n - i];
256 colonp[n - i] = 0;
257 }
258 tp = endp;
259 }
260 if (tp != endp)
261 return (0);
262 memcpy (dst, tmp, NS_IN6ADDRSZ);
263 return (1);
264}
265
266# endif
267
268#endif
diff --git a/gl/intprops-internal.h b/gl/intprops-internal.h
index b5ba8d7c..7ace0cdd 100644
--- a/gl/intprops-internal.h
+++ b/gl/intprops-internal.h
@@ -1,6 +1,6 @@
1/* intprops-internal.h -- properties of integer types not visible to users 1/* intprops-internal.h -- properties of integer types not visible to users
2 2
3 Copyright (C) 2001-2024 Free Software Foundation, Inc. 3 Copyright (C) 2001-2025 Free Software Foundation, Inc.
4 4
5 This program is free software: you can redistribute it and/or modify it 5 This program is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Lesser General Public License as published 6 under the terms of the GNU Lesser General Public License as published
@@ -21,7 +21,7 @@
21#include <limits.h> 21#include <limits.h>
22 22
23/* Pacify GCC 13.2 in some calls to _GL_EXPR_SIGNED. */ 23/* Pacify GCC 13.2 in some calls to _GL_EXPR_SIGNED. */
24#if defined __GNUC__ && 4 < __GNUC__ + (3 <= __GNUC_MINOR__) 24#if 4 < __GNUC__ + (3 <= __GNUC_MINOR__) && !defined __clang__
25# pragma GCC diagnostic ignored "-Wtype-limits" 25# pragma GCC diagnostic ignored "-Wtype-limits"
26#endif 26#endif
27 27
@@ -77,10 +77,11 @@
77 77
78/* Does the __typeof__ keyword work? This could be done by 78/* Does the __typeof__ keyword work? This could be done by
79 'configure', but for now it's easier to do it by hand. */ 79 'configure', but for now it's easier to do it by hand. */
80#if (2 <= __GNUC__ \ 80#if ((defined __GNUC__ && 2 <= __GNUC__) \
81 || (4 <= __clang_major__) \ 81 || (defined __clang_major__ && 4 <= __clang_major__) \
82 || (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \ 82 || (defined __IBMC__ && 1210 <= __IBMC__ && defined __IBM__TYPEOF__) \
83 || (0x5110 <= __SUNPRO_C && !__STDC__)) 83 || (defined __SUNPRO_C && 0x5110 <= __SUNPRO_C && !__STDC__) \
84 || (defined _MSC_VER && 1939 <= _MSC_VER))
84# define _GL_HAVE___TYPEOF__ 1 85# define _GL_HAVE___TYPEOF__ 1
85#else 86#else
86# define _GL_HAVE___TYPEOF__ 0 87# define _GL_HAVE___TYPEOF__ 0
@@ -119,8 +120,8 @@
119#endif 120#endif
120 121
121/* True if __builtin_mul_overflow (A, B, P) works when P is non-null. */ 122/* True if __builtin_mul_overflow (A, B, P) works when P is non-null. */
122#if defined __clang_major__ && __clang_major__ < 14 123#if defined __clang_major__ && __clang_major__ < 21
123/* Work around Clang bug <https://bugs.llvm.org/show_bug.cgi?id=16404>. */ 124/* Work around Clang bug <https://github.com/llvm/llvm-project/issues/16778>. */
124# define _GL_HAS_BUILTIN_MUL_OVERFLOW 0 125# define _GL_HAS_BUILTIN_MUL_OVERFLOW 0
125#else 126#else
126# define _GL_HAS_BUILTIN_MUL_OVERFLOW _GL_HAS_BUILTIN_ADD_OVERFLOW 127# define _GL_HAS_BUILTIN_MUL_OVERFLOW _GL_HAS_BUILTIN_ADD_OVERFLOW
@@ -163,7 +164,7 @@
163#if _GL_HAS_BUILTIN_MUL_OVERFLOW 164#if _GL_HAS_BUILTIN_MUL_OVERFLOW
164# if ((9 < __GNUC__ + (3 <= __GNUC_MINOR__) \ 165# if ((9 < __GNUC__ + (3 <= __GNUC_MINOR__) \
165 || (__GNUC__ == 8 && 4 <= __GNUC_MINOR__)) \ 166 || (__GNUC__ == 8 && 4 <= __GNUC_MINOR__)) \
166 && !defined __EDG__) 167 && !defined __clang__ && !defined __EDG__)
167# define _GL_INT_MULTIPLY_WRAPV(a, b, r) __builtin_mul_overflow (a, b, r) 168# define _GL_INT_MULTIPLY_WRAPV(a, b, r) __builtin_mul_overflow (a, b, r)
168# else 169# else
169 /* Work around GCC bug 91450. */ 170 /* Work around GCC bug 91450. */
@@ -182,13 +183,13 @@
182 _GL_INT_OP_WRAPV (a, b, r, *, _GL_INT_MULTIPLY_RANGE_OVERFLOW) 183 _GL_INT_OP_WRAPV (a, b, r, *, _GL_INT_MULTIPLY_RANGE_OVERFLOW)
183#endif 184#endif
184 185
185/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390. See: 186/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25764. See:
186 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193 187 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193
187 https://llvm.org/bugs/show_bug.cgi?id=25390 188 https://github.com/llvm/llvm-project/issues/25764
188 For now, assume all versions of GCC-like compilers generate bogus 189 For now, assume GCC < 14 and all Clang versions generate bogus
189 warnings for _Generic. This matters only for compilers that 190 warnings for _Generic. This matters only for compilers that
190 lack relevant builtins. */ 191 lack relevant builtins. */
191#if __GNUC__ || defined __clang__ 192#if (__GNUC__ && __GNUC__ < 14) || defined __clang__
192# define _GL__GENERIC_BOGUS 1 193# define _GL__GENERIC_BOGUS 1
193#else 194#else
194# define _GL__GENERIC_BOGUS 0 195# define _GL__GENERIC_BOGUS 0
diff --git a/gl/intprops.h b/gl/intprops.h
index 43734f34..2f9fa0a0 100644
--- a/gl/intprops.h
+++ b/gl/intprops.h
@@ -1,6 +1,6 @@
1/* intprops.h -- properties of integer types 1/* intprops.h -- properties of integer types
2 2
3 Copyright (C) 2001-2024 Free Software Foundation, Inc. 3 Copyright (C) 2001-2025 Free Software Foundation, Inc.
4 4
5 This program is free software: you can redistribute it and/or modify it 5 This program is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Lesser General Public License as published 6 under the terms of the GNU Lesser General Public License as published
@@ -34,6 +34,14 @@
34 signed or floating type. Do not evaluate E. */ 34 signed or floating type. Do not evaluate E. */
35#define EXPR_SIGNED(e) _GL_EXPR_SIGNED (e) 35#define EXPR_SIGNED(e) _GL_EXPR_SIGNED (e)
36 36
37/* The same value as as the arithmetic expression E, but with E's type
38 after integer promotions. For example, if E is of type 'enum {A, B}'
39 then 'switch (INT_PROMOTE (E))' pacifies gcc -Wswitch-enum if some
40 enum values are deliberately omitted from the switch's cases.
41 Here, unary + is safer than a cast or inline function, as unary +
42 does only integer promotions and is disallowed on pointers. */
43#define INT_PROMOTE(e) (+ (e))
44
37 45
38/* Minimum and maximum values for integer types and expressions. */ 46/* Minimum and maximum values for integer types and expressions. */
39 47
diff --git a/gl/inttypes.in.h b/gl/inttypes.in.h
index b9ab8a4b..5520ebc5 100644
--- a/gl/inttypes.in.h
+++ b/gl/inttypes.in.h
@@ -1,4 +1,4 @@
1/* Copyright (C) 2006-2024 Free Software Foundation, Inc. 1/* Copyright (C) 2006-2025 Free Software Foundation, Inc.
2 Written by Paul Eggert, Bruno Haible, Derek Price. 2 Written by Paul Eggert, Bruno Haible, Derek Price.
3 This file is part of gnulib. 3 This file is part of gnulib.
4 4
@@ -913,11 +913,11 @@ extern "C" {
913# undef imaxabs 913# undef imaxabs
914# define imaxabs rpl_imaxabs 914# define imaxabs rpl_imaxabs
915# endif 915# endif
916_GL_FUNCDECL_RPL (imaxabs, intmax_t, (intmax_t x)); 916_GL_FUNCDECL_RPL (imaxabs, intmax_t, (intmax_t x), );
917_GL_CXXALIAS_RPL (imaxabs, intmax_t, (intmax_t x)); 917_GL_CXXALIAS_RPL (imaxabs, intmax_t, (intmax_t x));
918# else 918# else
919# if !@HAVE_DECL_IMAXABS@ 919# if !@HAVE_DECL_IMAXABS@
920_GL_FUNCDECL_SYS (imaxabs, intmax_t, (intmax_t x)); 920_GL_FUNCDECL_SYS (imaxabs, intmax_t, (intmax_t x), );
921# endif 921# endif
922_GL_CXXALIAS_SYS (imaxabs, intmax_t, (intmax_t x)); 922_GL_CXXALIAS_SYS (imaxabs, intmax_t, (intmax_t x));
923# endif 923# endif
@@ -944,11 +944,11 @@ typedef struct { intmax_t quot; intmax_t rem; } imaxdiv_t;
944# undef imaxdiv 944# undef imaxdiv
945# define imaxdiv rpl_imaxdiv 945# define imaxdiv rpl_imaxdiv
946# endif 946# endif
947_GL_FUNCDECL_RPL (imaxdiv, imaxdiv_t, (intmax_t numer, intmax_t denom)); 947_GL_FUNCDECL_RPL (imaxdiv, imaxdiv_t, (intmax_t numer, intmax_t denom), );
948_GL_CXXALIAS_RPL (imaxdiv, imaxdiv_t, (intmax_t numer, intmax_t denom)); 948_GL_CXXALIAS_RPL (imaxdiv, imaxdiv_t, (intmax_t numer, intmax_t denom));
949# else 949# else
950# if !@HAVE_DECL_IMAXDIV@ 950# if !@HAVE_DECL_IMAXDIV@
951_GL_FUNCDECL_SYS (imaxdiv, imaxdiv_t, (intmax_t numer, intmax_t denom)); 951_GL_FUNCDECL_SYS (imaxdiv, imaxdiv_t, (intmax_t numer, intmax_t denom), );
952# endif 952# endif
953_GL_CXXALIAS_SYS (imaxdiv, imaxdiv_t, (intmax_t numer, intmax_t denom)); 953_GL_CXXALIAS_SYS (imaxdiv, imaxdiv_t, (intmax_t numer, intmax_t denom));
954# endif 954# endif
@@ -970,7 +970,7 @@ _GL_WARN_ON_USE (imaxdiv, "imaxdiv is unportable - "
970# define strtoimax rpl_strtoimax 970# define strtoimax rpl_strtoimax
971# endif 971# endif
972_GL_FUNCDECL_RPL (strtoimax, intmax_t, 972_GL_FUNCDECL_RPL (strtoimax, intmax_t,
973 (const char *restrict, char **restrict, int) 973 (const char *restrict, char **restrict, int),
974 _GL_ARG_NONNULL ((1))); 974 _GL_ARG_NONNULL ((1)));
975_GL_CXXALIAS_RPL (strtoimax, intmax_t, 975_GL_CXXALIAS_RPL (strtoimax, intmax_t,
976 (const char *restrict, char **restrict, int)); 976 (const char *restrict, char **restrict, int));
@@ -978,7 +978,7 @@ _GL_CXXALIAS_RPL (strtoimax, intmax_t,
978# if !@HAVE_DECL_STRTOIMAX@ 978# if !@HAVE_DECL_STRTOIMAX@
979# undef strtoimax 979# undef strtoimax
980_GL_FUNCDECL_SYS (strtoimax, intmax_t, 980_GL_FUNCDECL_SYS (strtoimax, intmax_t,
981 (const char *restrict, char **restrict, int) 981 (const char *restrict, char **restrict, int),
982 _GL_ARG_NONNULL ((1))); 982 _GL_ARG_NONNULL ((1)));
983# endif 983# endif
984_GL_CXXALIAS_SYS (strtoimax, intmax_t, 984_GL_CXXALIAS_SYS (strtoimax, intmax_t,
@@ -1000,7 +1000,7 @@ _GL_WARN_ON_USE (strtoimax, "strtoimax is unportable - "
1000# define strtoumax rpl_strtoumax 1000# define strtoumax rpl_strtoumax
1001# endif 1001# endif
1002_GL_FUNCDECL_RPL (strtoumax, uintmax_t, 1002_GL_FUNCDECL_RPL (strtoumax, uintmax_t,
1003 (const char *restrict, char **restrict, int) 1003 (const char *restrict, char **restrict, int),
1004 _GL_ARG_NONNULL ((1))); 1004 _GL_ARG_NONNULL ((1)));
1005_GL_CXXALIAS_RPL (strtoumax, uintmax_t, 1005_GL_CXXALIAS_RPL (strtoumax, uintmax_t,
1006 (const char *restrict, char **restrict, int)); 1006 (const char *restrict, char **restrict, int));
@@ -1008,7 +1008,7 @@ _GL_CXXALIAS_RPL (strtoumax, uintmax_t,
1008# if !@HAVE_DECL_STRTOUMAX@ 1008# if !@HAVE_DECL_STRTOUMAX@
1009# undef strtoumax 1009# undef strtoumax
1010_GL_FUNCDECL_SYS (strtoumax, uintmax_t, 1010_GL_FUNCDECL_SYS (strtoumax, uintmax_t,
1011 (const char *restrict, char **restrict, int) 1011 (const char *restrict, char **restrict, int),
1012 _GL_ARG_NONNULL ((1))); 1012 _GL_ARG_NONNULL ((1)));
1013# endif 1013# endif
1014_GL_CXXALIAS_SYS (strtoumax, uintmax_t, 1014_GL_CXXALIAS_SYS (strtoumax, uintmax_t,
diff --git a/gl/iswblank.c b/gl/iswblank.c
index f699850a..6e361f43 100644
--- a/gl/iswblank.c
+++ b/gl/iswblank.c
@@ -1,5 +1,5 @@
1/* Test wide character for being blank. 1/* Test wide character for being blank.
2 Copyright (C) 2008-2024 Free Software Foundation, Inc. 2 Copyright (C) 2008-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/iswctype-impl.h b/gl/iswctype-impl.h
index 999f220c..c87e00ff 100644
--- a/gl/iswctype-impl.h
+++ b/gl/iswctype-impl.h
@@ -1,5 +1,5 @@
1/* Test whether a wide character has a given property. 1/* Test whether a wide character has a given property.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 2 Copyright (C) 2011-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2011. 3 Written by Bruno Haible <bruno@clisp.org>, 2011.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/iswctype.c b/gl/iswctype.c
index f4e6f015..576e93e4 100644
--- a/gl/iswctype.c
+++ b/gl/iswctype.c
@@ -1,5 +1,5 @@
1/* Test whether a wide character has a given property. 1/* Test whether a wide character has a given property.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 2 Copyright (C) 2011-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2011. 3 Written by Bruno Haible <bruno@clisp.org>, 2011.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/iswdigit.c b/gl/iswdigit.c
index 57363ab8..6bba487b 100644
--- a/gl/iswdigit.c
+++ b/gl/iswdigit.c
@@ -1,5 +1,5 @@
1/* Test wide character for being a digit. 1/* Test wide character for being a digit.
2 Copyright (C) 2020-2024 Free Software Foundation, Inc. 2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/iswpunct.c b/gl/iswpunct.c
index c7cb28b5..2b9258a9 100644
--- a/gl/iswpunct.c
+++ b/gl/iswpunct.c
@@ -1,5 +1,5 @@
1/* Test wide character for being a punctuation or symbol character. 1/* Test wide character for being a punctuation or symbol character.
2 Copyright (C) 2023-2024 Free Software Foundation, Inc. 2 Copyright (C) 2023-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/iswxdigit.c b/gl/iswxdigit.c
index d32e3b0f..e154ac80 100644
--- a/gl/iswxdigit.c
+++ b/gl/iswxdigit.c
@@ -1,5 +1,5 @@
1/* Test wide character for being a hexadecimal digit. 1/* Test wide character for being a hexadecimal digit.
2 Copyright (C) 2020-2024 Free Software Foundation, Inc. 2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/itold.c b/gl/itold.c
index e6fbcff4..084eba23 100644
--- a/gl/itold.c
+++ b/gl/itold.c
@@ -1,5 +1,5 @@
1/* Replacement for 'int' to 'long double' conversion routine. 1/* Replacement for 'int' to 'long double' conversion routine.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 2 Copyright (C) 2011-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2011. 3 Written by Bruno Haible <bruno@clisp.org>, 2011.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/langinfo.in.h b/gl/langinfo.in.h
index febbd25f..e16c95b3 100644
--- a/gl/langinfo.in.h
+++ b/gl/langinfo.in.h
@@ -1,5 +1,5 @@
1/* Substitute for and wrapper around <langinfo.h>. 1/* Substitute for and wrapper around <langinfo.h>.
2 Copyright (C) 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2009-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -115,6 +115,18 @@ typedef int nl_item;
115# define ABMON_10 (ABMON_1 + 9) 115# define ABMON_10 (ABMON_1 + 9)
116# define ABMON_11 (ABMON_1 + 10) 116# define ABMON_11 (ABMON_1 + 10)
117# define ABMON_12 (ABMON_1 + 11) 117# define ABMON_12 (ABMON_1 + 11)
118# define ABALTMON_1 10220
119# define ABALTMON_2 (ABALTMON_1 + 1)
120# define ABALTMON_3 (ABALTMON_1 + 2)
121# define ABALTMON_4 (ABALTMON_1 + 3)
122# define ABALTMON_5 (ABALTMON_1 + 4)
123# define ABALTMON_6 (ABALTMON_1 + 5)
124# define ABALTMON_7 (ABALTMON_1 + 6)
125# define ABALTMON_8 (ABALTMON_1 + 7)
126# define ABALTMON_9 (ABALTMON_1 + 8)
127# define ABALTMON_10 (ABALTMON_1 + 9)
128# define ABALTMON_11 (ABALTMON_1 + 10)
129# define ABALTMON_12 (ABALTMON_1 + 11)
118# define ERA 10047 130# define ERA 10047
119# define ERA_D_FMT 10048 131# define ERA_D_FMT 10048
120# define ERA_D_T_FMT 10049 132# define ERA_D_T_FMT 10049
@@ -171,6 +183,37 @@ typedef int nl_item;
171# define GNULIB_defined_ALTMON 1 183# define GNULIB_defined_ALTMON 1
172# endif 184# endif
173 185
186# if !@HAVE_LANGINFO_ABALTMON@
187# if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 27
188# define ABALTMON_1 _NL_ABALTMON_1
189# define ABALTMON_2 _NL_ABALTMON_2
190# define ABALTMON_3 _NL_ABALTMON_3
191# define ABALTMON_4 _NL_ABALTMON_4
192# define ABALTMON_5 _NL_ABALTMON_5
193# define ABALTMON_6 _NL_ABALTMON_6
194# define ABALTMON_7 _NL_ABALTMON_7
195# define ABALTMON_8 _NL_ABALTMON_8
196# define ABALTMON_9 _NL_ABALTMON_9
197# define ABALTMON_10 _NL_ABALTMON_10
198# define ABALTMON_11 _NL_ABALTMON_11
199# define ABALTMON_12 _NL_ABALTMON_12
200# else
201# define ABALTMON_1 10220
202# define ABALTMON_2 (ABALTMON_1 + 1)
203# define ABALTMON_3 (ABALTMON_1 + 2)
204# define ABALTMON_4 (ABALTMON_1 + 3)
205# define ABALTMON_5 (ABALTMON_1 + 4)
206# define ABALTMON_6 (ABALTMON_1 + 5)
207# define ABALTMON_7 (ABALTMON_1 + 6)
208# define ABALTMON_8 (ABALTMON_1 + 7)
209# define ABALTMON_9 (ABALTMON_1 + 8)
210# define ABALTMON_10 (ABALTMON_1 + 9)
211# define ABALTMON_11 (ABALTMON_1 + 10)
212# define ABALTMON_12 (ABALTMON_1 + 11)
213# define GNULIB_defined_ABALTMON 1
214# endif
215# endif
216
174# if !@HAVE_LANGINFO_ERA@ 217# if !@HAVE_LANGINFO_ERA@
175# define ERA 10047 218# define ERA 10047
176# define ERA_D_FMT 10048 219# define ERA_D_FMT 10048
@@ -205,11 +248,11 @@ typedef int nl_item;
205# undef nl_langinfo 248# undef nl_langinfo
206# define nl_langinfo rpl_nl_langinfo 249# define nl_langinfo rpl_nl_langinfo
207# endif 250# endif
208_GL_FUNCDECL_RPL (nl_langinfo, char *, (nl_item item)); 251_GL_FUNCDECL_RPL (nl_langinfo, char *, (nl_item item), );
209_GL_CXXALIAS_RPL (nl_langinfo, char *, (nl_item item)); 252_GL_CXXALIAS_RPL (nl_langinfo, char *, (nl_item item));
210# else 253# else
211# if !@HAVE_NL_LANGINFO@ 254# if !@HAVE_NL_LANGINFO@
212_GL_FUNCDECL_SYS (nl_langinfo, char *, (nl_item item)); 255_GL_FUNCDECL_SYS (nl_langinfo, char *, (nl_item item), );
213# endif 256# endif
214_GL_CXXALIAS_SYS (nl_langinfo, char *, (nl_item item)); 257_GL_CXXALIAS_SYS (nl_langinfo, char *, (nl_item item));
215# endif 258# endif
diff --git a/gl/lc-charset-dispatch.c b/gl/lc-charset-dispatch.c
index e2f8b2f5..91ab6d72 100644
--- a/gl/lc-charset-dispatch.c
+++ b/gl/lc-charset-dispatch.c
@@ -1,5 +1,5 @@
1/* Dispatching based on the current locale's character encoding. 1/* Dispatching based on the current locale's character encoding.
2 Copyright (C) 2018-2024 Free Software Foundation, Inc. 2 Copyright (C) 2018-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/lc-charset-dispatch.h b/gl/lc-charset-dispatch.h
index 4c1cf5f1..554137b6 100644
--- a/gl/lc-charset-dispatch.h
+++ b/gl/lc-charset-dispatch.h
@@ -1,5 +1,5 @@
1/* Dispatching based on the current locale's character encoding. 1/* Dispatching based on the current locale's character encoding.
2 Copyright (C) 2018-2024 Free Software Foundation, Inc. 2 Copyright (C) 2018-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/libc-config.h b/gl/libc-config.h
index 70114608..33da9cf1 100644
--- a/gl/libc-config.h
+++ b/gl/libc-config.h
@@ -1,6 +1,6 @@
1/* System definitions for code taken from the GNU C Library 1/* System definitions for code taken from the GNU C Library
2 2
3 Copyright 2017-2024 Free Software Foundation, Inc. 3 Copyright 2017-2025 Free Software Foundation, Inc.
4 4
5 This program is free software; you can redistribute it and/or 5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public 6 modify it under the terms of the GNU Lesser General Public
@@ -48,6 +48,11 @@
48 48
49/* From glibc <features.h>. */ 49/* From glibc <features.h>. */
50 50
51#if defined __clang__
52 /* clang really only groks GNU C 4.2, regardless of its value of __GNUC__. */
53# undef __GNUC_PREREQ
54# define __GNUC_PREREQ(maj, min) ((maj) < 4 + ((min) <= 2))
55#endif
51#ifndef __GNUC_PREREQ 56#ifndef __GNUC_PREREQ
52# if defined __GNUC__ && defined __GNUC_MINOR__ 57# if defined __GNUC__ && defined __GNUC_MINOR__
53# define __GNUC_PREREQ(maj, min) ((maj) < __GNUC__ + ((min) <= __GNUC_MINOR__)) 58# define __GNUC_PREREQ(maj, min) ((maj) < __GNUC__ + ((min) <= __GNUC_MINOR__))
diff --git a/gl/limits.in.h b/gl/limits.in.h
index c65eb4c1..c33c59e1 100644
--- a/gl/limits.in.h
+++ b/gl/limits.in.h
@@ -1,6 +1,6 @@
1/* A GNU-like <limits.h>. 1/* A GNU-like <limits.h>.
2 2
3 Copyright 2016-2024 Free Software Foundation, Inc. 3 Copyright 2016-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -20,7 +20,7 @@
20#endif 20#endif
21@PRAGMA_COLUMNS@ 21@PRAGMA_COLUMNS@
22 22
23#if defined _GL_ALREADY_INCLUDING_LIMITS_H 23#if defined _@GUARD_PREFIX@_ALREADY_INCLUDING_LIMITS_H
24/* Special invocation convention: 24/* Special invocation convention:
25 On Haiku/x86_64, we have a sequence of nested includes 25 On Haiku/x86_64, we have a sequence of nested includes
26 <limits.h> -> <syslimits.h> -> <limits.h>. 26 <limits.h> -> <syslimits.h> -> <limits.h>.
@@ -34,12 +34,12 @@
34 34
35#ifndef _@GUARD_PREFIX@_LIMITS_H 35#ifndef _@GUARD_PREFIX@_LIMITS_H
36 36
37# define _GL_ALREADY_INCLUDING_LIMITS_H 37# define _@GUARD_PREFIX@_ALREADY_INCLUDING_LIMITS_H
38 38
39/* The include_next requires a split double-inclusion guard. */ 39/* The include_next requires a split double-inclusion guard. */
40# @INCLUDE_NEXT@ @NEXT_LIMITS_H@ 40# @INCLUDE_NEXT@ @NEXT_LIMITS_H@
41 41
42# undef _GL_ALREADY_INCLUDING_LIMITS_H 42# undef _@GUARD_PREFIX@_ALREADY_INCLUDING_LIMITS_H
43 43
44#ifndef _@GUARD_PREFIX@_LIMITS_H 44#ifndef _@GUARD_PREFIX@_LIMITS_H
45#define _@GUARD_PREFIX@_LIMITS_H 45#define _@GUARD_PREFIX@_LIMITS_H
diff --git a/gl/localcharset.c b/gl/localcharset.c
index 93c4baa4..32f6f78e 100644
--- a/gl/localcharset.c
+++ b/gl/localcharset.c
@@ -1,6 +1,6 @@
1/* Determine a canonical name for the current locale's character encoding. 1/* Determine a canonical name for the current locale's character encoding.
2 2
3 Copyright (C) 2000-2006, 2008-2024 Free Software Foundation, Inc. 3 Copyright (C) 2000-2006, 2008-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -380,7 +380,7 @@ static const struct table_entry alias_table[] =
380# if defined OS2 /* OS/2 */ 380# if defined OS2 /* OS/2 */
381 /* The list of encodings is taken from "List of OS/2 Codepages" 381 /* The list of encodings is taken from "List of OS/2 Codepages"
382 by Alex Taylor: 382 by Alex Taylor:
383 <http://altsan.org/os2/toolkits/uls/index.html#codepages>. 383 <https://altsan.org/os2/toolkits/uls/index.html#codepages>.
384 See also "__convcp() of kLIBC": 384 See also "__convcp() of kLIBC":
385 <https://github.com/bitwiseworks/libc/blob/master/src/emx/src/lib/locale/__convcp.c>. */ 385 <https://github.com/bitwiseworks/libc/blob/master/src/emx/src/lib/locale/__convcp.c>. */
386 { "CP1004", "CP1252" }, 386 { "CP1004", "CP1252" },
@@ -939,8 +939,10 @@ locale_charset (void)
939 sprintf (buf, "CP%u", GetACP ()); 939 sprintf (buf, "CP%u", GetACP ());
940 } 940 }
941 /* For a locale name such as "French_France.65001", in Windows 10, 941 /* For a locale name such as "French_France.65001", in Windows 10,
942 setlocale now returns "French_France.utf8" instead. */ 942 setlocale now returns "French_France.utf8" instead, or in the UTF-8
943 if (strcmp (buf + 2, "65001") == 0 || strcmp (buf + 2, "utf8") == 0) 943 environment (with modern system settings) "fr_FR.UTF-8". */
944 if (strcmp (buf + 2, "65001") == 0 || strcmp (buf + 2, "utf8") == 0
945 || strcmp (buf + 2, "UTF-8") == 0)
944 codeset = "UTF-8"; 946 codeset = "UTF-8";
945 else 947 else
946 { 948 {
diff --git a/gl/localcharset.h b/gl/localcharset.h
index 47214024..25e6d099 100644
--- a/gl/localcharset.h
+++ b/gl/localcharset.h
@@ -1,5 +1,5 @@
1/* Determine a canonical name for the current locale's character encoding. 1/* Determine a canonical name for the current locale's character encoding.
2 Copyright (C) 2000-2003, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2000-2003, 2009-2025 Free Software Foundation, Inc.
3 This file is part of the GNU CHARSET Library. 3 This file is part of the GNU CHARSET Library.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/locale.in.h b/gl/locale.in.h
index 1b11a41c..34f8c5b6 100644
--- a/gl/locale.in.h
+++ b/gl/locale.in.h
@@ -1,5 +1,5 @@
1/* A POSIX <locale.h>. 1/* A POSIX <locale.h>.
2 Copyright (C) 2007-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -20,7 +20,7 @@
20@PRAGMA_COLUMNS@ 20@PRAGMA_COLUMNS@
21 21
22#if (defined _WIN32 && !defined __CYGWIN__ && defined __need_locale_t) \ 22#if (defined _WIN32 && !defined __CYGWIN__ && defined __need_locale_t) \
23 || defined _GL_ALREADY_INCLUDING_LOCALE_H 23 || defined _@GUARD_PREFIX@_ALREADY_INCLUDING_LOCALE_H
24 24
25/* Special invocation convention: 25/* Special invocation convention:
26 - Inside mingw header files, 26 - Inside mingw header files,
@@ -34,12 +34,12 @@
34 34
35#ifndef _@GUARD_PREFIX@_LOCALE_H 35#ifndef _@GUARD_PREFIX@_LOCALE_H
36 36
37#define _GL_ALREADY_INCLUDING_LOCALE_H 37#define _@GUARD_PREFIX@_ALREADY_INCLUDING_LOCALE_H
38 38
39/* The include_next requires a split double-inclusion guard. */ 39/* The include_next requires a split double-inclusion guard. */
40#@INCLUDE_NEXT@ @NEXT_LOCALE_H@ 40#@INCLUDE_NEXT@ @NEXT_LOCALE_H@
41 41
42#undef _GL_ALREADY_INCLUDING_LOCALE_H 42#undef _@GUARD_PREFIX@_ALREADY_INCLUDING_LOCALE_H
43 43
44#ifndef _@GUARD_PREFIX@_LOCALE_H 44#ifndef _@GUARD_PREFIX@_LOCALE_H
45#define _@GUARD_PREFIX@_LOCALE_H 45#define _@GUARD_PREFIX@_LOCALE_H
@@ -69,6 +69,85 @@
69# define LC_MESSAGES 1729 69# define LC_MESSAGES 1729
70#endif 70#endif
71 71
72#if !@HAVE_LOCALE_T@
73# if !defined GNULIB_defined_locale_t
74/* The values of the POSIX-standardized LC_* macros are:
75
76 LC_COLLATE LC_CTYPE LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME
77
78 glibc, Solaris, 3 0 5 4 1 2
79 Android
80 macOS, *BSD 1 2 6 3 4 5
81 native Windows 1 2 1729 3 4 5
82
83 We map these to the log2(LC_*_MASK) values, chosen to be compatible with
84 later releases of the same operating system. */
85# if defined __APPLE__ && defined __MACH__ /* macOS */
86/* LC_COLLATE LC_CTYPE LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME
87
88 category 1 2 6 3 4 5
89 log2(LC_*_MASK) 0 1 2 3 4 5
90 */
91# define gl_log2_lc_mask(category) ((0x2543100 >> (4 * (category))) & 0xf)
92# elif defined __FreeBSD__ || defined __DragonFly__ /* FreeBSD */
93/* LC_COLLATE LC_CTYPE LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME
94
95 category 1 2 6 3 4 5
96 log2(LC_*_MASK) 0 1 5 2 3 4
97 */
98# define gl_log2_lc_mask(category) ((category) - 1)
99# elif defined _WIN32 && !defined __CYGWIN__ /* native Windows */
100# define gl_log2_lc_mask(category) \
101 ((category) == LC_MESSAGES ? 0 : (category))
102# else /* glibc, Solaris, Android, NetBSD, OpenBSD */
103# define gl_log2_lc_mask(category) (category)
104# endif
105/* From there we map them to array indices 0..5. */
106# if (gl_log2_lc_mask (LC_COLLATE) == 0 || gl_log2_lc_mask (LC_CTYPE) == 0 \
107 || gl_log2_lc_mask (LC_MESSAGES) == 0)
108 /* glibc, Solaris, Android, macOS, FreeBSD, native Windows */
109# define gl_log2_lcmask_to_index(c) (c)
110# define gl_index_to_log2_lcmask(i) (i)
111# else
112 /* NetBSD, OpenBSD */
113# define gl_log2_lcmask_to_index(c) ((c) - 1)
114# define gl_index_to_log2_lcmask(i) ((i) + 1)
115# endif
116/* Define the LC_*_MASK macros. */
117# define LC_COLLATE_MASK (1 << gl_log2_lc_mask (LC_COLLATE))
118# define LC_CTYPE_MASK (1 << gl_log2_lc_mask (LC_CTYPE))
119# define LC_MESSAGES_MASK (1 << gl_log2_lc_mask (LC_MESSAGES))
120# define LC_MONETARY_MASK (1 << gl_log2_lc_mask (LC_MONETARY))
121# define LC_NUMERIC_MASK (1 << gl_log2_lc_mask (LC_NUMERIC))
122# define LC_TIME_MASK (1 << gl_log2_lc_mask (LC_TIME))
123# define LC_ALL_MASK \
124 (LC_COLLATE_MASK | LC_CTYPE_MASK | LC_MESSAGES_MASK | LC_MONETARY_MASK \
125 | LC_NUMERIC_MASK | LC_TIME_MASK)
126/* Now define the locale_t type. */
127struct gl_locale_category_t
128{
129 char *name;
130 bool is_c_locale;
131# if @HAVE_WINDOWS_LOCALE_T@
132 /* Use the native Windows '_locale_t' type.
133 Documentation:
134 <https://learn.microsoft.com/en-us/cpp/c-runtime-library/locale>
135 This field is NULL if is_c_locale is true. But don't use this NULL value,
136 since for the native Windows *_l functions a null _locale_t means to use
137 the global locale. */
138 _locale_t system_locale;
139# endif
140};
141struct gl_locale_t
142{
143 struct gl_locale_category_t category[6];
144};
145typedef struct gl_locale_t *locale_t;
146# define LC_GLOBAL_LOCALE ((locale_t)(-1))
147# define GNULIB_defined_locale_t 1
148# endif
149#endif
150
72/* On native Windows with MSVC, 'struct lconv' lacks the members int_p_* and 151/* On native Windows with MSVC, 'struct lconv' lacks the members int_p_* and
73 int_n_*. Instead of overriding 'struct lconv', merely define these member 152 int_n_*. Instead of overriding 'struct lconv', merely define these member
74 names as macros. This avoids trouble in C++ mode. */ 153 names as macros. This avoids trouble in C++ mode. */
@@ -83,7 +162,8 @@
83 162
84/* Bionic libc's 'struct lconv' is just a dummy. */ 163/* Bionic libc's 'struct lconv' is just a dummy. */
85#if @REPLACE_STRUCT_LCONV@ 164#if @REPLACE_STRUCT_LCONV@
86# define lconv rpl_lconv 165# if !defined GNULIB_defined_struct_lconv
166# define lconv rpl_lconv
87struct lconv 167struct lconv
88{ 168{
89 /* All 'char *' are actually 'const char *'. */ 169 /* All 'char *' are actually 'const char *'. */
@@ -160,6 +240,8 @@ struct lconv
160 number. */ 240 number. */
161 char int_n_sep_by_space; 241 char int_n_sep_by_space;
162}; 242};
243# define GNULIB_defined_struct_lconv 1
244# endif
163#endif 245#endif
164 246
165#if @GNULIB_LOCALECONV@ 247#if @GNULIB_LOCALECONV@
@@ -168,7 +250,7 @@ struct lconv
168# undef localeconv 250# undef localeconv
169# define localeconv rpl_localeconv 251# define localeconv rpl_localeconv
170# endif 252# endif
171_GL_FUNCDECL_RPL (localeconv, struct lconv *, (void)); 253_GL_FUNCDECL_RPL (localeconv, struct lconv *, (void), );
172_GL_CXXALIAS_RPL (localeconv, struct lconv *, (void)); 254_GL_CXXALIAS_RPL (localeconv, struct lconv *, (void));
173# else 255# else
174_GL_CXXALIAS_SYS (localeconv, struct lconv *, (void)); 256_GL_CXXALIAS_SYS (localeconv, struct lconv *, (void));
@@ -177,8 +259,10 @@ _GL_CXXALIAS_SYS (localeconv, struct lconv *, (void));
177_GL_CXXALIASWARN (localeconv); 259_GL_CXXALIASWARN (localeconv);
178# endif 260# endif
179#elif @REPLACE_STRUCT_LCONV@ 261#elif @REPLACE_STRUCT_LCONV@
180# undef localeconv 262# if !GNULIB_LOCALECONV
181# define localeconv localeconv_used_without_requesting_gnulib_module_localeconv 263# undef localeconv
264# define localeconv localeconv_used_without_requesting_gnulib_module_localeconv
265# endif
182#elif defined GNULIB_POSIXCHECK 266#elif defined GNULIB_POSIXCHECK
183# undef localeconv 267# undef localeconv
184# if HAVE_RAW_DECL_LOCALECONV 268# if HAVE_RAW_DECL_LOCALECONV
@@ -195,7 +279,7 @@ _GL_WARN_ON_USE (localeconv,
195# define setlocale rpl_setlocale 279# define setlocale rpl_setlocale
196# define GNULIB_defined_setlocale 1 280# define GNULIB_defined_setlocale 1
197# endif 281# endif
198_GL_FUNCDECL_RPL (setlocale, char *, (int category, const char *locale)); 282_GL_FUNCDECL_RPL (setlocale, char *, (int category, const char *locale), );
199_GL_CXXALIAS_RPL (setlocale, char *, (int category, const char *locale)); 283_GL_CXXALIAS_RPL (setlocale, char *, (int category, const char *locale));
200# else 284# else
201_GL_CXXALIAS_SYS (setlocale, char *, (int category, const char *locale)); 285_GL_CXXALIAS_SYS (setlocale, char *, (int category, const char *locale));
@@ -216,7 +300,7 @@ _GL_WARN_ON_USE (setlocale, "setlocale works differently on native Windows - "
216# include "setlocale_null.h" 300# include "setlocale_null.h"
217#endif 301#endif
218 302
219#if /*@GNULIB_NEWLOCALE@ ||*/ (@GNULIB_LOCALENAME_UNSAFE@ && @LOCALENAME_ENHANCE_LOCALE_FUNCS@ && @HAVE_NEWLOCALE@) 303#if @GNULIB_NEWLOCALE@ || (@GNULIB_GETLOCALENAME_L_UNSAFE@ && @LOCALENAME_ENHANCE_LOCALE_FUNCS@ && @HAVE_NEWLOCALE@)
220# if @REPLACE_NEWLOCALE@ 304# if @REPLACE_NEWLOCALE@
221# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 305# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
222# undef newlocale 306# undef newlocale
@@ -224,24 +308,22 @@ _GL_WARN_ON_USE (setlocale, "setlocale works differently on native Windows - "
224# define GNULIB_defined_newlocale 1 308# define GNULIB_defined_newlocale 1
225# endif 309# endif
226_GL_FUNCDECL_RPL (newlocale, locale_t, 310_GL_FUNCDECL_RPL (newlocale, locale_t,
227 (int category_mask, const char *name, locale_t base) 311 (int category_mask, const char *name, locale_t base),
228 _GL_ARG_NONNULL ((2))); 312 _GL_ARG_NONNULL ((2)));
229_GL_CXXALIAS_RPL (newlocale, locale_t, 313_GL_CXXALIAS_RPL (newlocale, locale_t,
230 (int category_mask, const char *name, locale_t base)); 314 (int category_mask, const char *name, locale_t base));
231# else 315# else
232# if @HAVE_NEWLOCALE@ 316# if !@HAVE_NEWLOCALE@
317_GL_FUNCDECL_SYS (newlocale, locale_t,
318 (int category_mask, const char *name, locale_t base),
319 _GL_ARG_NONNULL ((2)));
320# endif
233_GL_CXXALIAS_SYS (newlocale, locale_t, 321_GL_CXXALIAS_SYS (newlocale, locale_t,
234 (int category_mask, const char *name, locale_t base)); 322 (int category_mask, const char *name, locale_t base));
235# endif
236# endif 323# endif
237# if __GLIBC__ >= 2 && @HAVE_NEWLOCALE@ 324# if __GLIBC__ >= 2
238_GL_CXXALIASWARN (newlocale); 325_GL_CXXALIASWARN (newlocale);
239# endif 326# endif
240# if @HAVE_NEWLOCALE@ || @REPLACE_NEWLOCALE@
241# ifndef HAVE_WORKING_NEWLOCALE
242# define HAVE_WORKING_NEWLOCALE 1
243# endif
244# endif
245#elif defined GNULIB_POSIXCHECK 327#elif defined GNULIB_POSIXCHECK
246# undef newlocale 328# undef newlocale
247# if HAVE_RAW_DECL_NEWLOCALE 329# if HAVE_RAW_DECL_NEWLOCALE
@@ -249,53 +331,50 @@ _GL_WARN_ON_USE (newlocale, "newlocale is not portable");
249# endif 331# endif
250#endif 332#endif
251 333
252#if @GNULIB_DUPLOCALE@ || (@GNULIB_LOCALENAME_UNSAFE@ && @LOCALENAME_ENHANCE_LOCALE_FUNCS@ && @HAVE_DUPLOCALE@) 334#if @GNULIB_DUPLOCALE@ || (@GNULIB_GETLOCALENAME_L_UNSAFE@ && @LOCALENAME_ENHANCE_LOCALE_FUNCS@ && @HAVE_DUPLOCALE@)
253# if @HAVE_DUPLOCALE@ /* locale_t may be undefined if !@HAVE_DUPLOCALE@. */ 335# if @REPLACE_DUPLOCALE@
254# if @REPLACE_DUPLOCALE@ 336# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
255# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 337# undef duplocale
256# undef duplocale 338# define duplocale rpl_duplocale
257# define duplocale rpl_duplocale 339# define GNULIB_defined_duplocale 1
258# define GNULIB_defined_duplocale 1 340# endif
259# endif 341_GL_FUNCDECL_RPL (duplocale, locale_t, (locale_t locale), _GL_ARG_NONNULL ((1)));
260_GL_FUNCDECL_RPL (duplocale, locale_t, (locale_t locale) _GL_ARG_NONNULL ((1)));
261_GL_CXXALIAS_RPL (duplocale, locale_t, (locale_t locale)); 342_GL_CXXALIAS_RPL (duplocale, locale_t, (locale_t locale));
262# else 343# else
263_GL_CXXALIAS_SYS (duplocale, locale_t, (locale_t locale)); 344# if !@HAVE_DUPLOCALE@
345_GL_FUNCDECL_SYS (duplocale, locale_t, (locale_t locale), _GL_ARG_NONNULL ((1)));
264# endif 346# endif
347_GL_CXXALIAS_SYS (duplocale, locale_t, (locale_t locale));
265# endif 348# endif
266# if __GLIBC__ >= 2 && @HAVE_DUPLOCALE@ 349# if __GLIBC__ >= 2
267_GL_CXXALIASWARN (duplocale); 350_GL_CXXALIASWARN (duplocale);
268# endif 351# endif
269# if @HAVE_DUPLOCALE@
270# ifndef HAVE_WORKING_DUPLOCALE
271# define HAVE_WORKING_DUPLOCALE 1
272# endif
273# endif
274#elif defined GNULIB_POSIXCHECK 352#elif defined GNULIB_POSIXCHECK
275# undef duplocale 353# undef duplocale
276# if HAVE_RAW_DECL_DUPLOCALE 354# if HAVE_RAW_DECL_DUPLOCALE
277_GL_WARN_ON_USE (duplocale, "duplocale is buggy on some glibc systems - " 355_GL_WARN_ON_USE (duplocale, "duplocale is unportable and buggy on some glibc systems - "
278 "use gnulib module duplocale for portability"); 356 "use gnulib module duplocale for portability");
279# endif 357# endif
280#endif 358#endif
281 359
282#if /*@GNULIB_FREELOCALE@ ||*/ (@GNULIB_LOCALENAME_UNSAFE@ && @LOCALENAME_ENHANCE_LOCALE_FUNCS@ && @HAVE_FREELOCALE@) 360#if @GNULIB_FREELOCALE@ || (@GNULIB_GETLOCALENAME_L_UNSAFE@ && @LOCALENAME_ENHANCE_LOCALE_FUNCS@ && @HAVE_FREELOCALE@)
283# if @REPLACE_FREELOCALE@ 361# if @REPLACE_FREELOCALE@
284# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 362# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
285# undef freelocale 363# undef freelocale
286# define freelocale rpl_freelocale 364# define freelocale rpl_freelocale
287# define GNULIB_defined_freelocale 1 365# define GNULIB_defined_freelocale 1
288# endif 366# endif
289_GL_FUNCDECL_RPL (freelocale, void, (locale_t locale) _GL_ARG_NONNULL ((1))); 367_GL_FUNCDECL_RPL (freelocale, void, (locale_t locale), _GL_ARG_NONNULL ((1)));
290_GL_CXXALIAS_RPL (freelocale, void, (locale_t locale)); 368_GL_CXXALIAS_RPL (freelocale, void, (locale_t locale));
291# else 369# else
292# if @HAVE_FREELOCALE@ 370# if !@HAVE_FREELOCALE@
371_GL_FUNCDECL_SYS (freelocale, void, (locale_t locale), _GL_ARG_NONNULL ((1)));
372# endif
293/* Need to cast, because on FreeBSD and Mac OS X 10.13, the return type is 373/* Need to cast, because on FreeBSD and Mac OS X 10.13, the return type is
294 int. */ 374 int. */
295_GL_CXXALIAS_SYS_CAST (freelocale, void, (locale_t locale)); 375_GL_CXXALIAS_SYS_CAST (freelocale, void, (locale_t locale));
296# endif
297# endif 376# endif
298# if __GLIBC__ >= 2 && @HAVE_FREELOCALE@ 377# if __GLIBC__ >= 2
299_GL_CXXALIASWARN (freelocale); 378_GL_CXXALIASWARN (freelocale);
300# endif 379# endif
301#elif defined GNULIB_POSIXCHECK 380#elif defined GNULIB_POSIXCHECK
@@ -305,6 +384,36 @@ _GL_WARN_ON_USE (freelocale, "freelocale is not portable");
305# endif 384# endif
306#endif 385#endif
307 386
387#if @GNULIB_GETLOCALENAME_L@
388# if @REPLACE_GETLOCALENAME_L@
389# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
390# undef getlocalename_l
391# define getlocalename_l rpl_getlocalename_l
392# endif
393_GL_FUNCDECL_RPL (getlocalename_l, const char *,
394 (int category, locale_t locale),
395 _GL_ARG_NONNULL ((2)));
396_GL_CXXALIAS_RPL (getlocalename_l, const char *,
397 (int category, locale_t locale));
398# else
399# if !@HAVE_GETLOCALENAME_L@
400_GL_FUNCDECL_SYS (getlocalename_l, const char *,
401 (int category, locale_t locale),
402 _GL_ARG_NONNULL ((2)));
403# endif
404_GL_CXXALIAS_SYS (getlocalename_l, const char *,
405 (int category, locale_t locale));
406# endif
407# if __GLIBC__ >= 2
408_GL_CXXALIASWARN (getlocalename_l);
409# endif
410#elif defined GNULIB_POSIXCHECK
411# undef getlocalename_l
412# if HAVE_RAW_DECL_GETLOCALENAME_L
413_GL_WARN_ON_USE (getlocalename_l, "getlocalename_l is not portable");
414# endif
415#endif
416
308#endif /* _@GUARD_PREFIX@_LOCALE_H */ 417#endif /* _@GUARD_PREFIX@_LOCALE_H */
309#endif /* _@GUARD_PREFIX@_LOCALE_H */ 418#endif /* _@GUARD_PREFIX@_LOCALE_H */
310#endif /* !(__need_locale_t || _GL_ALREADY_INCLUDING_LOCALE_H) */ 419#endif /* !(__need_locale_t || _@GUARD_PREFIX@_ALREADY_INCLUDING_LOCALE_H) */
diff --git a/gl/localeconv.c b/gl/localeconv.c
index 10fc7b74..a6bbdced 100644
--- a/gl/localeconv.c
+++ b/gl/localeconv.c
@@ -1,5 +1,5 @@
1/* Query locale dependent information for formatting numbers. 1/* Query locale dependent information for formatting numbers.
2 Copyright (C) 2012-2024 Free Software Foundation, Inc. 2 Copyright (C) 2012-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/lseek.c b/gl/lseek.c
index 61bd9fcb..41708787 100644
--- a/gl/lseek.c
+++ b/gl/lseek.c
@@ -1,5 +1,5 @@
1/* An lseek() function that detects pipes. 1/* An lseek() function that detects pipes.
2 Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/lstat.c b/gl/lstat.c
new file mode 100644
index 00000000..bb4a59f1
--- /dev/null
+++ b/gl/lstat.c
@@ -0,0 +1,104 @@
1/* Work around a bug of lstat on some systems
2
3 Copyright (C) 1997-2006, 2008-2025 Free Software Foundation, Inc.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18/* written by Jim Meyering */
19
20/* If the user's config.h happens to include <sys/stat.h>, let it include only
21 the system's <sys/stat.h> here, so that orig_lstat doesn't recurse to
22 rpl_lstat. */
23#define __need_system_sys_stat_h
24#include <config.h>
25
26#if !HAVE_LSTAT
27/* On systems that lack symlinks, our replacement <sys/stat.h> already
28 defined lstat as stat, so there is nothing further to do other than
29 avoid an empty file. */
30typedef int dummy;
31#else /* HAVE_LSTAT */
32
33/* Get the original definition of lstat. It might be defined as a macro. */
34# include <sys/types.h>
35# include <sys/stat.h>
36# undef __need_system_sys_stat_h
37
38static int
39orig_lstat (const char *filename, struct stat *buf)
40{
41 return lstat (filename, buf);
42}
43
44/* Specification. */
45# ifdef __osf__
46/* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc
47 eliminates this include because of the preliminary #include <sys/stat.h>
48 above. */
49# include "sys/stat.h"
50# else
51# include <sys/stat.h>
52# endif
53
54# include "stat-time.h"
55
56# include <string.h>
57# include <errno.h>
58
59/* lstat works differently on Linux and Solaris systems. POSIX (see
60 "pathname resolution" in the glossary) requires that programs like
61 'ls' take into consideration the fact that FILE has a trailing slash
62 when FILE is a symbolic link. On Linux and Solaris 10 systems, the
63 lstat function already has the desired semantics (in treating
64 'lstat ("symlink/", sbuf)' just like 'lstat ("symlink/.", sbuf)',
65 but on Solaris 9 and earlier it does not.
66
67 If FILE has a trailing slash and specifies a symbolic link,
68 then use stat() to get more info on the referent of FILE.
69 If the referent is a non-directory, then set errno to ENOTDIR
70 and return -1. Otherwise, return stat's result. */
71
72int
73rpl_lstat (const char *file, struct stat *sbuf)
74{
75 int result = orig_lstat (file, sbuf);
76
77 /* This replacement file can blindly check against '/' rather than
78 using the ISSLASH macro, because all platforms with '\\' either
79 lack symlinks (mingw) or have working lstat (cygwin) and thus do
80 not compile this file. 0 len should have already been filtered
81 out above, with a failure return of ENOENT. */
82 if (result == 0)
83 {
84 if (S_ISDIR (sbuf->st_mode) || file[strlen (file) - 1] != '/')
85 result = stat_time_normalize (result, sbuf);
86 else
87 {
88 /* At this point, a trailing slash is permitted only on
89 symlink-to-dir; but it should have found information on the
90 directory, not the symlink. Call 'stat' to get info about the
91 link's referent. Our replacement stat guarantees valid results,
92 even if the symlink is not pointing to a directory. */
93 if (!S_ISLNK (sbuf->st_mode))
94 {
95 errno = ENOTDIR;
96 return -1;
97 }
98 result = stat (file, sbuf);
99 }
100 }
101 return result;
102}
103
104#endif /* HAVE_LSTAT */
diff --git a/gl/m4/00gnulib.m4 b/gl/m4/00gnulib.m4
index cd167718..2b205b35 100644
--- a/gl/m4/00gnulib.m4
+++ b/gl/m4/00gnulib.m4
@@ -1,9 +1,10 @@
1# 00gnulib.m4 1# 00gnulib.m4
2# serial 9 2# serial 9
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl This file must be named something that sorts before all other 9dnl This file must be named something that sorts before all other
9dnl gnulib-provided .m4 files. It is needed until the clang fix has 10dnl gnulib-provided .m4 files. It is needed until the clang fix has
diff --git a/gl/m4/__inline.m4 b/gl/m4/__inline.m4
index 20baf164..d1b8257b 100644
--- a/gl/m4/__inline.m4
+++ b/gl/m4/__inline.m4
@@ -1,9 +1,10 @@
1# __inline.m4 1# __inline.m4
2# serial 1 2# serial 1
3dnl Copyright 2017-2024 Free Software Foundation, Inc. 3dnl Copyright 2017-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Test for __inline keyword 9# Test for __inline keyword
9 10
diff --git a/gl/m4/absolute-header.m4 b/gl/m4/absolute-header.m4
index 0abd6d90..5501b07b 100644
--- a/gl/m4/absolute-header.m4
+++ b/gl/m4/absolute-header.m4
@@ -1,9 +1,10 @@
1# absolute-header.m4 1# absolute-header.m4
2# serial 18 2# serial 18
3dnl Copyright (C) 2006-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2006-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Derek Price. 9dnl From Derek Price.
9 10
diff --git a/gl/m4/af_alg.m4 b/gl/m4/af_alg.m4
index 33b74945..38575b6d 100644
--- a/gl/m4/af_alg.m4
+++ b/gl/m4/af_alg.m4
@@ -1,9 +1,10 @@
1# af_alg.m4 1# af_alg.m4
2# serial 6 2# serial 6
3dnl Copyright 2018-2024 Free Software Foundation, Inc. 3dnl Copyright 2018-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Matteo Croce. 9dnl From Matteo Croce.
9 10
diff --git a/gl/m4/alloca.m4 b/gl/m4/alloca.m4
index dc78dc19..68fc6211 100644
--- a/gl/m4/alloca.m4
+++ b/gl/m4/alloca.m4
@@ -1,10 +1,11 @@
1# alloca.m4 1# alloca.m4
2# serial 21 2# serial 21
3dnl Copyright (C) 2002-2004, 2006-2007, 2009-2024 Free Software Foundation, 3dnl Copyright (C) 2002-2004, 2006-2007, 2009-2025 Free Software Foundation,
4dnl Inc. 4dnl Inc.
5dnl This file is free software; the Free Software Foundation 5dnl This file is free software; the Free Software Foundation
6dnl gives unlimited permission to copy and/or distribute it, 6dnl gives unlimited permission to copy and/or distribute it,
7dnl with or without modifications, as long as this notice is preserved. 7dnl with or without modifications, as long as this notice is preserved.
8dnl This file is offered as-is, without any warranty.
8 9
9AC_DEFUN([gl_FUNC_ALLOCA], 10AC_DEFUN([gl_FUNC_ALLOCA],
10[ 11[
diff --git a/gl/m4/arpa_inet_h.m4 b/gl/m4/arpa_inet_h.m4
index 9eac86d7..5dae6f72 100644
--- a/gl/m4/arpa_inet_h.m4
+++ b/gl/m4/arpa_inet_h.m4
@@ -1,9 +1,10 @@
1# arpa_inet_h.m4 1# arpa_inet_h.m4
2# serial 17 2# serial 18
3dnl Copyright (C) 2006, 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2006, 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Written by Simon Josefsson and Bruno Haible 9dnl Written by Simon Josefsson and Bruno Haible
9 10
@@ -68,8 +69,12 @@ AC_DEFUN([gl_ARPA_INET_H_REQUIRE_DEFAULTS],
68AC_DEFUN([gl_ARPA_INET_H_DEFAULTS], 69AC_DEFUN([gl_ARPA_INET_H_DEFAULTS],
69[ 70[
70 dnl Assume proper GNU behavior unless another module says otherwise. 71 dnl Assume proper GNU behavior unless another module says otherwise.
72 HAVE_DECL_HTONL=1; AC_SUBST([HAVE_DECL_HTONL])
73 HAVE_DECL_HTONS=1; AC_SUBST([HAVE_DECL_HTONS])
71 HAVE_DECL_INET_NTOP=1; AC_SUBST([HAVE_DECL_INET_NTOP]) 74 HAVE_DECL_INET_NTOP=1; AC_SUBST([HAVE_DECL_INET_NTOP])
72 HAVE_DECL_INET_PTON=1; AC_SUBST([HAVE_DECL_INET_PTON]) 75 HAVE_DECL_INET_PTON=1; AC_SUBST([HAVE_DECL_INET_PTON])
76 HAVE_DECL_NTOHL=1; AC_SUBST([HAVE_DECL_NTOHL])
77 HAVE_DECL_NTOHS=1; AC_SUBST([HAVE_DECL_NTOHS])
73 REPLACE_INET_NTOP=0; AC_SUBST([REPLACE_INET_NTOP]) 78 REPLACE_INET_NTOP=0; AC_SUBST([REPLACE_INET_NTOP])
74 REPLACE_INET_PTON=0; AC_SUBST([REPLACE_INET_PTON]) 79 REPLACE_INET_PTON=0; AC_SUBST([REPLACE_INET_PTON])
75]) 80])
diff --git a/gl/m4/assert_h.m4 b/gl/m4/assert_h.m4
index b90d0f19..e77524ca 100644
--- a/gl/m4/assert_h.m4
+++ b/gl/m4/assert_h.m4
@@ -1,9 +1,10 @@
1# assert_h.m4 1# assert_h.m4
2# serial 1 2# serial 5
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2011-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Paul Eggert. 9dnl From Paul Eggert.
9 10
@@ -12,30 +13,31 @@ AC_DEFUN([gl_ASSERT_H],
12 AC_CACHE_CHECK([for static_assert], [gl_cv_static_assert], 13 AC_CACHE_CHECK([for static_assert], [gl_cv_static_assert],
13 [gl_saved_CFLAGS=$CFLAGS 14 [gl_saved_CFLAGS=$CFLAGS
14 for gl_working in "yes, a keyword" "yes, an <assert.h> macro"; do 15 for gl_working in "yes, a keyword" "yes, an <assert.h> macro"; do
15 AS_CASE([$gl_working], 16 AS_CASE([$gl_working],
16 [*assert.h*], [CFLAGS="$gl_saved_CFLAGS -DINCLUDE_ASSERT_H"]) 17 [*assert.h*], [CFLAGS="$gl_saved_CFLAGS -DINCLUDE_ASSERT_H"])
17 18 AC_COMPILE_IFELSE(
18 AC_COMPILE_IFELSE( 19 [AC_LANG_PROGRAM(
19 [AC_LANG_PROGRAM( 20 [[#if defined __clang__ && __STDC_VERSION__ < 202311
20 [[#if defined __clang__ && __STDC_VERSION__ < 202311 21 #pragma clang diagnostic error "-Wc2x-extensions"
21 #pragma clang diagnostic error "-Wc2x-extensions" 22 #pragma clang diagnostic error "-Wc++1z-extensions"
22 #pragma clang diagnostic error "-Wc++1z-extensions" 23 #endif
23 #endif 24 #ifdef INCLUDE_ASSERT_H
24 #ifdef INCLUDE_ASSERT_H 25 #include <assert.h>
25 #include <assert.h> 26 #endif
26 #endif 27 static_assert (2 + 2 == 4, "arithmetic does not work");
27 static_assert (2 + 2 == 4, "arithmetic does not work"); 28 static_assert (2 + 2 == 4);
28 static_assert (2 + 2 == 4); 29 ]],
29 ]], 30 [[
30 [[ 31 static_assert (sizeof (char) == 1, "sizeof does not work");
31 static_assert (sizeof (char) == 1, "sizeof does not work"); 32 static_assert (sizeof (char) == 1);
32 static_assert (sizeof (char) == 1); 33 ]])
33 ]])], 34 ],
34 [gl_cv_static_assert=$gl_working], 35 [gl_cv_static_assert=$gl_working],
35 [gl_cv_static_assert=no]) 36 [gl_cv_static_assert=no])
36 CFLAGS=$gl_saved_CFLAGS 37 CFLAGS=$gl_saved_CFLAGS
37 test "$gl_cv_static_assert" != no && break 38 test "$gl_cv_static_assert" != no && break
38 done]) 39 done
40 ])
39 41
40 GL_GENERATE_ASSERT_H=false 42 GL_GENERATE_ASSERT_H=false
41 AS_CASE([$gl_cv_static_assert], 43 AS_CASE([$gl_cv_static_assert],
@@ -48,6 +50,10 @@ AC_DEFUN([gl_ASSERT_H],
48 50
49 dnl The "zz" puts this toward config.h's end, to avoid potential 51 dnl The "zz" puts this toward config.h's end, to avoid potential
50 dnl collisions with other definitions. 52 dnl collisions with other definitions.
53 dnl Hardcode the known configuration results for GCC and clang, so that
54 dnl a configuration made with the C compiler works also with the C++ compiler
55 dnl and vice versa.
56 dnl The seemingly redundant parentheses are necessary for MSVC 14.
51 dnl #undef assert so that programs are not tempted to use it without 57 dnl #undef assert so that programs are not tempted to use it without
52 dnl specifically including assert.h. 58 dnl specifically including assert.h.
53 dnl #undef __ASSERT_H__ so that on IRIX, when programs later include 59 dnl #undef __ASSERT_H__ so that on IRIX, when programs later include
@@ -55,7 +61,18 @@ AC_DEFUN([gl_ASSERT_H],
55 dnl Break the #undef_s apart with a comment so that 'configure' does 61 dnl Break the #undef_s apart with a comment so that 'configure' does
56 dnl not comment them out. 62 dnl not comment them out.
57 AH_VERBATIM([zzstatic_assert], 63 AH_VERBATIM([zzstatic_assert],
58[#if (!defined HAVE_C_STATIC_ASSERT && !defined assert \ 64[#if (!(defined __clang__ \
65 ? (defined __cplusplus \
66 ? __cplusplus >= 201703L \
67 : __STDC_VERSION__ >= 202000L && __clang_major__ >= 16 \
68 && !defined __sun) \
69 : (defined __GNUC__ \
70 ? (defined __cplusplus \
71 ? __cplusplus >= 201103L && __GNUG__ >= 6 \
72 : __STDC_VERSION__ >= 202000L && __GNUC__ >= 13 \
73 && !defined __sun) \
74 : defined HAVE_C_STATIC_ASSERT)) \
75 && !defined assert \
59 && (!defined __cplusplus \ 76 && (!defined __cplusplus \
60 || (__cpp_static_assert < 201411 \ 77 || (__cpp_static_assert < 201411 \
61 && __GNUG__ < 6 && __clang_major__ < 6))) 78 && __GNUG__ < 6 && __clang_major__ < 6)))
@@ -65,8 +82,9 @@ AC_DEFUN([gl_ASSERT_H],
65 #undef/**/__ASSERT_H__ 82 #undef/**/__ASSERT_H__
66 #endif 83 #endif
67 /* Solaris 11.4 <assert.h> defines static_assert as a macro with 2 arguments. 84 /* Solaris 11.4 <assert.h> defines static_assert as a macro with 2 arguments.
68 We need it also to be invocable with a single argument. */ 85 We need it also to be invocable with a single argument.
69 #if defined __sun && (__STDC_VERSION__ - 0 >= 201112L) && !defined __cplusplus 86 Haiku 2022 <assert.h> does not define static_assert at all. */
87 #if (__STDC_VERSION__ - 0 >= 201112L) && !defined __cplusplus
70 #undef/**/static_assert 88 #undef/**/static_assert
71 #define static_assert _Static_assert 89 #define static_assert _Static_assert
72 #endif 90 #endif
diff --git a/gl/m4/base64.m4 b/gl/m4/base64.m4
index 26f2af41..785d31c0 100644
--- a/gl/m4/base64.m4
+++ b/gl/m4/base64.m4
@@ -1,9 +1,10 @@
1# base64.m4 1# base64.m4
2# serial 4 2# serial 4
3dnl Copyright (C) 2004, 2006, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2004, 2006, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_BASE64], 9AC_DEFUN([gl_FUNC_BASE64],
9[ 10[
diff --git a/gl/m4/btowc.m4 b/gl/m4/btowc.m4
index d9dd7036..59d52be6 100644
--- a/gl/m4/btowc.m4
+++ b/gl/m4/btowc.m4
@@ -1,13 +1,15 @@
1# btowc.m4 1# btowc.m4
2# serial 14 2# serial 15
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_BTOWC], 9AC_DEFUN([gl_FUNC_BTOWC],
9[ 10[
10 AC_REQUIRE([gl_WCHAR_H_DEFAULTS]) 11 AC_REQUIRE([gl_WCHAR_H_DEFAULTS])
12 AC_REQUIRE([gt_TYPE_WINT_T])
11 13
12 dnl Check whether <wchar.h> is usable at all, first. Otherwise the test 14 dnl Check whether <wchar.h> is usable at all, first. Otherwise the test
13 dnl program below may lead to an endless loop. See 15 dnl program below may lead to an endless loop. See
@@ -133,6 +135,13 @@ int main ()
133 ]) 135 ])
134 ]) 136 ])
135 137
138 if test $GNULIBHEADERS_OVERRIDE_WINT_T = 1; then
139 dnl On mingw/ucrt, we override the return type of btowc().
140 dnl While the original wint_t (= unsigned short) and the overridden wint_t
141 dnl (= unsigned int) are equivalent in function parameters, this is not
142 dnl the case for function return types.
143 REPLACE_BTOWC=1
144 fi
136 case "$gl_cv_func_btowc_nul" in 145 case "$gl_cv_func_btowc_nul" in
137 *yes) ;; 146 *yes) ;;
138 *) REPLACE_BTOWC=1 ;; 147 *) REPLACE_BTOWC=1 ;;
diff --git a/gl/m4/build-to-host.m4 b/gl/m4/build-to-host.m4
new file mode 100644
index 00000000..01bff8f3
--- /dev/null
+++ b/gl/m4/build-to-host.m4
@@ -0,0 +1,274 @@
1# build-to-host.m4
2# serial 5
3dnl Copyright (C) 2023-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9dnl Written by Bruno Haible.
10
11dnl When the build environment ($build_os) is different from the target runtime
12dnl environment ($host_os), file names may need to be converted from the build
13dnl environment syntax to the target runtime environment syntax. This is
14dnl because the Makefiles are executed (mostly) by build environment tools and
15dnl therefore expect file names in build environment syntax, whereas the runtime
16dnl expects file names in target runtime environment syntax.
17dnl
18dnl For example, if $build_os = cygwin and $host_os = mingw32, filenames need
19dnl be converted from Cygwin syntax to native Windows syntax:
20dnl /cygdrive/c/foo/bar -> C:\foo\bar
21dnl /usr/local/share -> C:\cygwin64\usr\local\share
22dnl
23dnl gl_BUILD_TO_HOST([somedir])
24dnl This macro takes as input an AC_SUBSTed variable 'somedir', which must
25dnl already have its final value assigned, and produces two additional
26dnl AC_SUBSTed variables 'somedir_c' and 'somedir_c_make', that designate the
27dnl same file name value, just in different syntax:
28dnl - somedir_c is the file name in target runtime environment syntax,
29dnl as a C string (starting and ending with a double-quote,
30dnl and with escaped backslashes and double-quotes in
31dnl between).
32dnl - somedir_c_make is the same thing, escaped for use in a Makefile.
33
34AC_DEFUN([gl_BUILD_TO_HOST],
35[
36 AC_REQUIRE([AC_CANONICAL_BUILD])
37 AC_REQUIRE([AC_CANONICAL_HOST])
38 AC_REQUIRE([gl_BUILD_TO_HOST_INIT])
39
40 dnl Define somedir_c.
41 gl_final_[$1]="$[$1]"
42 dnl Translate it from build syntax to host syntax.
43 case "$build_os" in
44 cygwin*)
45 case "$host_os" in
46 mingw* | windows*)
47 gl_final_[$1]=`cygpath -w "$gl_final_[$1]"` ;;
48 esac
49 ;;
50 esac
51 dnl Convert it to C string syntax.
52 [$1]_c=`printf '%s\n' "$gl_final_[$1]" | sed -e "$gl_sed_double_backslashes" -e "$gl_sed_escape_doublequotes" | tr -d "$gl_tr_cr"`
53 [$1]_c='"'"$[$1]_c"'"'
54 AC_SUBST([$1_c])
55
56 dnl Define somedir_c_make.
57 [$1]_c_make=`printf '%s\n' "$[$1]_c" | sed -e "$gl_sed_escape_for_make_1" -e "$gl_sed_escape_for_make_2" | tr -d "$gl_tr_cr"`
58 dnl Use the substituted somedir variable, when possible, so that the user
59 dnl may adjust somedir a posteriori when there are no special characters.
60 if test "$[$1]_c_make" = '\"'"${gl_final_[$1]}"'\"'; then
61 [$1]_c_make='\"$([$1])\"'
62 fi
63 AC_SUBST([$1_c_make])
64])
65
66dnl Some initializations for gl_BUILD_TO_HOST.
67AC_DEFUN([gl_BUILD_TO_HOST_INIT],
68[
69 gl_sed_double_backslashes='s/\\/\\\\/g'
70 gl_sed_escape_doublequotes='s/"/\\"/g'
71changequote(,)dnl
72 gl_sed_escape_for_make_1="s,\\([ \"&'();<>\\\\\`|]\\),\\\\\\1,g"
73changequote([,])dnl
74 gl_sed_escape_for_make_2='s,\$,\\$$,g'
75 dnl Find out how to remove carriage returns from output. Solaris /usr/ucb/tr
76 dnl does not understand '\r'.
77 case `echo r | tr -d '\r'` in
78 '') gl_tr_cr='\015' ;;
79 *) gl_tr_cr='\r' ;;
80 esac
81])
82
83
84dnl The following macros are convenience invocations of gl_BUILD_TO_HOST
85dnl for some of the variables that are defined by Autoconf.
86dnl To do so for _all_ the possible variables, use the module 'configmake'.
87
88dnl Defines bindir_c and bindir_c_make.
89AC_DEFUN_ONCE([gl_BUILD_TO_HOST_BINDIR],
90[
91 dnl Find the final value of bindir.
92 gl_saved_prefix="${prefix}"
93 gl_saved_exec_prefix="${exec_prefix}"
94 gl_saved_bindir="${bindir}"
95 dnl Unfortunately, prefix and exec_prefix get only finally determined
96 dnl at the end of configure.
97 if test "X$prefix" = "XNONE"; then
98 prefix="$ac_default_prefix"
99 fi
100 if test "X$exec_prefix" = "XNONE"; then
101 exec_prefix='${prefix}'
102 fi
103 eval exec_prefix="$exec_prefix"
104 eval bindir="$bindir"
105 gl_BUILD_TO_HOST([bindir])
106 bindir="${gl_saved_bindir}"
107 exec_prefix="${gl_saved_exec_prefix}"
108 prefix="${gl_saved_prefix}"
109])
110
111dnl Defines datadir_c and datadir_c_make,
112dnl where datadir = $(datarootdir)
113AC_DEFUN_ONCE([gl_BUILD_TO_HOST_DATADIR],
114[
115 dnl Find the final value of datadir.
116 gl_saved_prefix="${prefix}"
117 gl_saved_datarootdir="${datarootdir}"
118 gl_saved_datadir="${datadir}"
119 dnl Unfortunately, prefix gets only finally determined at the end of
120 dnl configure.
121 if test "X$prefix" = "XNONE"; then
122 prefix="$ac_default_prefix"
123 fi
124 eval datarootdir="$datarootdir"
125 eval datadir="$datadir"
126 gl_BUILD_TO_HOST([datadir])
127 datadir="${gl_saved_datadir}"
128 datarootdir="${gl_saved_datarootdir}"
129 prefix="${gl_saved_prefix}"
130])
131
132dnl Defines libdir_c and libdir_c_make.
133AC_DEFUN_ONCE([gl_BUILD_TO_HOST_LIBDIR],
134[
135 dnl Find the final value of libdir.
136 gl_saved_prefix="${prefix}"
137 gl_saved_exec_prefix="${exec_prefix}"
138 gl_saved_libdir="${libdir}"
139 dnl Unfortunately, prefix and exec_prefix get only finally determined
140 dnl at the end of configure.
141 if test "X$prefix" = "XNONE"; then
142 prefix="$ac_default_prefix"
143 fi
144 if test "X$exec_prefix" = "XNONE"; then
145 exec_prefix='${prefix}'
146 fi
147 eval exec_prefix="$exec_prefix"
148 eval libdir="$libdir"
149 gl_BUILD_TO_HOST([libdir])
150 libdir="${gl_saved_libdir}"
151 exec_prefix="${gl_saved_exec_prefix}"
152 prefix="${gl_saved_prefix}"
153])
154
155dnl Defines libexecdir_c and libexecdir_c_make.
156AC_DEFUN_ONCE([gl_BUILD_TO_HOST_LIBEXECDIR],
157[
158 dnl Find the final value of libexecdir.
159 gl_saved_prefix="${prefix}"
160 gl_saved_exec_prefix="${exec_prefix}"
161 gl_saved_libexecdir="${libexecdir}"
162 dnl Unfortunately, prefix and exec_prefix get only finally determined
163 dnl at the end of configure.
164 if test "X$prefix" = "XNONE"; then
165 prefix="$ac_default_prefix"
166 fi
167 if test "X$exec_prefix" = "XNONE"; then
168 exec_prefix='${prefix}'
169 fi
170 eval exec_prefix="$exec_prefix"
171 eval libexecdir="$libexecdir"
172 gl_BUILD_TO_HOST([libexecdir])
173 libexecdir="${gl_saved_libexecdir}"
174 exec_prefix="${gl_saved_exec_prefix}"
175 prefix="${gl_saved_prefix}"
176])
177
178dnl Defines localedir_c and localedir_c_make.
179AC_DEFUN_ONCE([gl_BUILD_TO_HOST_LOCALEDIR],
180[
181 dnl Find the final value of localedir.
182 gl_saved_prefix="${prefix}"
183 gl_saved_datarootdir="${datarootdir}"
184 gl_saved_localedir="${localedir}"
185 dnl Unfortunately, prefix gets only finally determined at the end of
186 dnl configure.
187 if test "X$prefix" = "XNONE"; then
188 prefix="$ac_default_prefix"
189 fi
190 eval datarootdir="$datarootdir"
191 eval localedir="$localedir"
192 gl_BUILD_TO_HOST([localedir])
193 localedir="${gl_saved_localedir}"
194 datarootdir="${gl_saved_datarootdir}"
195 prefix="${gl_saved_prefix}"
196])
197
198dnl Defines pkgdatadir_c and pkgdatadir_c_make,
199dnl where pkgdatadir = $(datadir)/$(PACKAGE)
200AC_DEFUN_ONCE([gl_BUILD_TO_HOST_PKGDATADIR],
201[
202 dnl Find the final value of pkgdatadir.
203 gl_saved_prefix="${prefix}"
204 gl_saved_datarootdir="${datarootdir}"
205 gl_saved_datadir="${datadir}"
206 gl_saved_pkgdatadir="${pkgdatadir}"
207 dnl Unfortunately, prefix gets only finally determined at the end of
208 dnl configure.
209 if test "X$prefix" = "XNONE"; then
210 prefix="$ac_default_prefix"
211 fi
212 eval datarootdir="$datarootdir"
213 eval datadir="$datadir"
214 eval pkgdatadir="$pkgdatadir"
215 gl_BUILD_TO_HOST([pkgdatadir])
216 pkgdatadir="${gl_saved_pkgdatadir}"
217 datadir="${gl_saved_datadir}"
218 datarootdir="${gl_saved_datarootdir}"
219 prefix="${gl_saved_prefix}"
220])
221
222dnl Defines pkglibdir_c and pkglibdir_c_make,
223dnl where pkglibdir = $(libdir)/$(PACKAGE)
224AC_DEFUN_ONCE([gl_BUILD_TO_HOST_PKGLIBDIR],
225[
226 dnl Find the final value of pkglibdir.
227 gl_saved_prefix="${prefix}"
228 gl_saved_exec_prefix="${exec_prefix}"
229 gl_saved_libdir="${libdir}"
230 gl_saved_pkglibdir="${pkglibdir}"
231 dnl Unfortunately, prefix and exec_prefix get only finally determined
232 dnl at the end of configure.
233 if test "X$prefix" = "XNONE"; then
234 prefix="$ac_default_prefix"
235 fi
236 if test "X$exec_prefix" = "XNONE"; then
237 exec_prefix='${prefix}'
238 fi
239 eval exec_prefix="$exec_prefix"
240 eval libdir="$libdir"
241 eval pkglibdir="$pkglibdir"
242 gl_BUILD_TO_HOST([pkglibdir])
243 pkglibdir="${gl_saved_pkglibdir}"
244 libdir="${gl_saved_libdir}"
245 exec_prefix="${gl_saved_exec_prefix}"
246 prefix="${gl_saved_prefix}"
247])
248
249dnl Defines pkglibexecdir_c and pkglibexecdir_c_make,
250dnl where pkglibexecdir = $(libexecdir)/$(PACKAGE)
251AC_DEFUN_ONCE([gl_BUILD_TO_HOST_PKGLIBEXECDIR],
252[
253 dnl Find the final value of pkglibexecdir.
254 gl_saved_prefix="${prefix}"
255 gl_saved_exec_prefix="${exec_prefix}"
256 gl_saved_libexecdir="${libexecdir}"
257 gl_saved_pkglibexecdir="${pkglibexecdir}"
258 dnl Unfortunately, prefix and exec_prefix get only finally determined
259 dnl at the end of configure.
260 if test "X$prefix" = "XNONE"; then
261 prefix="$ac_default_prefix"
262 fi
263 if test "X$exec_prefix" = "XNONE"; then
264 exec_prefix='${prefix}'
265 fi
266 eval exec_prefix="$exec_prefix"
267 eval libexecdir="$libexecdir"
268 eval pkglibexecdir="$pkglibexecdir"
269 gl_BUILD_TO_HOST([pkglibexecdir])
270 pkglibexecdir="${gl_saved_pkglibexecdir}"
271 libexecdir="${gl_saved_libexecdir}"
272 exec_prefix="${gl_saved_exec_prefix}"
273 prefix="${gl_saved_prefix}"
274])
diff --git a/gl/m4/builtin-expect.m4 b/gl/m4/builtin-expect.m4
index c7af926b..76d32867 100644
--- a/gl/m4/builtin-expect.m4
+++ b/gl/m4/builtin-expect.m4
@@ -1,11 +1,12 @@
1# builtin-expect.m4 1# builtin-expect.m4
2# serial 1 2# serial 3
3dnl Copyright 2016-2024 Free Software Foundation, Inc. 3dnl Copyright 2016-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Check for __builtin_expect. 9dnl Provide a GCC-compatible __builtin_expect macro in <config.h>.
9 10
10dnl Written by Paul Eggert. 11dnl Written by Paul Eggert.
11 12
@@ -47,5 +48,4 @@ AC_DEFUN([gl___BUILTIN_EXPECT],
47#elif HAVE___BUILTIN_EXPECT == 2 48#elif HAVE___BUILTIN_EXPECT == 2
48# include <builtins.h> 49# include <builtins.h>
49#endif 50#endif
50 ]) 51])])
51])
diff --git a/gl/m4/byteswap.m4 b/gl/m4/byteswap.m4
index 0c76fe93..b53cb4d0 100644
--- a/gl/m4/byteswap.m4
+++ b/gl/m4/byteswap.m4
@@ -1,18 +1,42 @@
1# byteswap.m4 1# byteswap.m4
2# serial 5 2# serial 7
3dnl Copyright (C) 2005, 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2005, 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Written by Oskar Liljeblad. 9dnl Written by Oskar Liljeblad.
9 10
10AC_DEFUN([gl_BYTESWAP], 11AC_DEFUN([gl_BYTESWAP],
11[ 12[
12 dnl Prerequisites of lib/byteswap.in.h. 13 dnl Prerequisites of lib/byteswap.in.h.
13 AC_CHECK_HEADERS([byteswap.h], [ 14 AC_CHECK_HEADERS_ONCE([byteswap.h])
15 if test $ac_cv_header_byteswap_h = yes; then
16 AC_CACHE_CHECK([for working bswap_16, bswap_32, bswap_64],
17 [gl_cv_header_working_byteswap_h],
18 [gl_cv_header_working_byteswap_h=no
19 dnl Check that floating point arguments work.
20 dnl This also checks C libraries with implementations like
21 dnl '#define bswap_16(x) (((x) >> 8 & 0xff) | (((x) & 0xff) << 8))'
22 dnl that mistakenly evaluate their arguments multiple times.
23 AC_COMPILE_IFELSE(
24 [AC_LANG_PROGRAM(
25 [[#include <byteswap.h>
26 ]],
27 [[int value_16 = bswap_16 (0.0);
28 int value_32 = bswap_32 (0.0);
29 int value_64 = bswap_64 (0.0);
30 return !(value_16 + value_32 + value_64);
31 ]])
32 ],
33 [gl_cv_header_working_byteswap_h=yes],
34 [gl_cv_header_working_byteswap_h=no])
35 ])
36 fi
37 if test "$gl_cv_header_working_byteswap_h" = yes; then
14 GL_GENERATE_BYTESWAP_H=false 38 GL_GENERATE_BYTESWAP_H=false
15 ], [ 39 else
16 GL_GENERATE_BYTESWAP_H=true 40 GL_GENERATE_BYTESWAP_H=true
17 ]) 41 fi
18]) 42])
diff --git a/gl/m4/c-bool.m4 b/gl/m4/c-bool.m4
index 0fb0de3b..8fa8bfc8 100644
--- a/gl/m4/c-bool.m4
+++ b/gl/m4/c-bool.m4
@@ -1,9 +1,10 @@
1# c-bool.m4 1# c-bool.m4
2# serial 1 2# serial 3
3dnl Copyright 2022-2024 Free Software Foundation, Inc. 3dnl Copyright 2022-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Check for bool that conforms to C2023. 9# Check for bool that conforms to C2023.
9 10
@@ -29,12 +30,23 @@ AC_DEFUN([gl_C_BOOL],
29 dnl The "zz" puts this toward config.h's end, to avoid potential 30 dnl The "zz" puts this toward config.h's end, to avoid potential
30 dnl collisions with other definitions. 31 dnl collisions with other definitions.
31 dnl If 'bool', 'true' and 'false' do not work, arrange for them to work. 32 dnl If 'bool', 'true' and 'false' do not work, arrange for them to work.
32 dnl In C, this means including <stdbool.h> if it is not already included. 33 dnl Hardcode the known configuration results for GCC and clang, so that
34 dnl a configuration made with the C compiler works also with the C++ compiler
35 dnl and vice versa.
36 dnl The seemingly redundant parentheses are necessary for MSVC 14.
37 dnl "Arrange for them to work", in C, means including <stdbool.h> if it is
38 dnl not already included.
33 dnl However, if the preprocessor mistakenly treats 'true' as 0, 39 dnl However, if the preprocessor mistakenly treats 'true' as 0,
34 dnl define it to a bool expression equal to 1; this is needed in 40 dnl define it to a bool expression equal to 1; this is needed in
35 dnl Sun C++ 5.11 (Oracle Solaris Studio 12.2, 2010) and older. 41 dnl Sun C++ 5.11 (Oracle Solaris Studio 12.2, 2010) and older.
36 AH_VERBATIM([zzbool], 42 AH_VERBATIM([zzbool],
37[#ifndef HAVE_C_BOOL 43[#if !(defined __cplusplus \
44 ? 1 \
45 : (defined __clang__ \
46 ? __STDC_VERSION__ >= 202000L && __clang_major__ >= 15 \
47 : (defined __GNUC__ \
48 ? __STDC_VERSION__ >= 202000L && __GNUC__ >= 13 \
49 : defined HAVE_C_BOOL)))
38# if !defined __cplusplus && !defined __bool_true_false_are_defined 50# if !defined __cplusplus && !defined __bool_true_false_are_defined
39# if HAVE_STDBOOL_H 51# if HAVE_STDBOOL_H
40# include <stdbool.h> 52# include <stdbool.h>
diff --git a/gl/m4/c32rtomb.m4 b/gl/m4/c32rtomb.m4
new file mode 100644
index 00000000..ce26a31e
--- /dev/null
+++ b/gl/m4/c32rtomb.m4
@@ -0,0 +1,187 @@
1# c32rtomb.m4
2# serial 8
3dnl Copyright (C) 2020-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9AC_DEFUN([gl_FUNC_C32RTOMB],
10[
11 AC_REQUIRE([gl_UCHAR_H_DEFAULTS])
12 AC_REQUIRE([AC_CANONICAL_HOST])
13
14 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
15 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
16
17 AC_REQUIRE([gl_CHECK_FUNC_C32RTOMB])
18 if test $gl_cv_func_c32rtomb = no; then
19 HAVE_C32RTOMB=0
20 else
21 dnl When we override mbrtoc32, redefining the meaning of the char32_t
22 dnl values, we need to override c32rtomb as well, for consistency.
23 if test $HAVE_WORKING_MBRTOC32 = 0; then
24 REPLACE_C32RTOMB=1
25 fi
26 AC_CACHE_CHECK([whether c32rtomb return value is correct],
27 [gl_cv_func_c32rtomb_retval],
28 [
29 dnl Initial guess, used when cross-compiling.
30changequote(,)dnl
31 case "$host_os" in
32 # Guess no on AIX.
33 aix*) gl_cv_func_c32rtomb_retval="guessing no" ;;
34 # Guess yes otherwise.
35 *) gl_cv_func_c32rtomb_retval="guessing yes" ;;
36 esac
37changequote([,])dnl
38 AC_RUN_IFELSE(
39 [AC_LANG_SOURCE([[
40#include <stddef.h>
41#ifdef __HAIKU__
42 #include <stdint.h>
43#endif
44#include <uchar.h>
45int main ()
46{
47 int result = 0;
48 if (c32rtomb (NULL, 0, NULL) != 1)
49 result |= 1;
50 return result;
51}]])],
52 [gl_cv_func_c32rtomb_retval=yes],
53 [gl_cv_func_c32rtomb_retval=no],
54 [:])
55 ])
56 case "$gl_cv_func_c32rtomb_retval" in
57 *yes) ;;
58 *) AC_DEFINE([C32RTOMB_RETVAL_BUG], [1],
59 [Define if the c32rtomb function has an incorrect return value.])
60 REPLACE_C32RTOMB=1 ;;
61 esac
62 if test $HAVE_WORKING_C32RTOMB = 0; then
63 REPLACE_C32RTOMB=1
64 fi
65 fi
66])
67
68AC_DEFUN([gl_CHECK_FUNC_C32RTOMB],
69[
70 dnl Cf. gl_CHECK_FUNCS_ANDROID
71 AC_CHECK_DECL([c32rtomb], , ,
72 [[#ifdef __HAIKU__
73 #include <stdint.h>
74 #endif
75 #include <uchar.h>
76 ]])
77 if test $ac_cv_have_decl_c32rtomb = yes; then
78 dnl We can't use AC_CHECK_FUNC here, because c32rtomb() is defined as a
79 dnl static inline function on Haiku 2020.
80 AC_CACHE_CHECK([for c32rtomb], [gl_cv_func_c32rtomb],
81 [AC_LINK_IFELSE(
82 [AC_LANG_PROGRAM(
83 [[#include <stdlib.h>
84 #ifdef __HAIKU__
85 #include <stdint.h>
86 #endif
87 #include <uchar.h>
88 ]],
89 [[char buf[8];
90 return c32rtomb (buf, 0, NULL) == 0;
91 ]])
92 ],
93 [gl_cv_func_c32rtomb=yes],
94 [gl_cv_func_c32rtomb=no])
95 ])
96 else
97 gl_cv_func_c32rtomb=no
98 fi
99])
100
101dnl Test whether c32rtomb works not worse than wcrtomb.
102dnl Result is HAVE_WORKING_C32RTOMB.
103
104AC_DEFUN([gl_C32RTOMB_SANITYCHECK],
105[
106 AC_REQUIRE([AC_PROG_CC])
107 AC_REQUIRE([gl_TYPE_CHAR32_T])
108 AC_REQUIRE([gl_CHECK_FUNC_C32RTOMB])
109 AC_REQUIRE([gt_LOCALE_ZH_CN])
110 AC_REQUIRE([AC_CANONICAL_HOST])
111 if test $GNULIBHEADERS_OVERRIDE_CHAR32_T = 1 || test $gl_cv_func_c32rtomb = no; then
112 HAVE_WORKING_C32RTOMB=0
113 else
114 AC_CACHE_CHECK([whether c32rtomb works as well as wcrtomb],
115 [gl_cv_func_c32rtomb_sanitycheck],
116 [
117 dnl Initial guess, used when cross-compiling or when no suitable locale
118 dnl is present.
119changequote(,)dnl
120 case "$host_os" in
121 # Guess no on Solaris derivatives.
122 solaris*)
123 if test -f /etc/release && grep 'Oracle Solaris' /etc/release >/dev/null; then
124 gl_cv_func_c32rtomb_sanitycheck="guessing yes"
125 else
126 gl_cv_func_c32rtomb_sanitycheck="guessing no"
127 fi
128 ;;
129 # Guess yes otherwise.
130 *)
131 gl_cv_func_c32rtomb_sanitycheck="guessing yes"
132 ;;
133 esac
134changequote([,])dnl
135 if test $LOCALE_ZH_CN != none; then
136 AC_RUN_IFELSE(
137 [AC_LANG_SOURCE([[
138#include <locale.h>
139#include <stdlib.h>
140#include <string.h>
141#include <wchar.h>
142#ifdef __HAIKU__
143 #include <stdint.h>
144#endif
145#include <uchar.h>
146int main ()
147{
148 int result = 0;
149 /* This fails on Solaris 11 OmniOS:
150 c32rtomb returns (size_t)-1.
151 wcrtomb returns 4 (correct). */
152 if (strcmp ("$LOCALE_ZH_CN", "none") != 0
153 && setlocale (LC_ALL, "$LOCALE_ZH_CN") != NULL)
154 {
155 mbstate_t state;
156 wchar_t wc = (wchar_t) 0xBADFACE;
157 char buf[16];
158 memset (&state, '\0', sizeof (mbstate_t));
159 if (mbrtowc (&wc, "\201\060\211\070", 4, &state) == 4
160 && wcrtomb (buf, wc, NULL) == 4
161 && memcmp (buf, "\201\060\211\070", 4) == 0)
162 {
163 char32_t c32 = (wchar_t) 0xBADFACE;
164 memset (&state, '\0', sizeof (mbstate_t));
165 if (mbrtoc32 (&c32, "\201\060\211\070", 4, &state) == 4
166 && c32rtomb (buf, c32, NULL) != 4)
167 result |= 1;
168 }
169 }
170 return result;
171}]])],
172 [gl_cv_func_c32rtomb_sanitycheck=yes],
173 [gl_cv_func_c32rtomb_sanitycheck=no],
174 [:])
175 fi
176 ])
177 case "$gl_cv_func_c32rtomb_sanitycheck" in
178 *yes)
179 HAVE_WORKING_C32RTOMB=1
180 AC_DEFINE([HAVE_WORKING_C32RTOMB], [1],
181 [Define if the c32rtomb function basically works.])
182 ;;
183 *) HAVE_WORKING_C32RTOMB=0 ;;
184 esac
185 fi
186 AC_SUBST([HAVE_WORKING_C32RTOMB])
187])
diff --git a/gl/m4/calloc.m4 b/gl/m4/calloc.m4
index 550cf5cc..ac7d08d4 100644
--- a/gl/m4/calloc.m4
+++ b/gl/m4/calloc.m4
@@ -1,9 +1,10 @@
1# calloc.m4 1# calloc.m4
2# serial 31 2# serial 36
3dnl Copyright (C) 2004-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2004-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Written by Jim Meyering. 9# Written by Jim Meyering.
9 10
@@ -12,42 +13,35 @@ dnl with or without modifications, as long as this notice is preserved.
12# If so, define HAVE_CALLOC. Otherwise, define calloc to rpl_calloc 13# If so, define HAVE_CALLOC. Otherwise, define calloc to rpl_calloc
13# and arrange to use a calloc wrapper function that does work in that case. 14# and arrange to use a calloc wrapper function that does work in that case.
14 15
15# _AC_FUNC_CALLOC_IF([IF-WORKS], [IF-NOT]) 16# gl_FUNC_CALLOC_IF([IF-WORKS], [IF-NOT])
16# ------------------------------------- 17# ---------------------------------------
17# If calloc is compatible with GNU calloc, run IF-WORKS, otherwise, IF-NOT. 18# If calloc is compatible with GNU calloc, run IF-WORKS, otherwise, IF-NOT.
18AC_DEFUN([_AC_FUNC_CALLOC_IF], 19AC_DEFUN([gl_FUNC_CALLOC_IF],
19[ 20[
20 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles 21 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
21 AC_CACHE_CHECK([whether calloc (0, n) and calloc (n, 0) return nonnull], 22 AC_CACHE_CHECK([whether calloc (0, n) and calloc (n, 0) return nonnull],
22 [ac_cv_func_calloc_0_nonnull], 23 [gl_cv_func_calloc_0_nonnull],
23 [if test $cross_compiling != yes; then 24 [AC_RUN_IFELSE(
24 ac_cv_func_calloc_0_nonnull=yes 25 [AC_LANG_PROGRAM(
25 AC_RUN_IFELSE( 26 [[#include <stdlib.h>
26 [AC_LANG_PROGRAM( 27 /* Use pcalloc to test; "volatile" prevents the compiler
27 [AC_INCLUDES_DEFAULT], 28 from optimizing the calloc call away. */
28 [[int result = 0; 29 void *(*volatile pcalloc) (size_t, size_t) = calloc;]],
29 char * volatile p = calloc (0, 0); 30 [[void *p = pcalloc (0, 0);
30 if (!p) 31 int result = !p;
31 result |= 1; 32 free (p);
32 free (p); 33 return result;]])],
33 return result; 34 [gl_cv_func_calloc_0_nonnull=yes],
34 ]])], 35 [gl_cv_func_calloc_0_nonnull=no],
35 [], 36 [AS_CASE([$host_os],
36 [ac_cv_func_calloc_0_nonnull=no]) 37 [# Guess yes on platforms where we know the result.
37 else 38 *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \
38 case "$host_os" in 39 | gnu* | *-musl* | midipix* | midnightbsd* \
39 # Guess yes on glibc systems. 40 | hpux* | solaris* | cygwin* | mingw* | windows* | msys*],
40 *-gnu* | gnu*) ac_cv_func_calloc_0_nonnull="guessing yes" ;; 41 [gl_cv_func_calloc_0_nonnull="guessing yes"],
41 # Guess yes on musl systems. 42 [# If we don't know, obey --enable-cross-guesses.
42 *-musl* | midipix*) ac_cv_func_calloc_0_nonnull="guessing yes" ;; 43 gl_cv_func_calloc_0_nonnull="$gl_cross_guess_normal"])])])
43 # Guess yes on native Windows. 44 AS_CASE([$gl_cv_func_calloc_0_nonnull], [*yes], [$1], [$2])
44 mingw* | windows*) ac_cv_func_calloc_0_nonnull="guessing yes" ;;
45 # If we don't know, obey --enable-cross-guesses.
46 *) ac_cv_func_calloc_0_nonnull="$gl_cross_guess_normal" ;;
47 esac
48 fi
49 ])
50 AS_CASE([$ac_cv_func_calloc_0_nonnull], [*yes], [$1], [$2])
51]) 45])
52 46
53 47
@@ -58,9 +52,14 @@ AC_DEFUN([gl_FUNC_CALLOC_GNU],
58[ 52[
59 AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) 53 AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
60 AC_REQUIRE([gl_FUNC_CALLOC_POSIX]) 54 AC_REQUIRE([gl_FUNC_CALLOC_POSIX])
55
56 dnl Through the dependency on module extensions-aix, _LINUX_SOURCE_COMPAT
57 dnl gets defined already before this macro gets invoked. This helps
58 dnl if !(__VEC__ || __AIXVEC), and doesn't hurt otherwise.
59
61 REPLACE_CALLOC_FOR_CALLOC_GNU="$REPLACE_CALLOC_FOR_CALLOC_POSIX" 60 REPLACE_CALLOC_FOR_CALLOC_GNU="$REPLACE_CALLOC_FOR_CALLOC_POSIX"
62 if test $REPLACE_CALLOC_FOR_CALLOC_GNU = 0; then 61 if test $REPLACE_CALLOC_FOR_CALLOC_GNU = 0; then
63 _AC_FUNC_CALLOC_IF([], [REPLACE_CALLOC_FOR_CALLOC_GNU=1]) 62 gl_FUNC_CALLOC_IF([], [REPLACE_CALLOC_FOR_CALLOC_GNU=1])
64 fi 63 fi
65])# gl_FUNC_CALLOC_GNU 64])# gl_FUNC_CALLOC_GNU
66 65
@@ -73,9 +72,7 @@ AC_DEFUN([gl_FUNC_CALLOC_POSIX],
73[ 72[
74 AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) 73 AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
75 AC_REQUIRE([gl_FUNC_MALLOC_POSIX]) 74 AC_REQUIRE([gl_FUNC_MALLOC_POSIX])
76 if test $REPLACE_MALLOC_FOR_MALLOC_POSIX = 1; then 75 REPLACE_CALLOC_FOR_CALLOC_POSIX=$REPLACE_MALLOC_FOR_MALLOC_POSIX
77 REPLACE_CALLOC_FOR_CALLOC_POSIX=1
78 fi
79 dnl Although in theory we should also test for size_t overflow, 76 dnl Although in theory we should also test for size_t overflow,
80 dnl in practice testing for ptrdiff_t overflow suffices 77 dnl in practice testing for ptrdiff_t overflow suffices
81 dnl since PTRDIFF_MAX <= SIZE_MAX on all known Gnulib porting targets. 78 dnl since PTRDIFF_MAX <= SIZE_MAX on all known Gnulib porting targets.
diff --git a/gl/m4/close.m4 b/gl/m4/close.m4
index 88c37fab..314e321e 100644
--- a/gl/m4/close.m4
+++ b/gl/m4/close.m4
@@ -1,9 +1,10 @@
1# close.m4 1# close.m4
2# serial 10 2# serial 10
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN_ONCE([gl_FUNC_CLOSE], 9AC_DEFUN_ONCE([gl_FUNC_CLOSE],
9[ 10[
diff --git a/gl/m4/codeset.m4 b/gl/m4/codeset.m4
index e69b7402..6bed9dee 100644
--- a/gl/m4/codeset.m4
+++ b/gl/m4/codeset.m4
@@ -1,10 +1,11 @@
1# codeset.m4 1# codeset.m4
2# serial 5 (gettext-0.18.2) 2# serial 5 (gettext-0.18.2)
3dnl Copyright (C) 2000-2002, 2006, 2008-2014, 2016, 2019-2024 Free Software 3dnl Copyright (C) 2000-2002, 2006, 2008-2014, 2016, 2019-2025 Free Software
4dnl Foundation, Inc. 4dnl Foundation, Inc.
5dnl This file is free software; the Free Software Foundation 5dnl This file is free software; the Free Software Foundation
6dnl gives unlimited permission to copy and/or distribute it, 6dnl gives unlimited permission to copy and/or distribute it,
7dnl with or without modifications, as long as this notice is preserved. 7dnl with or without modifications, as long as this notice is preserved.
8dnl This file is offered as-is, without any warranty.
8 9
9dnl From Bruno Haible. 10dnl From Bruno Haible.
10 11
diff --git a/gl/m4/double-slash-root.m4 b/gl/m4/double-slash-root.m4
index 3437c699..5c40b73c 100644
--- a/gl/m4/double-slash-root.m4
+++ b/gl/m4/double-slash-root.m4
@@ -1,9 +1,10 @@
1# double-slash-root.m4 1# double-slash-root.m4
2# serial 4 -*- Autoconf -*- 2# serial 4 -*- Autoconf -*-
3dnl Copyright (C) 2006, 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2006, 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_DOUBLE_SLASH_ROOT], 9AC_DEFUN([gl_DOUBLE_SLASH_ROOT],
9[ 10[
diff --git a/gl/m4/dup2.m4 b/gl/m4/dup2.m4
index 786121fd..5da3a0b9 100644
--- a/gl/m4/dup2.m4
+++ b/gl/m4/dup2.m4
@@ -1,9 +1,10 @@
1# dup2.m4 1# dup2.m4
2# serial 28 2# serial 28
3dnl Copyright (C) 2002, 2005, 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2002, 2005, 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_DUP2], 9AC_DEFUN([gl_FUNC_DUP2],
9[ 10[
diff --git a/gl/m4/eealloc.m4 b/gl/m4/eealloc.m4
deleted file mode 100644
index 8a15e705..00000000
--- a/gl/m4/eealloc.m4
+++ /dev/null
@@ -1,32 +0,0 @@
1# eealloc.m4
2# serial 3
3dnl Copyright (C) 2003, 2009-2024 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7
8AC_DEFUN([gl_EEALLOC],
9[
10 AC_REQUIRE([gl_EEMALLOC])
11 AC_REQUIRE([gl_EEREALLOC])
12])
13
14AC_DEFUN([gl_EEMALLOC],
15[
16 _AC_FUNC_MALLOC_IF(
17 [gl_cv_func_malloc_0_nonnull=1],
18 [gl_cv_func_malloc_0_nonnull=0])
19 AC_DEFINE_UNQUOTED([MALLOC_0_IS_NONNULL], [$gl_cv_func_malloc_0_nonnull],
20 [If malloc(0) is != NULL, define this to 1. Otherwise define this
21 to 0.])
22])
23
24AC_DEFUN([gl_EEREALLOC],
25[
26 _AC_FUNC_REALLOC_IF(
27 [gl_cv_func_realloc_0_nonnull=1],
28 [gl_cv_func_realloc_0_nonnull=0])
29 AC_DEFINE_UNQUOTED([REALLOC_0_IS_NONNULL], [$gl_cv_func_realloc_0_nonnull],
30 [If realloc(NULL,0) is != NULL, define this to 1. Otherwise define this
31 to 0.])
32])
diff --git a/gl/m4/environ.m4 b/gl/m4/environ.m4
index 107960b2..e0690e54 100644
--- a/gl/m4/environ.m4
+++ b/gl/m4/environ.m4
@@ -1,9 +1,10 @@
1# environ.m4 1# environ.m4
2# serial 8 2# serial 8
3dnl Copyright (C) 2001-2004, 2006-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2001-2004, 2006-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN_ONCE([gl_ENVIRON], 9AC_DEFUN_ONCE([gl_ENVIRON],
9[ 10[
diff --git a/gl/m4/errno_h.m4 b/gl/m4/errno_h.m4
index b6050e5d..420d5bb3 100644
--- a/gl/m4/errno_h.m4
+++ b/gl/m4/errno_h.m4
@@ -1,15 +1,21 @@
1# errno_h.m4 1# errno_h.m4
2# serial 14 2# serial 18
3dnl Copyright (C) 2004, 2006, 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2004, 2006, 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_PREREQ([2.61]) 9AC_PREREQ([2.61])
9 10
10AC_DEFUN_ONCE([gl_HEADER_ERRNO_H], 11AC_DEFUN_ONCE([gl_HEADER_ERRNO_H],
11[ 12[
12 AC_REQUIRE([AC_PROG_CC]) 13 AC_REQUIRE([AC_PROG_CC])
14
15 dnl Through the dependency on module extensions-aix, _LINUX_SOURCE_COMPAT
16 dnl gets defined already before this macro gets invoked. This persuades
17 dnl AIX 7.3 errno.h to assign ENOTEMPTY a value different than EEXIST.
18
13 AC_CACHE_CHECK([for complete errno.h], [gl_cv_header_errno_h_complete], [ 19 AC_CACHE_CHECK([for complete errno.h], [gl_cv_header_errno_h_complete], [
14 AC_EGREP_CPP([booboo],[ 20 AC_EGREP_CPP([booboo],[
15#include <errno.h> 21#include <errno.h>
@@ -64,6 +70,9 @@ booboo
64#if !defined EILSEQ 70#if !defined EILSEQ
65booboo 71booboo
66#endif 72#endif
73#if !defined ESOCKTNOSUPPORT
74booboo
75#endif
67 ], 76 ],
68 [gl_cv_header_errno_h_complete=no], 77 [gl_cv_header_errno_h_complete=no],
69 [gl_cv_header_errno_h_complete=yes]) 78 [gl_cv_header_errno_h_complete=yes])
diff --git a/gl/m4/error.m4 b/gl/m4/error.m4
index 273b636b..1572250a 100644
--- a/gl/m4/error.m4
+++ b/gl/m4/error.m4
@@ -1,9 +1,11 @@
1# error.m4 1# error.m4
2# serial 16 2# serial 16
3dnl Copyright (C) 1996-1998, 2001-2004, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 1996-1998, 2001-2004, 2009-2025 Free Software Foundation,
4dnl Inc.
4dnl This file is free software; the Free Software Foundation 5dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 6dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 7dnl with or without modifications, as long as this notice is preserved.
8dnl This file is offered as-is, without any warranty.
7 9
8AC_DEFUN([gl_ERROR], 10AC_DEFUN([gl_ERROR],
9[ 11[
diff --git a/gl/m4/error_h.m4 b/gl/m4/error_h.m4
index 050a410c..4ef5cbff 100644
--- a/gl/m4/error_h.m4
+++ b/gl/m4/error_h.m4
@@ -1,9 +1,10 @@
1# error_h.m4 1# error_h.m4
2# serial 4 2# serial 5
3dnl Copyright (C) 1996-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 1996-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Bruno Haible. 9dnl From Bruno Haible.
9dnl Provide a working <error.h>. 10dnl Provide a working <error.h>.
@@ -111,12 +112,15 @@ AC_DEFUN_ONCE([gl_ERROR_H],
111 esac 112 esac
112 fi 113 fi
113 114
114 if test $HAVE_ERROR = 0 || test $REPLACE_ERROR = 1 \ 115 m4_ifdef([gl_HAVE_MODULE_VERROR],
115 || test $HAVE_ERROR_AT_LINE = 0 || test $REPLACE_ERROR_AT_LINE = 1; then 116 [COMPILE_ERROR_C=1],
116 COMPILE_ERROR_C=1 117 [if test $HAVE_ERROR = 0 || test $REPLACE_ERROR = 1 \
117 else 118 || test $HAVE_ERROR_AT_LINE = 0 \
118 COMPILE_ERROR_C=0 119 || test $REPLACE_ERROR_AT_LINE = 1; then
119 fi 120 COMPILE_ERROR_C=1
121 else
122 COMPILE_ERROR_C=0
123 fi])
120 124
121 AC_SUBST([HAVE_ERROR]) 125 AC_SUBST([HAVE_ERROR])
122 AC_SUBST([HAVE_ERROR_AT_LINE]) 126 AC_SUBST([HAVE_ERROR_AT_LINE])
diff --git a/gl/m4/exponentd.m4 b/gl/m4/exponentd.m4
index db597afc..08e93397 100644
--- a/gl/m4/exponentd.m4
+++ b/gl/m4/exponentd.m4
@@ -1,9 +1,10 @@
1# exponentd.m4 1# exponentd.m4
2# serial 4 2# serial 5
3dnl Copyright (C) 2007-2008, 2010-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2008, 2010-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7AC_DEFUN_ONCE([gl_DOUBLE_EXPONENT_LOCATION], 8AC_DEFUN_ONCE([gl_DOUBLE_EXPONENT_LOCATION],
8[ 9[
9 AC_CACHE_CHECK([where to find the exponent in a 'double'], 10 AC_CACHE_CHECK([where to find the exponent in a 'double'],
@@ -84,7 +85,7 @@ int main ()
84 dnl The newer VFP instructions assume little-endian order 85 dnl The newer VFP instructions assume little-endian order
85 dnl consistently. 86 dnl consistently.
86 AC_EGREP_CPP([mixed_endianness], [ 87 AC_EGREP_CPP([mixed_endianness], [
87#if defined arm || defined __arm || defined __arm__ 88#if defined __arm__
88 mixed_endianness 89 mixed_endianness
89#endif 90#endif
90 ], 91 ],
diff --git a/gl/m4/extensions-aix.m4 b/gl/m4/extensions-aix.m4
new file mode 100644
index 00000000..08b703b4
--- /dev/null
+++ b/gl/m4/extensions-aix.m4
@@ -0,0 +1,26 @@
1# extensions-aix.m4
2# serial 1
3dnl Copyright (C) 2024-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9# On AIX, most extensions are already enabled through the _ALL_SOURCE macro,
10# defined by gl_USE_SYSTEM_EXTENSIONS. gl_USE_AIX_EXTENSIONS additionally
11# activates more GNU and Linux-like behaviours, affecting
12# - the time_t type,
13# - errno values in <errno.h>: ENOTEMPTY
14# - functions in <stdlib.h>: malloc calloc realloc valloc
15# <https://www.ibm.com/docs/en/aix/7.3?topic=m-malloc-free-realloc-calloc-mallopt-mallinfo-mallinfo-heap-alloca-valloc-posix-memalign-subroutine>
16# - functions in <string.h>: strerror_r (returns 'char *', like glibc)
17# - functions in <dirent.h>: scandir, alphasort, readdir_r
18# - functions in <netdb.h>: gethostbyname_r gethostbyaddr_r
19# - declarations in <unistd.h>: sbrk
20# and a couple of secondary <sys/*> header files.
21
22AC_DEFUN_ONCE([gl_USE_AIX_EXTENSIONS],
23[
24 AC_DEFINE([_LINUX_SOURCE_COMPAT], [1],
25 [Define so that AIX headers are more compatible with GNU/Linux.])
26])
diff --git a/gl/m4/extensions.m4 b/gl/m4/extensions.m4
index 1fb68956..76516bce 100644
--- a/gl/m4/extensions.m4
+++ b/gl/m4/extensions.m4
@@ -1,9 +1,10 @@
1# extensions.m4 1# extensions.m4
2# serial 25 -*- Autoconf -*- 2# serial 25 -*- Autoconf -*-
3dnl Copyright (C) 2003, 2006-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2003, 2006-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Enable extensions on systems that normally disable them. 9# Enable extensions on systems that normally disable them.
9 10
diff --git a/gl/m4/extern-inline.m4 b/gl/m4/extern-inline.m4
index 547da82a..d4fe6d82 100644
--- a/gl/m4/extern-inline.m4
+++ b/gl/m4/extern-inline.m4
@@ -1,9 +1,10 @@
1# extern-inline.m4 1# extern-inline.m4
2# serial 1 2# serial 1
3dnl Copyright 2012-2024 Free Software Foundation, Inc. 3dnl Copyright 2012-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl 'extern inline' a la ISO C99. 9dnl 'extern inline' a la ISO C99.
9 10
diff --git a/gl/m4/fclose.m4 b/gl/m4/fclose.m4
index 0c1358ed..cfb92e28 100644
--- a/gl/m4/fclose.m4
+++ b/gl/m4/fclose.m4
@@ -1,9 +1,10 @@
1# fclose.m4 1# fclose.m4
2# serial 12 2# serial 12
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN_ONCE([gl_FUNC_FCLOSE], 9AC_DEFUN_ONCE([gl_FUNC_FCLOSE],
9[ 10[
diff --git a/gl/m4/fcntl-o.m4 b/gl/m4/fcntl-o.m4
index 43aa1325..8020c481 100644
--- a/gl/m4/fcntl-o.m4
+++ b/gl/m4/fcntl-o.m4
@@ -1,15 +1,17 @@
1# fcntl-o.m4 1# fcntl-o.m4
2# serial 8 2# serial 12
3dnl Copyright (C) 2006, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2006, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Written by Paul Eggert. 9dnl Written by Paul Eggert.
9 10
10AC_PREREQ([2.60]) 11AC_PREREQ([2.60])
11 12
12# Test whether the flags O_NOATIME and O_NOFOLLOW actually work. 13# Test whether the flags O_DIRECTORY, O_NOATIME and O_NOFOLLOW actually work.
14# Define HAVE_WORKING_O_DIRECTORY to 1 if O_DIRECTORY works, or to 0 otherwise.
13# Define HAVE_WORKING_O_NOATIME to 1 if O_NOATIME works, or to 0 otherwise. 15# Define HAVE_WORKING_O_NOATIME to 1 if O_NOATIME works, or to 0 otherwise.
14# Define HAVE_WORKING_O_NOFOLLOW to 1 if O_NOFOLLOW works, or to 0 otherwise. 16# Define HAVE_WORKING_O_NOFOLLOW to 1 if O_NOFOLLOW works, or to 0 otherwise.
15AC_DEFUN([gl_FCNTL_O_FLAGS], 17AC_DEFUN([gl_FCNTL_O_FLAGS],
@@ -30,16 +32,23 @@ AC_DEFUN([gl_FCNTL_O_FLAGS],
30 #else /* on Windows with MSVC */ 32 #else /* on Windows with MSVC */
31 # include <io.h> 33 # include <io.h>
32 # include <stdlib.h> 34 # include <stdlib.h>
33 # defined sleep(n) _sleep ((n) * 1000) 35 # define sleep(n) _sleep ((n) * 1000)
34 #endif 36 #endif
37 #include <errno.h>
35 #include <fcntl.h> 38 #include <fcntl.h>
36 ]GL_MDA_DEFINES[ 39 ]GL_MDA_DEFINES[
40 #ifndef O_DIRECTORY
41 #define O_DIRECTORY 0
42 #endif
37 #ifndef O_NOATIME 43 #ifndef O_NOATIME
38 #define O_NOATIME 0 44 #define O_NOATIME 0
39 #endif 45 #endif
40 #ifndef O_NOFOLLOW 46 #ifndef O_NOFOLLOW
41 #define O_NOFOLLOW 0 47 #define O_NOFOLLOW 0
42 #endif 48 #endif
49 #ifndef O_SEARCH
50 #define O_SEARCH O_RDONLY
51 #endif
43 static int const constants[] = 52 static int const constants[] =
44 { 53 {
45 O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC, O_APPEND, 54 O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC, O_APPEND,
@@ -52,31 +61,38 @@ AC_DEFUN([gl_FCNTL_O_FLAGS],
52 { 61 {
53 static char const sym[] = "conftest.sym"; 62 static char const sym[] = "conftest.sym";
54 if (symlink ("/dev/null", sym) != 0) 63 if (symlink ("/dev/null", sym) != 0)
55 result |= 2; 64 result |= 1;
56 else 65 else
57 { 66 {
58 int fd = open (sym, O_WRONLY | O_NOFOLLOW | O_CREAT, 0); 67 int fd = open (sym, O_WRONLY | O_NOFOLLOW | O_CREAT, 0);
59 if (fd >= 0) 68 if (fd >= 0)
60 { 69 {
61 close (fd); 70 close (fd);
62 result |= 4; 71 result |= 3;
63 } 72 }
64 } 73 }
65 if (unlink (sym) != 0 || symlink (".", sym) != 0) 74 if (unlink (sym) != 0 || symlink (".", sym) != 0)
66 result |= 2; 75 result |= 1;
67 else 76 else
68 { 77 {
69 int fd = open (sym, O_RDONLY | O_NOFOLLOW); 78 int fd = open (sym, O_RDONLY | O_NOFOLLOW);
70 if (fd >= 0) 79 if (fd >= 0)
71 { 80 {
72 close (fd); 81 close (fd);
73 result |= 4; 82 result |= 3;
74 } 83 }
75 } 84 }
76 unlink (sym); 85 unlink (sym);
77 } 86 }
78 #endif 87 #endif
79 { 88 {
89 int fd = open ("confdefs.h", O_SEARCH | O_DIRECTORY);
90 if (!(fd < 0 && errno == ENOTDIR))
91 result |= 4;
92 if (0 <= fd)
93 close (fd);
94 }
95 {
80 static char const file[] = "confdefs.h"; 96 static char const file[] = "confdefs.h";
81 int fd = open (file, O_RDONLY | O_NOATIME); 97 int fd = open (file, O_RDONLY | O_NOATIME);
82 if (fd < 0) 98 if (fd < 0)
@@ -111,31 +127,46 @@ AC_DEFUN([gl_FCNTL_O_FLAGS],
111 } 127 }
112 return result;]])], 128 return result;]])],
113 [gl_cv_header_working_fcntl_h=yes], 129 [gl_cv_header_working_fcntl_h=yes],
114 [case $? in #( 130 [AS_CASE([$?],
115 4) gl_cv_header_working_fcntl_h='no (bad O_NOFOLLOW)';; #( 131 dnl We cannot catch exit code 1 or 2 here, because
116 64) gl_cv_header_working_fcntl_h='no (bad O_NOATIME)';; #( 132 dnl - exit code 1 can occur through a compilation error on mingw (e.g.
117 68) gl_cv_header_working_fcntl_h='no (bad O_NOATIME, O_NOFOLLOW)';; #( 133 dnl when O_NOCTTY, O_NONBLOCK, O_SYNC are not defined) or when
118 *) gl_cv_header_working_fcntl_h='no';; 134 dnl result = 1, whereas
119 esac], 135 dnl - exit code 2 can occur through a compilation error on MSVC (e.g.
120 [case "$host_os" in 136 dnl again when O_NOCTTY, O_NONBLOCK, O_SYNC are not defined) or when
121 # Guess 'no' on native Windows. 137 dnl result = 2.
122 mingw* | windows*) gl_cv_header_working_fcntl_h='no' ;; 138 [ 3], [gl_cv_header_working_fcntl_h="no (bad O_NOFOLLOW)"],
123 *) gl_cv_header_working_fcntl_h=cross-compiling ;; 139 [ 4], [gl_cv_header_working_fcntl_h="no (bad O_DIRECTORY)"],
124 esac 140 [ 7], [gl_cv_header_working_fcntl_h="no (bad O_NOFOLLOW, O_DIRECTORY)"],
125 ]) 141 [64], [gl_cv_header_working_fcntl_h="no (bad O_NOATIME)"],
126 ]) 142 [67], [gl_cv_header_working_fcntl_h="no (bad O_NOFOLLOW, O_NOATIME)"],
143 [68], [gl_cv_header_working_fcntl_h="no (bad O_DIRECTORY, O_NOATIME)"],
144 [71], [gl_cv_header_working_fcntl_h="no (bad O_NOFOLLOW, O_DIRECTORY, O_NOATIME)"],
145 [gl_cv_header_working_fcntl_h="no"])],
146 [AS_CASE([$host_os,$gl_cross_guess_normal],
147 # The O_DIRECTORY test is known to fail on Mac OS X 10.4.11 (2007)
148 # (see <https://bugs.gnu.org/78509#95>)
149 # and to succeed on Mac OS X 10.5.8 [darwin9.8.0] (2009).
150 # Guess it fails on Mac OS X 10.4.x and earlier.
151 [darwin[[0-8]].*yes],
152 [gl_cv_header_working_fcntl_h="guessing no (bad O_DIRECTORY)"],
153 # Known to be "no" on native MS-Windows.
154 [mingw* | windows*],
155 [gl_cv_header_working_fcntl_h=no],
156 [gl_cv_header_working_fcntl_h=$gl_cross_guess_normal])])])
157
158 AS_CASE([$gl_cv_header_working_fcntl_h],
159 [*O_DIRECTORY* | *no], [gl_val=0], [gl_val=1])
160 AC_DEFINE_UNQUOTED([HAVE_WORKING_O_DIRECTORY], [$gl_val],
161 [Define to 1 if O_DIRECTORY works, 0 otherwise.])
127 162
128 case $gl_cv_header_working_fcntl_h in #( 163 AS_CASE([$gl_cv_header_working_fcntl_h],
129 *O_NOATIME* | no | cross-compiling) ac_val=0;; #( 164 [*O_NOATIME* | *no], [gl_val=0], [gl_val=1])
130 *) ac_val=1;; 165 AC_DEFINE_UNQUOTED([HAVE_WORKING_O_NOATIME], [$gl_val],
131 esac 166 [Define to 1 if O_NOATIME works, 0 otherwise.])
132 AC_DEFINE_UNQUOTED([HAVE_WORKING_O_NOATIME], [$ac_val],
133 [Define to 1 if O_NOATIME works.])
134 167
135 case $gl_cv_header_working_fcntl_h in #( 168 AS_CASE([$gl_cv_header_working_fcntl_h],
136 *O_NOFOLLOW* | no | cross-compiling) ac_val=0;; #( 169 [*O_NOFOLLOW* | *no], [gl_val=0], [gl_val=1])
137 *) ac_val=1;; 170 AC_DEFINE_UNQUOTED([HAVE_WORKING_O_NOFOLLOW], [$gl_val],
138 esac 171 [Define to 1 if O_NOFOLLOW works, 0 otherwise.])
139 AC_DEFINE_UNQUOTED([HAVE_WORKING_O_NOFOLLOW], [$ac_val],
140 [Define to 1 if O_NOFOLLOW works.])
141]) 172])
diff --git a/gl/m4/fcntl.m4 b/gl/m4/fcntl.m4
index f6d0f377..08ab936f 100644
--- a/gl/m4/fcntl.m4
+++ b/gl/m4/fcntl.m4
@@ -1,9 +1,10 @@
1# fcntl.m4 1# fcntl.m4
2# serial 12 2# serial 12
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# For now, this module ensures that fcntl() 9# For now, this module ensures that fcntl()
9# - supports F_DUPFD correctly 10# - supports F_DUPFD correctly
diff --git a/gl/m4/fcntl_h.m4 b/gl/m4/fcntl_h.m4
index b69f7a0c..1c9f9cce 100644
--- a/gl/m4/fcntl_h.m4
+++ b/gl/m4/fcntl_h.m4
@@ -1,9 +1,10 @@
1# fcntl_h.m4 1# fcntl_h.m4
2# serial 20 2# serial 20
3dnl Copyright (C) 2006-2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2006-2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Configure fcntl.h. 9# Configure fcntl.h.
9 10
diff --git a/gl/m4/fflush.m4 b/gl/m4/fflush.m4
index 43fc3bf3..399065b6 100644
--- a/gl/m4/fflush.m4
+++ b/gl/m4/fflush.m4
@@ -1,9 +1,10 @@
1# fflush.m4 1# fflush.m4
2# serial 19 2# serial 20
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Eric Blake 9dnl From Eric Blake
9 10
@@ -79,8 +80,9 @@ AC_DEFUN([gl_FUNC_FFLUSH_STDIN],
79 [gl_cv_func_fflush_stdin=yes], 80 [gl_cv_func_fflush_stdin=yes],
80 [gl_cv_func_fflush_stdin=no], 81 [gl_cv_func_fflush_stdin=no],
81 [case "$host_os" in 82 [case "$host_os" in
82 # Guess no on native Windows. 83 # Guess no on NetBSD, OpenBSD, native Windows.
83 mingw* | windows*) gl_cv_func_fflush_stdin="guessing no" ;; 84 netbsd* | openbsd* | mingw* | windows*)
85 gl_cv_func_fflush_stdin="guessing no" ;;
84 *) gl_cv_func_fflush_stdin=cross ;; 86 *) gl_cv_func_fflush_stdin=cross ;;
85 esac 87 esac
86 ]) 88 ])
@@ -92,8 +94,8 @@ AC_DEFUN([gl_FUNC_FFLUSH_STDIN],
92 *) gl_func_fflush_stdin='(-1)' ;; 94 *) gl_func_fflush_stdin='(-1)' ;;
93 esac 95 esac
94 AC_DEFINE_UNQUOTED([FUNC_FFLUSH_STDIN], [$gl_func_fflush_stdin], 96 AC_DEFINE_UNQUOTED([FUNC_FFLUSH_STDIN], [$gl_func_fflush_stdin],
95 [Define to 1 if fflush is known to work on stdin as per POSIX.1-2008, 97 [Define to 1 if fflush is known to work on stdin as per POSIX.1-2008
96 0 if fflush is known to not work, -1 if unknown.]) 98 or later, 0 if fflush is known to not work, -1 if unknown.])
97]) 99])
98 100
99# Prerequisites of lib/fflush.c. 101# Prerequisites of lib/fflush.c.
diff --git a/gl/m4/float_h.m4 b/gl/m4/float_h.m4
index c95d4171..8580c9c9 100644
--- a/gl/m4/float_h.m4
+++ b/gl/m4/float_h.m4
@@ -1,9 +1,10 @@
1# float_h.m4 1# float_h.m4
2# serial 14 2# serial 15
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FLOAT_H], 9AC_DEFUN([gl_FLOAT_H],
9[ 10[
@@ -54,6 +55,31 @@ changequote([,])dnl
54 ;; 55 ;;
55 esac 56 esac
56 57
58 dnl Test for completeness w.r.t. ISO C 23.
59 REPLACE_FLOAT_SNAN=0
60 AC_CACHE_CHECK([whether float.h conforms to ISO C23],
61 [gl_cv_header_float_h_isoc23],
62 [AC_COMPILE_IFELSE(
63 [AC_LANG_PROGRAM(
64 [[#include <float.h>
65 int x[] = { FLT_DECIMAL_DIG, DBL_DECIMAL_DIG, LDBL_DECIMAL_DIG };
66 float maxf = FLT_NORM_MAX;
67 double maxd = DBL_NORM_MAX;
68 long double maxl = LDBL_NORM_MAX;
69 ]],
70 [[float sf = FLT_SNAN;
71 double sd = DBL_SNAN;
72 long double sl = LDBL_SNAN;
73 return (sf != 0) + (sd != 0) + (sl != 0);
74 ]])],
75 [gl_cv_header_float_h_isoc23=yes],
76 [gl_cv_header_float_h_isoc23=no])
77 ])
78 if test $gl_cv_header_float_h_isoc23 != yes; then
79 GL_GENERATE_FLOAT_H=true
80 REPLACE_FLOAT_SNAN=1
81 fi
82
57 dnl Test against glibc-2.7 Linux/SPARC64 bug. 83 dnl Test against glibc-2.7 Linux/SPARC64 bug.
58 REPLACE_ITOLD=0 84 REPLACE_ITOLD=0
59 AC_CACHE_CHECK([whether conversion from 'int' to 'long double' works], 85 AC_CACHE_CHECK([whether conversion from 'int' to 'long double' works],
diff --git a/gl/m4/floorf.m4 b/gl/m4/floorf.m4
index 2572c848..cb75fce9 100644
--- a/gl/m4/floorf.m4
+++ b/gl/m4/floorf.m4
@@ -1,9 +1,10 @@
1# floorf.m4 1# floorf.m4
2# serial 21 2# serial 21
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_FLOORF], 9AC_DEFUN([gl_FUNC_FLOORF],
9[ 10[
diff --git a/gl/m4/fopen.m4 b/gl/m4/fopen.m4
index f3b7aadd..e27b3270 100644
--- a/gl/m4/fopen.m4
+++ b/gl/m4/fopen.m4
@@ -1,9 +1,10 @@
1# fopen.m4 1# fopen.m4
2# serial 16 2# serial 16
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_FOPEN_ITSELF], 9AC_DEFUN([gl_FUNC_FOPEN_ITSELF],
9[ 10[
diff --git a/gl/m4/fpurge.m4 b/gl/m4/fpurge.m4
index a77f5b96..408a2579 100644
--- a/gl/m4/fpurge.m4
+++ b/gl/m4/fpurge.m4
@@ -1,65 +1,65 @@
1# fpurge.m4 1# fpurge.m4
2# serial 14 2# serial 16
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_FPURGE], 9AC_DEFUN([gl_FUNC_FPURGE],
9[ 10[
10 AC_REQUIRE([gl_STDIO_H_DEFAULTS]) 11 AC_REQUIRE([gl_STDIO_H_DEFAULTS])
11 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
12 AC_CHECK_HEADERS_ONCE([stdio_ext.h]) 12 AC_CHECK_HEADERS_ONCE([stdio_ext.h])
13 AC_CHECK_FUNCS_ONCE([fpurge]) 13 AC_CHECK_FUNCS_ONCE([fpurge])
14 gl_CHECK_FUNCS_ANDROID([__fpurge], [[#include <stdio_ext.h>]]) 14 gl_CHECK_FUNCS_ANDROID([__fpurge], [[#include <stdio_ext.h>]])
15 AC_CHECK_DECLS([fpurge], , , [[#include <stdio.h>]]) 15 AC_CHECK_DECLS([fpurge], , , [[#include <stdio.h>]])
16 if test "x$ac_cv_func_fpurge" = xyes; then 16 if test $ac_cv_func_fpurge = yes; then
17 HAVE_FPURGE=1 17 HAVE_FPURGE=1
18 # Detect BSD bug. Only cygwin 1.7 and musl are known to be immune. 18 # Detect BSD bug. Only cygwin 1.7 and musl are known to be immune.
19 AC_CACHE_CHECK([whether fpurge works], [gl_cv_func_fpurge_works], 19 AC_CACHE_CHECK([whether fpurge works], [gl_cv_func_fpurge_works],
20 [AC_RUN_IFELSE( 20 [if test $ac_cv_have_decl_fpurge = yes; then
21 [AC_LANG_PROGRAM( 21 AC_RUN_IFELSE(
22 [[#include <stdio.h> 22 [AC_LANG_PROGRAM(
23]], 23 [[#include <stdio.h>
24 [[FILE *f = fopen ("conftest.txt", "w+"); 24 ]],
25 if (!f) 25 [[FILE *f = fopen ("conftest.txt", "w+");
26 return 1; 26 if (!f)
27 if (fputc ('a', f) != 'a') 27 return 1;
28 { fclose (f); return 2; } 28 if (fputc ('a', f) != 'a')
29 rewind (f); 29 { fclose (f); return 2; }
30 if (fgetc (f) != 'a') 30 rewind (f);
31 { fclose (f); return 3; } 31 if (fgetc (f) != 'a')
32 if (fgetc (f) != EOF) 32 { fclose (f); return 3; }
33 { fclose (f); return 4; } 33 if (fgetc (f) != EOF)
34 if (fpurge (f) != 0) 34 { fclose (f); return 4; }
35 { fclose (f); return 5; } 35 if (fpurge (f) != 0)
36 if (putc ('b', f) != 'b') 36 { fclose (f); return 5; }
37 { fclose (f); return 6; } 37 if (putc ('b', f) != 'b')
38 if (fclose (f) != 0) 38 { fclose (f); return 6; }
39 return 7; 39 if (fclose (f) != 0)
40 if ((f = fopen ("conftest.txt", "r")) == NULL) 40 return 7;
41 return 8; 41 if ((f = fopen ("conftest.txt", "r")) == NULL)
42 if (fgetc (f) != 'a') 42 return 8;
43 { fclose (f); return 9; } 43 if (fgetc (f) != 'a')
44 if (fgetc (f) != 'b') 44 { fclose (f); return 9; }
45 { fclose (f); return 10; } 45 if (fgetc (f) != 'b')
46 if (fgetc (f) != EOF) 46 { fclose (f); return 10; }
47 { fclose (f); return 11; } 47 if (fgetc (f) != EOF)
48 if (fclose (f) != 0) 48 { fclose (f); return 11; }
49 return 12; 49 if (fclose (f) != 0)
50 if (remove ("conftest.txt") != 0) 50 return 12;
51 return 13; 51 if (remove ("conftest.txt") != 0)
52 return 0; 52 return 13;
53 ]])], 53 return 0;
54 [gl_cv_func_fpurge_works=yes], 54 ]])],
55 [gl_cv_func_fpurge_works=no], 55 [gl_cv_func_fpurge_works=yes],
56 [case "$host_os" in 56 [gl_cv_func_fpurge_works=no],
57 # Guess yes on musl systems. 57 [# Obey --enable-cross-guesses.
58 *-musl* | midipix*) gl_cv_func_fpurge_works="guessing yes" ;; 58 gl_cv_func_fpurge_works="$gl_cross_guess_normal"
59 # Otherwise obey --enable-cross-guesses. 59 ])
60 *) gl_cv_func_fpurge_works="$gl_cross_guess_normal" ;; 60 else
61 esac 61 gl_cv_func_fpurge_works=no
62 ]) 62 fi
63 ]) 63 ])
64 case "$gl_cv_func_fpurge_works" in 64 case "$gl_cv_func_fpurge_works" in
65 *yes) ;; 65 *yes) ;;
diff --git a/gl/m4/freading.m4 b/gl/m4/freading.m4
index be899456..373d2bff 100644
--- a/gl/m4/freading.m4
+++ b/gl/m4/freading.m4
@@ -1,9 +1,10 @@
1# freading.m4 1# freading.m4
2# serial 3 2# serial 3
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_FREADING], 9AC_DEFUN([gl_FUNC_FREADING],
9[ 10[
diff --git a/gl/m4/free.m4 b/gl/m4/free.m4
index a2b596d6..485d8243 100644
--- a/gl/m4/free.m4
+++ b/gl/m4/free.m4
@@ -1,9 +1,10 @@
1# free.m4 1# free.m4
2# serial 6 2# serial 6
3dnl Copyright (C) 2003-2005, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2003-2005, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Written by Paul Eggert and Bruno Haible. 9# Written by Paul Eggert and Bruno Haible.
9 10
diff --git a/gl/m4/fseek.m4 b/gl/m4/fseek.m4
index fb220a1f..ce728f60 100644
--- a/gl/m4/fseek.m4
+++ b/gl/m4/fseek.m4
@@ -1,9 +1,10 @@
1# fseek.m4 1# fseek.m4
2# serial 4 2# serial 4
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_FSEEK], 9AC_DEFUN([gl_FUNC_FSEEK],
9[ 10[
diff --git a/gl/m4/fseeko.m4 b/gl/m4/fseeko.m4
index 5682a1f2..c093d399 100644
--- a/gl/m4/fseeko.m4
+++ b/gl/m4/fseeko.m4
@@ -1,9 +1,10 @@
1# fseeko.m4 1# fseeko.m4
2# serial 20 2# serial 21
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_FSEEKO], 9AC_DEFUN([gl_FUNC_FSEEKO],
9[ 10[
@@ -69,6 +70,10 @@ AC_DEFUN([gl_STDIN_LARGE_OFFSET],
69# Prerequisites of lib/fseeko.c. 70# Prerequisites of lib/fseeko.c.
70AC_DEFUN([gl_PREREQ_FSEEKO], 71AC_DEFUN([gl_PREREQ_FSEEKO],
71[ 72[
73 if test $gl_cv_func_fseeko != no; then
74 AC_DEFINE([HAVE_FSEEKO], [1],
75 [Define to 1 if the system has the fseeko function.])
76 fi
72 dnl Native Windows has the function _fseeki64. mingw hides it in some 77 dnl Native Windows has the function _fseeki64. mingw hides it in some
73 dnl circumstances, but mingw64 makes it usable again. 78 dnl circumstances, but mingw64 makes it usable again.
74 AC_CHECK_FUNCS([_fseeki64]) 79 AC_CHECK_FUNCS([_fseeki64])
diff --git a/gl/m4/fseterr.m4 b/gl/m4/fseterr.m4
new file mode 100644
index 00000000..3a94c288
--- /dev/null
+++ b/gl/m4/fseterr.m4
@@ -0,0 +1,15 @@
1# fseterr.m4
2# serial 2
3dnl Copyright (C) 2012-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9AC_DEFUN([gl_FUNC_FSETERR],
10[
11 gl_CHECK_FUNCS_ANDROID([__fseterr],
12 [[#include <stdio.h>
13 #include <stdio_ext.h>
14 ]])
15])
diff --git a/gl/m4/fstat.m4 b/gl/m4/fstat.m4
index 47777b0c..e89bbc32 100644
--- a/gl/m4/fstat.m4
+++ b/gl/m4/fstat.m4
@@ -1,9 +1,10 @@
1# fstat.m4 1# fstat.m4
2# serial 10 2# serial 10
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2011-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_FSTAT], 9AC_DEFUN([gl_FUNC_FSTAT],
9[ 10[
diff --git a/gl/m4/fstypename.m4 b/gl/m4/fstypename.m4
index 05a68805..4407b765 100644
--- a/gl/m4/fstypename.m4
+++ b/gl/m4/fstypename.m4
@@ -1,10 +1,11 @@
1# fstypename.m4 1# fstypename.m4
2# serial 6 2# serial 6
3dnl Copyright (C) 1998-1999, 2001, 2004, 2006, 2009-2024 Free Software 3dnl Copyright (C) 1998-1999, 2001, 2004, 2006, 2009-2025 Free Software
4dnl Foundation, Inc. 4dnl Foundation, Inc.
5dnl This file is free software; the Free Software Foundation 5dnl This file is free software; the Free Software Foundation
6dnl gives unlimited permission to copy and/or distribute it, 6dnl gives unlimited permission to copy and/or distribute it,
7dnl with or without modifications, as long as this notice is preserved. 7dnl with or without modifications, as long as this notice is preserved.
8dnl This file is offered as-is, without any warranty.
8 9
9dnl From Jim Meyering. 10dnl From Jim Meyering.
10dnl 11dnl
diff --git a/gl/m4/fsusage.m4 b/gl/m4/fsusage.m4
index 1ce90660..bb7b6e43 100644
--- a/gl/m4/fsusage.m4
+++ b/gl/m4/fsusage.m4
@@ -1,9 +1,11 @@
1# fsusage.m4 1# fsusage.m4
2# serial 35 2# serial 35
3dnl Copyright (C) 1997-1998, 2000-2001, 2003-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 1997-1998, 2000-2001, 2003-2025 Free Software Foundation,
4dnl Inc.
4dnl This file is free software; the Free Software Foundation 5dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 6dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 7dnl with or without modifications, as long as this notice is preserved.
8dnl This file is offered as-is, without any warranty.
7 9
8# Obtaining file system usage information. 10# Obtaining file system usage information.
9 11
diff --git a/gl/m4/ftell.m4 b/gl/m4/ftell.m4
index ab10736b..d5610b70 100644
--- a/gl/m4/ftell.m4
+++ b/gl/m4/ftell.m4
@@ -1,9 +1,10 @@
1# ftell.m4 1# ftell.m4
2# serial 3 2# serial 3
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_FTELL], 9AC_DEFUN([gl_FUNC_FTELL],
9[ 10[
diff --git a/gl/m4/ftello.m4 b/gl/m4/ftello.m4
index 0eb8fa0d..35d30f98 100644
--- a/gl/m4/ftello.m4
+++ b/gl/m4/ftello.m4
@@ -1,9 +1,10 @@
1# ftello.m4 1# ftello.m4
2# serial 16 2# serial 17
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_FTELLO], 9AC_DEFUN([gl_FUNC_FTELLO],
9[ 10[
@@ -157,6 +158,10 @@ main (void)
157# Prerequisites of lib/ftello.c. 158# Prerequisites of lib/ftello.c.
158AC_DEFUN([gl_PREREQ_FTELLO], 159AC_DEFUN([gl_PREREQ_FTELLO],
159[ 160[
161 if test $gl_cv_func_ftello != no; then
162 AC_DEFINE([HAVE_FTELLO], [1],
163 [Define to 1 if the system has the ftello function.])
164 fi
160 dnl Native Windows has the function _ftelli64. mingw hides it, but mingw64 165 dnl Native Windows has the function _ftelli64. mingw hides it, but mingw64
161 dnl makes it usable again. 166 dnl makes it usable again.
162 AC_CHECK_FUNCS([_ftelli64]) 167 AC_CHECK_FUNCS([_ftelli64])
diff --git a/gl/m4/getaddrinfo.m4 b/gl/m4/getaddrinfo.m4
index 8e209177..2931d526 100644
--- a/gl/m4/getaddrinfo.m4
+++ b/gl/m4/getaddrinfo.m4
@@ -1,14 +1,16 @@
1# getaddrinfo.m4 1# getaddrinfo.m4
2# serial 35 2# serial 38
3dnl Copyright (C) 2004-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2004-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_GETADDRINFO], 9AC_DEFUN([gl_GETADDRINFO],
9[ 10[
10 AC_REQUIRE([gl_SYS_SOCKET_H])dnl for HAVE_SYS_SOCKET_H, HAVE_WINSOCK2_H 11 AC_REQUIRE([gl_SYS_SOCKET_H])dnl for HAVE_SYS_SOCKET_H, HAVE_WINSOCK2_H
11 AC_REQUIRE([gl_NETDB_H])dnl for HAVE_NETDB_H 12 AC_REQUIRE([gl_NETDB_H])dnl for HAVE_NETDB_H
13 AC_REQUIRE([AC_CANONICAL_HOST])
12 GETADDRINFO_LIB= 14 GETADDRINFO_LIB=
13 gai_saved_LIBS="$LIBS" 15 gai_saved_LIBS="$LIBS"
14 16
@@ -87,6 +89,46 @@ int getaddrinfo (const char *, const char *, const struct addrinfo *, struct add
87 HAVE_GETADDRINFO=0 89 HAVE_GETADDRINFO=0
88 fi 90 fi
89 fi 91 fi
92 if test $HAVE_GETADDRINFO != 0; then
93 AC_CACHE_CHECK([whether getaddrinfo supports AI_NUMERICSERV],
94 [gl_cv_func_getaddrinfo_works],
95 [AC_RUN_IFELSE(
96 [AC_LANG_PROGRAM([[
97#include <sys/types.h>
98#ifdef HAVE_SYS_SOCKET_H
99#include <sys/socket.h>
100#endif
101#ifdef HAVE_NETDB_H
102#include <netdb.h>
103#endif
104#ifdef HAVE_WS2TCPIP_H
105#include <ws2tcpip.h>
106#endif
107#include <stddef.h>
108#include <string.h>
109 ]], [[
110 struct addrinfo hints;
111 struct addrinfo *ai;
112 memset (&hints, 0, sizeof (hints));
113 hints.ai_flags = AI_NUMERICSERV;
114 return getaddrinfo ("www.gnu.org", "http", &hints, &ai) != EAI_NONAME;
115 ]])
116 ],
117 [gl_cv_func_getaddrinfo_works=yes],
118 [gl_cv_func_getaddrinfo_works=no],
119 [case "$host_os" in
120 # Guess no on native Windows.
121 mingw* | windows*) gl_cv_func_getaddrinfo_works="guessing no" ;;
122 # Guess yes otherwise.
123 *) gl_cv_func_getaddrinfo_works="guessing yes" ;;
124 esac
125 ])
126 ])
127 case "$gl_cv_func_getaddrinfo_works" in
128 *yes) ;;
129 *) REPLACE_GETADDRINFO=1 ;;
130 esac
131 fi
90 AC_DEFINE_UNQUOTED([HAVE_GETADDRINFO], [$HAVE_GETADDRINFO], 132 AC_DEFINE_UNQUOTED([HAVE_GETADDRINFO], [$HAVE_GETADDRINFO],
91 [Define to 1 if getaddrinfo exists, or to 0 otherwise.]) 133 [Define to 1 if getaddrinfo exists, or to 0 otherwise.])
92 134
diff --git a/gl/m4/getdelim.m4 b/gl/m4/getdelim.m4
index 61139039..63d88306 100644
--- a/gl/m4/getdelim.m4
+++ b/gl/m4/getdelim.m4
@@ -1,11 +1,12 @@
1# getdelim.m4 1# getdelim.m4
2# serial 19 2# serial 19
3 3
4dnl Copyright (C) 2005-2007, 2009-2024 Free Software Foundation, Inc. 4dnl Copyright (C) 2005-2007, 2009-2025 Free Software Foundation, Inc.
5dnl 5dnl
6dnl This file is free software; the Free Software Foundation 6dnl This file is free software; the Free Software Foundation
7dnl gives unlimited permission to copy and/or distribute it, 7dnl gives unlimited permission to copy and/or distribute it,
8dnl with or without modifications, as long as this notice is preserved. 8dnl with or without modifications, as long as this notice is preserved.
9dnl This file is offered as-is, without any warranty.
9 10
10AC_PREREQ([2.59]) 11AC_PREREQ([2.59])
11 12
diff --git a/gl/m4/getdtablesize.m4 b/gl/m4/getdtablesize.m4
index aaefe9b2..112c1c4d 100644
--- a/gl/m4/getdtablesize.m4
+++ b/gl/m4/getdtablesize.m4
@@ -1,9 +1,10 @@
1# getdtablesize.m4 1# getdtablesize.m4
2# serial 8 2# serial 8
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_GETDTABLESIZE], 9AC_DEFUN([gl_FUNC_GETDTABLESIZE],
9[ 10[
diff --git a/gl/m4/gethostname.m4 b/gl/m4/gethostname.m4
index 2f743b7d..be71ff78 100644
--- a/gl/m4/gethostname.m4
+++ b/gl/m4/gethostname.m4
@@ -1,9 +1,10 @@
1# gethostname.m4 1# gethostname.m4
2# serial 16 2# serial 16
3dnl Copyright (C) 2002, 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2002, 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Ensure 9# Ensure
9# - the gethostname() function, 10# - the gethostname() function,
diff --git a/gl/m4/getline.m4 b/gl/m4/getline.m4
index 36513cd4..b97b8011 100644
--- a/gl/m4/getline.m4
+++ b/gl/m4/getline.m4
@@ -1,12 +1,13 @@
1# getline.m4 1# getline.m4
2# serial 33 2# serial 33
3 3
4dnl Copyright (C) 1998-2003, 2005-2007, 2009-2024 Free Software Foundation, 4dnl Copyright (C) 1998-2003, 2005-2007, 2009-2025 Free Software Foundation,
5dnl Inc. 5dnl Inc.
6dnl 6dnl
7dnl This file is free software; the Free Software Foundation 7dnl This file is free software; the Free Software Foundation
8dnl gives unlimited permission to copy and/or distribute it, 8dnl gives unlimited permission to copy and/or distribute it,
9dnl with or without modifications, as long as this notice is preserved. 9dnl with or without modifications, as long as this notice is preserved.
10dnl This file is offered as-is, without any warranty.
10 11
11AC_PREREQ([2.59]) 12AC_PREREQ([2.59])
12 13
diff --git a/gl/m4/getloadavg.m4 b/gl/m4/getloadavg.m4
index 0918bcd2..8ab613db 100644
--- a/gl/m4/getloadavg.m4
+++ b/gl/m4/getloadavg.m4
@@ -1,10 +1,11 @@
1# getloadavg.m4 1# getloadavg.m4
2# serial 13 2# serial 13
3dnl Copyright (C) 1992-1996, 1999-2000, 2002-2003, 2006, 2008-2024 Free Software 3dnl Copyright (C) 1992-1996, 1999-2000, 2002-2003, 2006, 2008-2025 Free
4dnl Foundation, Inc. 4dnl Software Foundation, Inc.
5dnl This file is free software; the Free Software Foundation 5dnl This file is free software; the Free Software Foundation
6dnl gives unlimited permission to copy and/or distribute it, 6dnl gives unlimited permission to copy and/or distribute it,
7dnl with or without modifications, as long as this notice is preserved. 7dnl with or without modifications, as long as this notice is preserved.
8dnl This file is offered as-is, without any warranty.
8 9
9# Check for getloadavg. 10# Check for getloadavg.
10 11
diff --git a/gl/m4/getopt.m4 b/gl/m4/getopt.m4
index 297722ea..cb344c15 100644
--- a/gl/m4/getopt.m4
+++ b/gl/m4/getopt.m4
@@ -1,9 +1,10 @@
1# getopt.m4 1# getopt.m4
2# serial 49 2# serial 50
3dnl Copyright (C) 2002-2006, 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2002-2006, 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Request a POSIX compliant getopt function. 9# Request a POSIX compliant getopt function.
9AC_DEFUN([gl_FUNC_GETOPT_POSIX], 10AC_DEFUN([gl_FUNC_GETOPT_POSIX],
@@ -77,7 +78,7 @@ AC_DEFUN([gl_GETOPT_CHECK_HEADERS],
77 fi 78 fi
78 79
79 dnl POSIX 2008 does not specify leading '+' behavior, but see 80 dnl POSIX 2008 does not specify leading '+' behavior, but see
80 dnl http://austingroupbugs.net/view.php?id=191 for a recommendation on 81 dnl https://austingroupbugs.net/view.php?id=191 for a recommendation on
81 dnl the next version of POSIX. For now, we only guarantee leading '+' 82 dnl the next version of POSIX. For now, we only guarantee leading '+'
82 dnl behavior with getopt-gnu. 83 dnl behavior with getopt-gnu.
83 if test -z "$gl_replace_getopt"; then 84 if test -z "$gl_replace_getopt"; then
@@ -366,14 +367,7 @@ dnl is ambiguous with environment values that contain newlines.
366 367
367AC_DEFUN([gl_GETOPT_SUBSTITUTE_HEADER], 368AC_DEFUN([gl_GETOPT_SUBSTITUTE_HEADER],
368[ 369[
369 AC_CHECK_HEADERS_ONCE([sys/cdefs.h]) 370 gl_CHECK_HEADER_SYS_CDEFS_H
370 if test $ac_cv_header_sys_cdefs_h = yes; then
371 HAVE_SYS_CDEFS_H=1
372 else
373 HAVE_SYS_CDEFS_H=0
374 fi
375 AC_SUBST([HAVE_SYS_CDEFS_H])
376
377 AC_DEFINE([__GETOPT_PREFIX], [[rpl_]], 371 AC_DEFINE([__GETOPT_PREFIX], [[rpl_]],
378 [Define to rpl_ if the getopt replacement functions and variables 372 [Define to rpl_ if the getopt replacement functions and variables
379 should be used.]) 373 should be used.])
diff --git a/gl/m4/getprogname.m4 b/gl/m4/getprogname.m4
index b24f4480..90f34c74 100644
--- a/gl/m4/getprogname.m4
+++ b/gl/m4/getprogname.m4
@@ -1,9 +1,10 @@
1# getprogname.m4 1# getprogname.m4
2# serial 8 2# serial 8
3dnl Copyright (C) 2016-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2016-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Check for getprogname or replacements for it 9# Check for getprogname or replacements for it
9 10
diff --git a/gl/m4/gl-openssl.m4 b/gl/m4/gl-openssl.m4
index c5e1f7ba..3cfea50f 100644
--- a/gl/m4/gl-openssl.m4
+++ b/gl/m4/gl-openssl.m4
@@ -1,9 +1,10 @@
1# gl-openssl.m4 1# gl-openssl.m4
2# serial 7 2# serial 7
3dnl Copyright (C) 2013-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2013-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_SET_CRYPTO_CHECK_DEFAULT], 9AC_DEFUN([gl_SET_CRYPTO_CHECK_DEFAULT],
9[ 10[
diff --git a/gl/m4/gnulib-cache.m4 b/gl/m4/gnulib-cache.m4
index fcf84226..6a6e8593 100644
--- a/gl/m4/gnulib-cache.m4
+++ b/gl/m4/gnulib-cache.m4
@@ -1,4 +1,4 @@
1# Copyright (C) 2002-2024 Free Software Foundation, Inc. 1# Copyright (C) 2002-2025 Free Software Foundation, Inc.
2# 2#
3# This file is free software; you can redistribute it and/or modify 3# This file is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by 4# it under the terms of the GNU General Public License as published by
diff --git a/gl/m4/gnulib-common.m4 b/gl/m4/gnulib-common.m4
index cb730449..034dae69 100644
--- a/gl/m4/gnulib-common.m4
+++ b/gl/m4/gnulib-common.m4
@@ -1,9 +1,10 @@
1# gnulib-common.m4 1# gnulib-common.m4
2# serial 93 2# serial 113
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_PREREQ([2.62]) 9AC_PREREQ([2.62])
9 10
@@ -20,43 +21,61 @@ AC_DEFUN([gl_COMMON_BODY], [
20[/* Witness that <config.h> has been included. */ 21[/* Witness that <config.h> has been included. */
21#define _GL_CONFIG_H_INCLUDED 1 22#define _GL_CONFIG_H_INCLUDED 1
22]) 23])
24 dnl Avoid warnings from gcc -Wtrailing-whitespace.
25 dnl This is a temporary workaround until Autoconf fixes it.
26 dnl Test case:
27 dnl empty1=; empty2=; AC_DEFINE_UNQUOTED([FOO], [$empty1$empty2], [...])
28 dnl should produce "#define FOO /**/", not "#define FOO ".
29 AH_TOP([#if defined __GNUC__ && __GNUC__ >= 15 && !defined __clang__
30# pragma GCC diagnostic push
31# pragma GCC diagnostic ignored "-Wtrailing-whitespace"
32#endif
33])
34 AH_BOTTOM([#if defined __GNUC__ && __GNUC__ >= 15 && !defined __clang__
35# pragma GCC diagnostic pop
36#endif
37])
23 AH_VERBATIM([_GL_GNUC_PREREQ], 38 AH_VERBATIM([_GL_GNUC_PREREQ],
24[/* True if the compiler says it groks GNU C version MAJOR.MINOR. */ 39[/* True if the compiler says it groks GNU C version MAJOR.MINOR.
25#if defined __GNUC__ && defined __GNUC_MINOR__ 40 Except that
41 - clang groks GNU C 4.2, even on Windows, where it does not define
42 __GNUC__.
43 - The OpenMandriva-modified clang compiler pretends that it groks
44 GNU C version 13.1, but it doesn't: It does not support
45 __attribute__ ((__malloc__ (f, i))), nor does it support
46 __attribute__ ((__warning__ (message))) on a function redeclaration.
47 - Users can make clang lie as well, through the -fgnuc-version option. */
48#if defined __GNUC__ && defined __GNUC_MINOR__ && !defined __clang__
26# define _GL_GNUC_PREREQ(major, minor) \ 49# define _GL_GNUC_PREREQ(major, minor) \
27 ((major) < __GNUC__ + ((minor) <= __GNUC_MINOR__)) 50 ((major) < __GNUC__ + ((minor) <= __GNUC_MINOR__))
51#elif defined __clang__
52 /* clang really only groks GNU C 4.2. */
53# define _GL_GNUC_PREREQ(major, minor) \
54 ((major) < 4 + ((minor) <= 2))
28#else 55#else
29# define _GL_GNUC_PREREQ(major, minor) 0 56# define _GL_GNUC_PREREQ(major, minor) 0
30#endif 57#endif
31]) 58])
32 AH_VERBATIM([_Noreturn], 59 AH_VERBATIM([_Noreturn],
33[/* The _Noreturn keyword of C11. */ 60[/* The _Noreturn keyword of C11.
61 Do not use [[noreturn]], because with it the syntax
62 extern _Noreturn void func (...);
63 would not be valid; such a declaration would be valid only with 'extern'
64 and '_Noreturn' swapped, or without the 'extern' keyword. However, some
65 AIX system header files and several gnulib header files use precisely
66 this syntax with 'extern'. So even though C23 deprecates _Noreturn,
67 it is currently more portable to prefer it to [[noreturn]].
68
69 Also, do not try to work around LLVM bug 59792 (clang 15 or earlier).
70 This rare bug can be worked around by compiling with 'clang -D_Noreturn=',
71 though the workaround may generate many false-alarm warnings. */
34#ifndef _Noreturn 72#ifndef _Noreturn
35# if (defined __cplusplus \ 73# if ((!defined __cplusplus || defined __clang__) \
36 && ((201103 <= __cplusplus && !(__GNUC__ == 4 && __GNUC_MINOR__ == 7)) \ 74 && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0)))
37 || (defined _MSC_VER && 1900 <= _MSC_VER)) \
38 && 0)
39 /* [[noreturn]] is not practically usable, because with it the syntax
40 extern _Noreturn void func (...);
41 would not be valid; such a declaration would only be valid with 'extern'
42 and '_Noreturn' swapped, or without the 'extern' keyword. However, some
43 AIX system header files and several gnulib header files use precisely
44 this syntax with 'extern'. */
45# define _Noreturn [[noreturn]]
46# elif (defined __clang__ && __clang_major__ < 16 \
47 && defined _GL_WORK_AROUND_LLVM_BUG_59792)
48 /* Compile with -D_GL_WORK_AROUND_LLVM_BUG_59792 to work around
49 that rare LLVM bug, though you may get many false-alarm warnings. */
50# define _Noreturn
51# elif ((!defined __cplusplus || defined __clang__) \
52 && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) \
53 || (!defined __STRICT_ANSI__ \
54 && (_GL_GNUC_PREREQ (4, 7) \
55 || (defined __apple_build_version__ \
56 ? 6000000 <= __apple_build_version__ \
57 : 3 < __clang_major__ + (5 <= __clang_minor__))))))
58 /* _Noreturn works as-is. */ 75 /* _Noreturn works as-is. */
59# elif _GL_GNUC_PREREQ (2, 8) || defined __clang__ || 0x5110 <= __SUNPRO_C 76# elif _GL_GNUC_PREREQ (2, 8) || defined __clang__ || 0x5110 <= __SUNPRO_C
77 /* Prefer __attribute__ ((__noreturn__)) to plain _Noreturn even if the
78 latter works, as 'gcc -std=gnu99 -Wpedantic' warns about _Noreturn. */
60# define _Noreturn __attribute__ ((__noreturn__)) 79# define _Noreturn __attribute__ ((__noreturn__))
61# elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0) 80# elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0)
62# define _Noreturn __declspec (noreturn) 81# define _Noreturn __declspec (noreturn)
@@ -90,6 +109,9 @@ AC_DEFUN([gl_COMMON_BODY], [
90# define _GL_HAS_ATTRIBUTE(attr) __has_attribute (__##attr##__) 109# define _GL_HAS_ATTRIBUTE(attr) __has_attribute (__##attr##__)
91# else 110# else
92# define _GL_HAS_ATTRIBUTE(attr) _GL_ATTR_##attr 111# define _GL_HAS_ATTRIBUTE(attr) _GL_ATTR_##attr
112/* The following lines list the first GCC version that supports the attribute.
113 Although the lines are not used in GCC 5 and later (as GCC 5 introduced
114 __has_attribute support), list GCC versions 5+ anyway for completeness. */
93# define _GL_ATTR_alloc_size _GL_GNUC_PREREQ (4, 3) 115# define _GL_ATTR_alloc_size _GL_GNUC_PREREQ (4, 3)
94# define _GL_ATTR_always_inline _GL_GNUC_PREREQ (3, 2) 116# define _GL_ATTR_always_inline _GL_GNUC_PREREQ (3, 2)
95# define _GL_ATTR_artificial _GL_GNUC_PREREQ (4, 3) 117# define _GL_ATTR_artificial _GL_GNUC_PREREQ (4, 3)
@@ -110,12 +132,15 @@ AC_DEFUN([gl_COMMON_BODY], [
110# endif 132# endif
111# define _GL_ATTR_noinline _GL_GNUC_PREREQ (3, 1) 133# define _GL_ATTR_noinline _GL_GNUC_PREREQ (3, 1)
112# define _GL_ATTR_nonnull _GL_GNUC_PREREQ (3, 3) 134# define _GL_ATTR_nonnull _GL_GNUC_PREREQ (3, 3)
135# define _GL_ATTR_nonnull_if_nonzero _GL_GNUC_PREREQ (15, 1)
113# define _GL_ATTR_nonstring _GL_GNUC_PREREQ (8, 0) 136# define _GL_ATTR_nonstring _GL_GNUC_PREREQ (8, 0)
114# define _GL_ATTR_nothrow _GL_GNUC_PREREQ (3, 3) 137# define _GL_ATTR_nothrow _GL_GNUC_PREREQ (3, 3)
115# define _GL_ATTR_packed _GL_GNUC_PREREQ (2, 7) 138# define _GL_ATTR_packed _GL_GNUC_PREREQ (2, 7)
116# define _GL_ATTR_pure _GL_GNUC_PREREQ (2, 96) 139# define _GL_ATTR_pure _GL_GNUC_PREREQ (2, 96)
140# define _GL_ATTR_reproducible _GL_GNUC_PREREQ (15, 1)
117# define _GL_ATTR_returns_nonnull _GL_GNUC_PREREQ (4, 9) 141# define _GL_ATTR_returns_nonnull _GL_GNUC_PREREQ (4, 9)
118# define _GL_ATTR_sentinel _GL_GNUC_PREREQ (4, 0) 142# define _GL_ATTR_sentinel _GL_GNUC_PREREQ (4, 0)
143# define _GL_ATTR_unsequenced _GL_GNUC_PREREQ (15, 1)
119# define _GL_ATTR_unused _GL_GNUC_PREREQ (2, 7) 144# define _GL_ATTR_unused _GL_GNUC_PREREQ (2, 7)
120# define _GL_ATTR_warn_unused_result _GL_GNUC_PREREQ (3, 4) 145# define _GL_ATTR_warn_unused_result _GL_GNUC_PREREQ (3, 4)
121# endif 146# endif
@@ -131,6 +156,23 @@ AC_DEFUN([gl_COMMON_BODY], [
131# define _GL_HAVE___HAS_C_ATTRIBUTE 0 156# define _GL_HAVE___HAS_C_ATTRIBUTE 0
132#endif 157#endif
133 158
159/* Attributes in bracket syntax [[...]] vs. attributes in __attribute__((...))
160 syntax, in function declarations. There are two problems here.
161 (Last tested with gcc/g++ 14 and clang/clang++ 18.)
162
163 1) We want that the _GL_ATTRIBUTE_* can be cumulated on the same declaration
164 in any order.
165 =========================== foo.c = foo.cc ===========================
166 __attribute__ ((__deprecated__)) [[__nodiscard__]] int bar1 (int);
167 [[__nodiscard__]] __attribute__ ((__deprecated__)) int bar2 (int);
168 ======================================================================
169 This gives a syntax error
170 - in C mode with gcc
171 <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108796>, and
172 - in C++ mode with clang++ version < 16, and
173 - in C++ mode, inside extern "C" {}, still in newer clang++ versions
174 <https://github.com/llvm/llvm-project/issues/101990>.
175 */
134/* Define if, in a function declaration, the attributes in bracket syntax 176/* Define if, in a function declaration, the attributes in bracket syntax
135 [[...]] must come before the attributes in __attribute__((...)) syntax. 177 [[...]] must come before the attributes in __attribute__((...)) syntax.
136 If this is defined, it is best to avoid the bracket syntax, so that the 178 If this is defined, it is best to avoid the bracket syntax, so that the
@@ -145,6 +187,176 @@ AC_DEFUN([gl_COMMON_BODY], [
145# define _GL_BRACKET_BEFORE_ATTRIBUTE 1 187# define _GL_BRACKET_BEFORE_ATTRIBUTE 1
146# endif 188# endif
147#endif 189#endif
190/*
191 2) We want that the _GL_ATTRIBUTE_* can be placed in a declaration
192 - without 'extern', in C as well as in C++,
193 - with 'extern', in C,
194 - with 'extern "C"', in C++
195 in the same position. That is, we don't want to be forced to use a
196 macro which arranges for the attribute to come before 'extern' in
197 one case and after 'extern' in the other case, because such a macro
198 would make the source code of .h files pretty ugly.
199 =========================== foo.c = foo.cc ===========================
200 #ifdef __cplusplus
201 # define CC "C"
202 #else
203 # define CC
204 #endif
205
206 #define ND [[__nodiscard__]]
207 #define WUR __attribute__((__warn_unused_result__))
208
209 #ifdef __cplusplus
210 extern "C" {
211 #endif
212 // gcc clang g++ clang++
213
214 ND int foo (int);
215 int ND foo (int); // warn error warn error
216 int foo ND (int);
217 int foo (int) ND; // warn error warn error
218
219 WUR int foo (int);
220 int WUR foo (int);
221 int fo1 WUR (int); // error error error error
222 int foo (int) WUR;
223
224 #ifdef __cplusplus
225 }
226 #endif
227
228 // gcc clang g++ clang++
229
230 ND extern CC int foo (int); // error error
231 extern CC ND int foo (int); // error error
232 extern CC int ND foo (int); // warn error warn error
233 extern CC int foo ND (int);
234 extern CC int foo (int) ND; // warn error warn error
235
236 WUR extern CC int foo (int); // warn
237 extern CC WUR int foo (int);
238 extern CC int WUR foo (int);
239 extern CC int foo WUR (int); // error error error error
240 extern CC int foo (int) WUR;
241
242 ND EXTERN_C_FUNC int foo (int); // error error
243 EXTERN_C_FUNC ND int foo (int);
244 EXTERN_C_FUNC int ND foo (int); // warn error warn error
245 EXTERN_C_FUNC int foo ND (int);
246 EXTERN_C_FUNC int foo (int) ND; // warn error warn error
247
248 WUR EXTERN_C_FUNC int foo (int); // warn
249 EXTERN_C_FUNC WUR int foo (int);
250 EXTERN_C_FUNC int WUR foo (int);
251 EXTERN_C_FUNC int fo2 WUR (int); // error error error error
252 EXTERN_C_FUNC int foo (int) WUR;
253 ======================================================================
254 So, if we insist on using the 'extern' keyword ('extern CC' idiom):
255 * If _GL_ATTRIBUTE_* expands to bracket syntax [[...]]
256 in both C and C++, there is one available position:
257 - between the function name and the parameter list.
258 * If _GL_ATTRIBUTE_* expands to __attribute__((...)) syntax
259 in both C and C++, there are several available positions:
260 - before the return type,
261 - between return type and function name,
262 - at the end of the declaration.
263 * If _GL_ATTRIBUTE_* expands to bracket syntax [[...]] in C and to
264 __attribute__((...)) syntax in C++, there is no available position:
265 it would need to come before 'extern' in C but after 'extern "C"'
266 in C++.
267 * If _GL_ATTRIBUTE_* expands to __attribute__((...)) syntax in C and
268 to bracket syntax [[...]] in C++, there is one available position:
269 - before the return type.
270 Whereas, if we use the 'EXTERN_C_FUNC' idiom, which conditionally
271 omits the 'extern' keyword:
272 * If _GL_ATTRIBUTE_* expands to bracket syntax [[...]]
273 in both C and C++, there are two available positions:
274 - before the return type,
275 - between the function name and the parameter list.
276 * If _GL_ATTRIBUTE_* expands to __attribute__((...)) syntax
277 in both C and C++, there are several available positions:
278 - before the return type,
279 - between return type and function name,
280 - at the end of the declaration.
281 * If _GL_ATTRIBUTE_* expands to bracket syntax [[...]] in C and to
282 __attribute__((...)) syntax in C++, there is one available position:
283 - before the return type.
284 * If _GL_ATTRIBUTE_* expands to __attribute__((...)) syntax in C and
285 to bracket syntax [[...]] in C++, there is one available position:
286 - before the return type.
287 The best choice is therefore to use the 'EXTERN_C_FUNC' idiom and
288 put the attributes before the return type. This works regardless
289 to what the _GL_ATTRIBUTE_* macros expand.
290 */
291
292/* Attributes in bracket syntax [[...]] vs. attributes in __attribute__((...))
293 syntax, in static/inline function definitions.
294
295 There are similar constraints as for function declarations. However, here,
296 we cannot omit the storage-class specifier. Therefore, the following rule
297 applies:
298 * The macros
299 _GL_ATTRIBUTE_CONST
300 _GL_ATTRIBUTE_DEPRECATED
301 _GL_ATTRIBUTE_MAYBE_UNUSED
302 _GL_ATTRIBUTE_NODISCARD
303 _GL_ATTRIBUTE_PURE
304 _GL_ATTRIBUTE_REPRODUCIBLE
305 _GL_ATTRIBUTE_UNSEQUENCED
306 which may expand to bracket syntax [[...]], must come first, before the
307 storage-class specifier.
308 * Other _GL_ATTRIBUTE_* macros, that expand to __attribute__((...)) syntax,
309 are better placed between the storage-class specifier and the return
310 type.
311 */
312
313/* Attributes in bracket syntax [[...]] vs. attributes in __attribute__((...))
314 syntax, in variable declarations.
315
316 At which position can they be placed?
317 (Last tested with gcc/g++ 14 and clang/clang++ 18.)
318
319 =========================== foo.c = foo.cc ===========================
320 #ifdef __cplusplus
321 # define CC "C"
322 #else
323 # define CC
324 #endif
325
326 #define BD [[__deprecated__]]
327 #define AD __attribute__ ((__deprecated__))
328
329 // gcc clang g++ clang++
330
331 BD extern CC int var; // error error
332 extern CC BD int var; // error error
333 extern CC int BD var; // warn error warn error
334 extern CC int var BD;
335
336 AD extern CC int var; // warn
337 extern CC AD int var;
338 extern CC int AD var;
339 extern CC int var AD;
340
341 BD extern CC int z[]; // error error
342 extern CC BD int z[]; // error error
343 extern CC int BD z[]; // warn error warn error
344 extern CC int z1 BD [];
345 extern CC int z[] BD; // warn error error
346
347 AD extern CC int z[]; // warn
348 extern CC AD int z[];
349 extern CC int AD z[];
350 extern CC int z2 AD []; // error error error error
351 extern CC int z[] AD;
352 ======================================================================
353
354 * For non-array variables, the only good position is after the variable name,
355 that is, at the end of the declaration.
356 * For array variables, you will need to distinguish C and C++:
357 - In C, before the 'extern' keyword.
358 - In C++, between the 'extern "C"' and the variable's type.
359 */
148]dnl There is no _GL_ATTRIBUTE_ALIGNED; use stdalign's alignas instead. 360]dnl There is no _GL_ATTRIBUTE_ALIGNED; use stdalign's alignas instead.
149[ 361[
150/* _GL_ATTRIBUTE_ALLOC_SIZE ((N)) declares that the Nth argument of the function 362/* _GL_ATTRIBUTE_ALLOC_SIZE ((N)) declares that the Nth argument of the function
@@ -152,7 +364,7 @@ AC_DEFUN([gl_COMMON_BODY], [
152 _GL_ATTRIBUTE_ALLOC_SIZE ((M, N)) declares that the Mth argument multiplied 364 _GL_ATTRIBUTE_ALLOC_SIZE ((M, N)) declares that the Mth argument multiplied
153 by the Nth argument of the function is the size of the returned memory block. 365 by the Nth argument of the function is the size of the returned memory block.
154 */ 366 */
155/* Applies to: function, pointer to function, function types. */ 367/* Applies to: functions, pointer to functions, function types. */
156#ifndef _GL_ATTRIBUTE_ALLOC_SIZE 368#ifndef _GL_ATTRIBUTE_ALLOC_SIZE
157# if _GL_HAS_ATTRIBUTE (alloc_size) 369# if _GL_HAS_ATTRIBUTE (alloc_size)
158# define _GL_ATTRIBUTE_ALLOC_SIZE(args) __attribute__ ((__alloc_size__ args)) 370# define _GL_ATTRIBUTE_ALLOC_SIZE(args) __attribute__ ((__alloc_size__ args))
@@ -163,7 +375,7 @@ AC_DEFUN([gl_COMMON_BODY], [
163 375
164/* _GL_ATTRIBUTE_ALWAYS_INLINE tells that the compiler should always inline the 376/* _GL_ATTRIBUTE_ALWAYS_INLINE tells that the compiler should always inline the
165 function and report an error if it cannot do so. */ 377 function and report an error if it cannot do so. */
166/* Applies to: function. */ 378/* Applies to: functions. */
167#ifndef _GL_ATTRIBUTE_ALWAYS_INLINE 379#ifndef _GL_ATTRIBUTE_ALWAYS_INLINE
168# if _GL_HAS_ATTRIBUTE (always_inline) 380# if _GL_HAS_ATTRIBUTE (always_inline)
169# define _GL_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((__always_inline__)) 381# define _GL_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((__always_inline__))
@@ -175,7 +387,7 @@ AC_DEFUN([gl_COMMON_BODY], [
175/* _GL_ATTRIBUTE_ARTIFICIAL declares that the function is not important to show 387/* _GL_ATTRIBUTE_ARTIFICIAL declares that the function is not important to show
176 in stack traces when debugging. The compiler should omit the function from 388 in stack traces when debugging. The compiler should omit the function from
177 stack traces. */ 389 stack traces. */
178/* Applies to: function. */ 390/* Applies to: functions. */
179#ifndef _GL_ATTRIBUTE_ARTIFICIAL 391#ifndef _GL_ATTRIBUTE_ARTIFICIAL
180# if _GL_HAS_ATTRIBUTE (artificial) 392# if _GL_HAS_ATTRIBUTE (artificial)
181# define _GL_ATTRIBUTE_ARTIFICIAL __attribute__ ((__artificial__)) 393# define _GL_ATTRIBUTE_ARTIFICIAL __attribute__ ((__artificial__))
@@ -201,18 +413,23 @@ AC_DEFUN([gl_COMMON_BODY], [
201# endif 413# endif
202#endif 414#endif
203 415
204/* _GL_ATTRIBUTE_CONST declares that it is OK for a compiler to omit duplicate 416/* _GL_ATTRIBUTE_CONST declares:
205 calls to the function with the same arguments. 417 It is OK for a compiler to move calls to the function and to omit
206 This attribute is safe for a function that neither depends on nor affects 418 calls to the function if another call has the same arguments or the
207 observable state, and always returns exactly once - e.g., does not loop 419 result is not used.
208 forever, and does not call longjmp. 420 This attribute is safe for a function that neither depends on
209 (This attribute is stricter than _GL_ATTRIBUTE_PURE.) */ 421 nor affects state, and always returns exactly once -
422 e.g., does not raise an exception, call longjmp, or loop forever.
423 (This attribute is stricter than _GL_ATTRIBUTE_PURE because the
424 function cannot observe state. It is stricter than
425 _GL_ATTRIBUTE_UNSEQUENCED because the function must return exactly
426 once and cannot depend on state addressed by its arguments.) */
210/* Applies to: functions. */ 427/* Applies to: functions. */
211#ifndef _GL_ATTRIBUTE_CONST 428#ifndef _GL_ATTRIBUTE_CONST
212# if _GL_HAS_ATTRIBUTE (const) 429# if _GL_HAS_ATTRIBUTE (const)
213# define _GL_ATTRIBUTE_CONST __attribute__ ((__const__)) 430# define _GL_ATTRIBUTE_CONST __attribute__ ((__const__))
214# else 431# else
215# define _GL_ATTRIBUTE_CONST 432# define _GL_ATTRIBUTE_CONST _GL_ATTRIBUTE_UNSEQUENCED
216# endif 433# endif
217#endif 434#endif
218 435
@@ -460,6 +677,17 @@ AC_DEFUN([gl_COMMON_BODY], [
460# endif 677# endif
461#endif 678#endif
462 679
680/* _GL_ATTRIBUTE_NONNULL_IF_NONZERO (NP, NI) declares that the argument NP
681 (a pointer) must not be NULL if the argument NI (an integer) is != 0. */
682/* Applies to: functions. */
683#ifndef _GL_ATTRIBUTE_NONNULL_IF_NONZERO
684# if _GL_HAS_ATTRIBUTE (nonnull_if_nonzero)
685# define _GL_ATTRIBUTE_NONNULL_IF_NONZERO(np, ni) __attribute__ ((__nonnull_if_nonzero__ (np, ni)))
686# else
687# define _GL_ATTRIBUTE_NONNULL_IF_NONZERO(np, ni)
688# endif
689#endif
690
463/* _GL_ATTRIBUTE_NONSTRING declares that the contents of a character array is 691/* _GL_ATTRIBUTE_NONSTRING declares that the contents of a character array is
464 not meant to be NUL-terminated. */ 692 not meant to be NUL-terminated. */
465/* Applies to: struct/union members and variables that are arrays of element 693/* Applies to: struct/union members and variables that are arrays of element
@@ -481,7 +709,7 @@ AC_DEFUN([gl_COMMON_BODY], [
481 other attributes. */ 709 other attributes. */
482#ifndef _GL_ATTRIBUTE_NOTHROW 710#ifndef _GL_ATTRIBUTE_NOTHROW
483# if defined __cplusplus 711# if defined __cplusplus
484# if _GL_GNUC_PREREQ (2, 8) || __clang_major >= 4 712# if _GL_GNUC_PREREQ (2, 8) || __clang_major__ >= 4
485# if __cplusplus >= 201103L 713# if __cplusplus >= 201103L
486# define _GL_ATTRIBUTE_NOTHROW noexcept (true) 714# define _GL_ATTRIBUTE_NOTHROW noexcept (true)
487# else 715# else
@@ -505,9 +733,9 @@ AC_DEFUN([gl_COMMON_BODY], [
505 minimizing the memory required. */ 733 minimizing the memory required. */
506/* Applies to: struct members, struct, union, 734/* Applies to: struct members, struct, union,
507 in C++ also: class. */ 735 in C++ also: class. */
736#ifndef _GL_ATTRIBUTE_PACKED
508/* Oracle Studio 12.6 miscompiles code with __attribute__ ((__packed__)) despite 737/* Oracle Studio 12.6 miscompiles code with __attribute__ ((__packed__)) despite
509 __has_attribute OK. */ 738 __has_attribute OK. */
510#ifndef _GL_ATTRIBUTE_PACKED
511# if _GL_HAS_ATTRIBUTE (packed) && !defined __SUNPRO_C 739# if _GL_HAS_ATTRIBUTE (packed) && !defined __SUNPRO_C
512# define _GL_ATTRIBUTE_PACKED __attribute__ ((__packed__)) 740# define _GL_ATTRIBUTE_PACKED __attribute__ ((__packed__))
513# else 741# else
@@ -515,18 +743,51 @@ AC_DEFUN([gl_COMMON_BODY], [
515# endif 743# endif
516#endif 744#endif
517 745
518/* _GL_ATTRIBUTE_PURE declares that It is OK for a compiler to omit duplicate 746/* _GL_ATTRIBUTE_PURE declares:
519 calls to the function with the same arguments if observable state is not 747 It is OK for a compiler to move calls to the function and to omit
520 changed between calls. 748 calls to the function if another call has the same arguments or the
521 This attribute is safe for a function that does not affect 749 result is not used, and if observable state is the same.
522 observable state, and always returns exactly once. 750 This attribute is safe for a function that does not affect observable state
523 (This attribute is looser than _GL_ATTRIBUTE_CONST.) */ 751 and always returns exactly once.
752 (This attribute is looser than _GL_ATTRIBUTE_CONST because the function
753 can depend on observable state. It is stricter than
754 _GL_ATTRIBUTE_REPRODUCIBLE because the function must return exactly
755 once and cannot affect state addressed by its arguments.) */
524/* Applies to: functions. */ 756/* Applies to: functions. */
525#ifndef _GL_ATTRIBUTE_PURE 757#ifndef _GL_ATTRIBUTE_PURE
526# if _GL_HAS_ATTRIBUTE (pure) 758# if _GL_HAS_ATTRIBUTE (pure)
527# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) 759# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
528# else 760# else
529# define _GL_ATTRIBUTE_PURE 761# define _GL_ATTRIBUTE_PURE _GL_ATTRIBUTE_REPRODUCIBLE
762# endif
763#endif
764
765/* _GL_ATTRIBUTE_REPRODUCIBLE declares:
766 It is OK for a compiler to move calls to the function and to omit duplicate
767 calls to the function with the same arguments, so long as the state
768 addressed by its arguments is the same and is updated in time for
769 the rest of the program.
770 This attribute is safe for a function that is effectless and idempotent; see
771 ISO C 23 § 6.7.12.7 for a definition of these terms.
772 (This attribute is looser than _GL_ATTRIBUTE_UNSEQUENCED because
773 the function need not be stateless and idempotent. It is looser
774 than _GL_ATTRIBUTE_PURE because the function need not return
775 exactly once and can affect state addressed by its arguments.)
776 See also <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2956.htm> and
777 <https://stackoverflow.com/questions/76847905/>.
778 ATTENTION! Efforts are underway to change the meaning of this attribute.
779 See <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3424.htm>. */
780/* Applies to: functions, pointer to functions, function types. */
781#ifndef _GL_ATTRIBUTE_REPRODUCIBLE
782/* This may be revisited when gcc and clang support [[reproducible]] or possibly
783 __attribute__ ((__reproducible__)). */
784# ifndef _GL_BRACKET_BEFORE_ATTRIBUTE
785# if _GL_HAS_ATTRIBUTE (reproducible)
786# define _GL_ATTRIBUTE_REPRODUCIBLE [[reproducible]]
787# endif
788# endif
789# ifndef _GL_ATTRIBUTE_REPRODUCIBLE
790# define _GL_ATTRIBUTE_REPRODUCIBLE
530# endif 791# endif
531#endif 792#endif
532 793
@@ -554,6 +815,35 @@ AC_DEFUN([gl_COMMON_BODY], [
554# endif 815# endif
555#endif 816#endif
556 817
818/* _GL_ATTRIBUTE_UNSEQUENCED declares:
819 It is OK for a compiler to move calls to the function and to omit duplicate
820 calls to the function with the same arguments, so long as the state
821 addressed by its arguments is the same.
822 This attribute is safe for a function that is effectless, idempotent,
823 stateless, and independent; see ISO C 23 § 6.7.12.7 for a definition of
824 these terms.
825 (This attribute is stricter than _GL_ATTRIBUTE_REPRODUCIBLE because
826 the function must be stateless and independent. It is looser than
827 _GL_ATTRIBUTE_CONST because the function need not return exactly
828 once and can depend on state addressed by its arguments.)
829 See also <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2956.htm> and
830 <https://stackoverflow.com/questions/76847905/>.
831 ATTENTION! Efforts are underway to change the meaning of this attribute.
832 See <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3424.htm>. */
833/* Applies to: functions, pointer to functions, function types. */
834#ifndef _GL_ATTRIBUTE_UNSEQUENCED
835/* This may be revisited when gcc and clang support [[unsequenced]] or possibly
836 __attribute__ ((__unsequenced__)). */
837# ifndef _GL_BRACKET_BEFORE_ATTRIBUTE
838# if _GL_HAS_ATTRIBUTE (unsequenced)
839# define _GL_ATTRIBUTE_UNSEQUENCED [[unsequenced]]
840# endif
841# endif
842# ifndef _GL_ATTRIBUTE_UNSEQUENCED
843# define _GL_ATTRIBUTE_UNSEQUENCED
844# endif
845#endif
846
557/* A helper macro. Don't use it directly. */ 847/* A helper macro. Don't use it directly. */
558#ifndef _GL_ATTRIBUTE_UNUSED 848#ifndef _GL_ATTRIBUTE_UNUSED
559# if _GL_HAS_ATTRIBUTE (unused) 849# if _GL_HAS_ATTRIBUTE (unused)
@@ -578,6 +868,35 @@ AC_DEFUN([gl_COMMON_BODY], [
578# define _GL_UNUSED_LABEL 868# define _GL_UNUSED_LABEL
579# endif 869# endif
580#endif 870#endif
871
872/* The following attributes enable detection of multithread-safety problems
873 and resource leaks at compile-time, by clang ≥ 15, when the warning option
874 -Wthread-safety is enabled. For usage, see
875 <https://clang.llvm.org/docs/ThreadSafetyAnalysis.html>. */
876#ifndef _GL_ATTRIBUTE_CAPABILITY_TYPE
877# if __clang_major__ >= 15
878# define _GL_ATTRIBUTE_CAPABILITY_TYPE(concept) \
879 __attribute__ ((__capability__ (concept)))
880# else
881# define _GL_ATTRIBUTE_CAPABILITY_TYPE(concept)
882# endif
883#endif
884#ifndef _GL_ATTRIBUTE_ACQUIRE_CAPABILITY
885# if __clang_major__ >= 15
886# define _GL_ATTRIBUTE_ACQUIRE_CAPABILITY(resource) \
887 __attribute__ ((__acquire_capability__ (resource)))
888# else
889# define _GL_ATTRIBUTE_ACQUIRE_CAPABILITY(resource)
890# endif
891#endif
892#ifndef _GL_ATTRIBUTE_RELEASE_CAPABILITY
893# if __clang_major__ >= 15
894# define _GL_ATTRIBUTE_RELEASE_CAPABILITY(resource) \
895 __attribute__ ((__release_capability__ (resource)))
896# else
897# define _GL_ATTRIBUTE_RELEASE_CAPABILITY(resource)
898# endif
899#endif
581]) 900])
582 AH_VERBATIM([c_linkage], 901 AH_VERBATIM([c_linkage],
583[/* In C++, there is the concept of "language linkage", that encompasses 902[/* In C++, there is the concept of "language linkage", that encompasses
@@ -628,8 +947,8 @@ AC_DEFUN([gl_COMMON_BODY], [
628 -1 if n1 < n2 947 -1 if n1 < n2
629 The naïve code (n1 > n2 ? 1 : n1 < n2 ? -1 : 0) produces a conditional 948 The naïve code (n1 > n2 ? 1 : n1 < n2 ? -1 : 0) produces a conditional
630 jump with nearly all GCC versions up to GCC 10. 949 jump with nearly all GCC versions up to GCC 10.
631 This variant (n1 < n2 ? -1 : n1 > n2) produces a conditional with many 950 This variant (n1 < n2 ? -1 : n1 > n2) produces a conditional jump with
632 GCC versions up to GCC 9. 951 many GCC versions up to GCC 9.
633 The better code (n1 > n2) - (n1 < n2) from Hacker's Delight § 2-9 952 The better code (n1 > n2) - (n1 < n2) from Hacker's Delight § 2-9
634 avoids conditional jumps in all GCC versions >= 3.4. */ 953 avoids conditional jumps in all GCC versions >= 3.4. */
635#define _GL_CMP(n1, n2) (((n1) > (n2)) - ((n1) < (n2))) 954#define _GL_CMP(n1, n2) (((n1) > (n2)) - ((n1) < (n2)))
@@ -1006,7 +1325,7 @@ AC_DEFUN([gl_CC_ALLOW_WARNINGS],
1006 AC_REQUIRE([AC_PROG_CC]) 1325 AC_REQUIRE([AC_PROG_CC])
1007 AC_CACHE_CHECK([for C compiler option to allow warnings], 1326 AC_CACHE_CHECK([for C compiler option to allow warnings],
1008 [gl_cv_cc_wallow], 1327 [gl_cv_cc_wallow],
1009 [rm -f conftest* 1328 [rm -fr conftest*
1010 echo 'int dummy;' > conftest.c 1329 echo 'int dummy;' > conftest.c
1011 AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -c conftest.c 2>conftest1.err]) >/dev/null 1330 AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -c conftest.c 2>conftest1.err]) >/dev/null
1012 AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -Wno-error -c conftest.c 2>conftest2.err]) >/dev/null 1331 AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -Wno-error -c conftest.c 2>conftest2.err]) >/dev/null
@@ -1019,7 +1338,7 @@ AC_DEFUN([gl_CC_ALLOW_WARNINGS],
1019 else 1338 else
1020 gl_cv_cc_wallow=none 1339 gl_cv_cc_wallow=none
1021 fi 1340 fi
1022 rm -f conftest* 1341 rm -fr conftest*
1023 ]) 1342 ])
1024 case "$gl_cv_cc_wallow" in 1343 case "$gl_cv_cc_wallow" in
1025 none) GL_CFLAG_ALLOW_WARNINGS='' ;; 1344 none) GL_CFLAG_ALLOW_WARNINGS='' ;;
@@ -1037,7 +1356,7 @@ AC_DEFUN([gl_CXX_ALLOW_WARNINGS],
1037 if test -n "$CXX" && test "$CXX" != no; then 1356 if test -n "$CXX" && test "$CXX" != no; then
1038 AC_CACHE_CHECK([for C++ compiler option to allow warnings], 1357 AC_CACHE_CHECK([for C++ compiler option to allow warnings],
1039 [gl_cv_cxx_wallow], 1358 [gl_cv_cxx_wallow],
1040 [rm -f conftest* 1359 [rm -fr conftest*
1041 echo 'int dummy;' > conftest.cc 1360 echo 'int dummy;' > conftest.cc
1042 AC_TRY_COMMAND([${CXX-c++} $CXXFLAGS $CPPFLAGS -c conftest.cc 2>conftest1.err]) >/dev/null 1361 AC_TRY_COMMAND([${CXX-c++} $CXXFLAGS $CPPFLAGS -c conftest.cc 2>conftest1.err]) >/dev/null
1043 AC_TRY_COMMAND([${CXX-c++} $CXXFLAGS $CPPFLAGS -Wno-error -c conftest.cc 2>conftest2.err]) >/dev/null 1362 AC_TRY_COMMAND([${CXX-c++} $CXXFLAGS $CPPFLAGS -Wno-error -c conftest.cc 2>conftest2.err]) >/dev/null
@@ -1050,7 +1369,7 @@ AC_DEFUN([gl_CXX_ALLOW_WARNINGS],
1050 else 1369 else
1051 gl_cv_cxx_wallow=none 1370 gl_cv_cxx_wallow=none
1052 fi 1371 fi
1053 rm -f conftest* 1372 rm -fr conftest*
1054 ]) 1373 ])
1055 case "$gl_cv_cxx_wallow" in 1374 case "$gl_cv_cxx_wallow" in
1056 none) GL_CXXFLAG_ALLOW_WARNINGS='' ;; 1375 none) GL_CXXFLAG_ALLOW_WARNINGS='' ;;
@@ -1087,11 +1406,12 @@ AC_DEFUN([gl_CC_GNULIB_WARNINGS],
1087 dnl -Wno-type-limits >= 4.3 >= 3.9 1406 dnl -Wno-type-limits >= 4.3 >= 3.9
1088 dnl -Wno-undef >= 3 >= 3.9 1407 dnl -Wno-undef >= 3 >= 3.9
1089 dnl -Wno-unsuffixed-float-constants >= 4.5 1408 dnl -Wno-unsuffixed-float-constants >= 4.5
1409 dnl -Wno-unused-const-variable >= 4.4 >= 3.9
1090 dnl -Wno-unused-function >= 3 >= 3.9 1410 dnl -Wno-unused-function >= 3 >= 3.9
1091 dnl -Wno-unused-parameter >= 3 >= 3.9 1411 dnl -Wno-unused-parameter >= 3 >= 3.9
1092 dnl 1412 dnl
1093 cat > conftest.c <<\EOF 1413 cat > conftest.c <<\EOF
1094 #if __GNUC__ >= 3 || (__clang_major__ + (__clang_minor__ >= 9) > 3) 1414 #if (__GNUC__ >= 3 && !defined __clang__) || (__clang_major__ + (__clang_minor__ >= 9) > 3)
1095 -Wno-cast-qual 1415 -Wno-cast-qual
1096 -Wno-conversion 1416 -Wno-conversion
1097 -Wno-float-equal 1417 -Wno-float-equal
@@ -1100,23 +1420,26 @@ AC_DEFUN([gl_CC_GNULIB_WARNINGS],
1100 -Wno-unused-function 1420 -Wno-unused-function
1101 -Wno-unused-parameter 1421 -Wno-unused-parameter
1102 #endif 1422 #endif
1103 #if __GNUC__ + (__GNUC_MINOR__ >= 9) > 4 || (__clang_major__ + (__clang_minor__ >= 9) > 3) 1423 #if (__GNUC__ + (__GNUC_MINOR__ >= 9) > 4 && !defined __clang__) || (__clang_major__ + (__clang_minor__ >= 9) > 3)
1104 -Wno-float-conversion 1424 -Wno-float-conversion
1105 #endif 1425 #endif
1106 #if __GNUC__ >= 7 || (__clang_major__ + (__clang_minor__ >= 9) > 3) 1426 #if (__GNUC__ >= 7 && !defined __clang__) || (__clang_major__ + (__clang_minor__ >= 9) > 3)
1107 -Wimplicit-fallthrough 1427 -Wimplicit-fallthrough
1108 #endif 1428 #endif
1109 #if __GNUC__ + (__GNUC_MINOR__ >= 8) > 4 || (__clang_major__ + (__clang_minor__ >= 9) > 3) 1429 #if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 4 && !defined __clang__) || (__clang_major__ + (__clang_minor__ >= 9) > 3)
1110 -Wno-pedantic 1430 -Wno-pedantic
1111 #endif 1431 #endif
1112 #if 3 < __clang_major__ + (9 <= __clang_minor__) 1432 #if 3 < __clang_major__ + (9 <= __clang_minor__)
1113 -Wno-tautological-constant-out-of-range-compare 1433 -Wno-tautological-constant-out-of-range-compare
1114 #endif 1434 #endif
1115 #if __GNUC__ + (__GNUC_MINOR__ >= 3) > 4 || (__clang_major__ + (__clang_minor__ >= 9) > 3) 1435 #if (__GNUC__ + (__GNUC_MINOR__ >= 3) > 4 && !defined __clang__) || (__clang_major__ + (__clang_minor__ >= 9) > 3)
1116 -Wno-sign-conversion 1436 -Wno-sign-conversion
1117 -Wno-type-limits 1437 -Wno-type-limits
1118 #endif 1438 #endif
1119 #if __GNUC__ + (__GNUC_MINOR__ >= 5) > 4 1439 #if (__GNUC__ + (__GNUC_MINOR__ >= 4) > 4 && !defined __clang__) || (__clang_major__ + (__clang_minor__ >= 9) > 3)
1440 -Wno-unused-const-variable
1441 #endif
1442 #if (__GNUC__ + (__GNUC_MINOR__ >= 5) > 4 && !defined __clang__)
1120 -Wno-unsuffixed-float-constants 1443 -Wno-unsuffixed-float-constants
1121 #endif 1444 #endif
1122EOF 1445EOF
@@ -1240,13 +1563,25 @@ AC_DEFUN([gl_CHECK_FUNCS_CASE_FOR_MACOS],
1240 if test $[ac_cv_func_][$1] = yes; then 1563 if test $[ac_cv_func_][$1] = yes; then
1241 [gl_cv_onwards_func_][$1]=yes 1564 [gl_cv_onwards_func_][$1]=yes
1242 else 1565 else
1566 dnl This is a bit complicated, because here we need the behaviour
1567 dnl of AC_CHECK_DECL before the
1568 dnl commit e1bbc9b93cdff61d70719c224b37970e065008bb (2025-05-26).
1569 [ac_cv_have_decl_][$1][_saved]="$[ac_cv_have_decl_][$1]"
1243 unset [ac_cv_have_decl_][$1] 1570 unset [ac_cv_have_decl_][$1]
1571 ac_c_future_darwin_options_saved="$ac_c_future_darwin_options"
1572 ac_cxx_future_darwin_options_saved="$ac_cxx_future_darwin_options"
1573 ac_c_future_darwin_options=
1574 ac_cxx_future_darwin_options=
1244 AC_CHECK_DECL([$1], , , [$2]) 1575 AC_CHECK_DECL([$1], , , [$2])
1576 ac_c_future_darwin_options="$ac_c_future_darwin_options_saved"
1577 ac_cxx_future_darwin_options="$ac_cxx_future_darwin_options_saved"
1245 if test $[ac_cv_have_decl_][$1] = yes; then 1578 if test $[ac_cv_have_decl_][$1] = yes; then
1246 [gl_cv_onwards_func_][$1]='future OS version' 1579 [gl_cv_onwards_func_][$1]='future OS version'
1247 else 1580 else
1248 [gl_cv_onwards_func_][$1]=no 1581 [gl_cv_onwards_func_][$1]=no
1249 fi 1582 fi
1583 [ac_cv_have_decl_][$1]="$[ac_cv_have_decl_][$1][_saved]"
1584 unset [ac_cv_have_decl_][$1][_saved]
1250 fi 1585 fi
1251 else 1586 else
1252 AC_CHECK_FUNC([$1]) 1587 AC_CHECK_FUNC([$1])
@@ -1299,7 +1634,7 @@ dnl
1299dnl This macro sets two variables: 1634dnl This macro sets two variables:
1300dnl - gl_cv_onwards_func_<func> to yes / no / "future OS version" 1635dnl - gl_cv_onwards_func_<func> to yes / no / "future OS version"
1301dnl - ac_cv_func_<func> to yes / no / no 1636dnl - ac_cv_func_<func> to yes / no / no
1302dnl The first variable allows to distinguish all three cases. 1637dnl The first variable allows distinguishing all three cases.
1303dnl The second variable is set, so that an invocation 1638dnl The second variable is set, so that an invocation
1304dnl gl_CHECK_FUNCS_ANDROID([func], [[#include <foo.h>]]) 1639dnl gl_CHECK_FUNCS_ANDROID([func], [[#include <foo.h>]])
1305dnl can be used as a drop-in replacement for 1640dnl can be used as a drop-in replacement for
@@ -1352,7 +1687,7 @@ dnl
1352dnl This macro sets two variables: 1687dnl This macro sets two variables:
1353dnl - gl_cv_onwards_func_<func> to yes / no / "future OS version" 1688dnl - gl_cv_onwards_func_<func> to yes / no / "future OS version"
1354dnl - ac_cv_func_<func> to yes / no / no 1689dnl - ac_cv_func_<func> to yes / no / no
1355dnl The first variable allows to distinguish all three cases. 1690dnl The first variable allows distinguishing all three cases.
1356dnl The second variable is set, so that an invocation 1691dnl The second variable is set, so that an invocation
1357dnl gl_CHECK_FUNCS_MACOS([func], [[#include <foo.h>]]) 1692dnl gl_CHECK_FUNCS_MACOS([func], [[#include <foo.h>]])
1358dnl can be used as a drop-in replacement for 1693dnl can be used as a drop-in replacement for
diff --git a/gl/m4/gnulib-comp.m4 b/gl/m4/gnulib-comp.m4
index 83a0f727..50e98454 100644
--- a/gl/m4/gnulib-comp.m4
+++ b/gl/m4/gnulib-comp.m4
@@ -1,5 +1,5 @@
1# DO NOT EDIT! GENERATED AUTOMATICALLY! 1# DO NOT EDIT! GENERATED AUTOMATICALLY!
2# Copyright (C) 2002-2024 Free Software Foundation, Inc. 2# Copyright (C) 2002-2025 Free Software Foundation, Inc.
3# 3#
4# This file is free software; you can redistribute it and/or modify 4# This file is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
@@ -45,14 +45,30 @@ AC_DEFUN([gl_EARLY],
45 # Code from module absolute-header: 45 # Code from module absolute-header:
46 # Code from module alignasof: 46 # Code from module alignasof:
47 # Code from module alloca-opt: 47 # Code from module alloca-opt:
48 # Code from module arpa_inet: 48 # Code from module arpa_inet-h:
49 # Code from module assert-h: 49 # Code from module assert-h:
50 # Code from module attribute: 50 # Code from module attribute:
51 # Code from module base64: 51 # Code from module base64:
52 # Code from module basename-lgpl: 52 # Code from module basename-lgpl:
53 # Code from module bool:
53 # Code from module btowc: 54 # Code from module btowc:
54 # Code from module builtin-expect: 55 # Code from module builtin-expect:
55 # Code from module byteswap: 56 # Code from module byteswap:
57 # Code from module c-ctype:
58 # Code from module c32isalnum:
59 # Code from module c32isalpha:
60 # Code from module c32isblank:
61 # Code from module c32iscntrl:
62 # Code from module c32isdigit:
63 # Code from module c32isgraph:
64 # Code from module c32islower:
65 # Code from module c32isprint:
66 # Code from module c32ispunct:
67 # Code from module c32isspace:
68 # Code from module c32isupper:
69 # Code from module c32isxdigit:
70 # Code from module c32tolower:
71 # Code from module c32width:
56 # Code from module c99: 72 # Code from module c99:
57 # Code from module calloc-gnu: 73 # Code from module calloc-gnu:
58 # Code from module calloc-posix: 74 # Code from module calloc-posix:
@@ -66,11 +82,15 @@ AC_DEFUN([gl_EARLY],
66 # Code from module double-slash-root: 82 # Code from module double-slash-root:
67 # Code from module dup2: 83 # Code from module dup2:
68 # Code from module environ: 84 # Code from module environ:
69 # Code from module errno: 85 # Code from module errno-h:
70 # Code from module error: 86 # Code from module error:
71 # Code from module error-h: 87 # Code from module error-h:
72 # Code from module exitfail: 88 # Code from module exitfail:
73 # Code from module extensions: 89 # Code from module extensions:
90 # This is actually already done in the pre-early phase.
91 # AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
92 # Code from module extensions-aix:
93 AC_REQUIRE([gl_USE_AIX_EXTENSIONS])
74 # Code from module extern-inline: 94 # Code from module extern-inline:
75 # Code from module fcntl: 95 # Code from module fcntl:
76 # Code from module fcntl-h: 96 # Code from module fcntl-h:
@@ -78,7 +98,7 @@ AC_DEFUN([gl_EARLY],
78 # Code from module fflush: 98 # Code from module fflush:
79 AC_REQUIRE([gl_SET_LARGEFILE_SOURCE]) 99 AC_REQUIRE([gl_SET_LARGEFILE_SOURCE])
80 # Code from module filename: 100 # Code from module filename:
81 # Code from module float: 101 # Code from module float-h:
82 # Code from module floorf: 102 # Code from module floorf:
83 # Code from module fopen: 103 # Code from module fopen:
84 # Code from module fopen-gnu: 104 # Code from module fopen-gnu:
@@ -88,6 +108,7 @@ AC_DEFUN([gl_EARLY],
88 # Code from module fseek: 108 # Code from module fseek:
89 # Code from module fseeko: 109 # Code from module fseeko:
90 AC_REQUIRE([gl_SET_LARGEFILE_SOURCE]) 110 AC_REQUIRE([gl_SET_LARGEFILE_SOURCE])
111 # Code from module fseterr:
91 # Code from module fstat: 112 # Code from module fstat:
92 # Code from module fsusage: 113 # Code from module fsusage:
93 # Code from module ftell: 114 # Code from module ftell:
@@ -105,6 +126,7 @@ AC_DEFUN([gl_EARLY],
105 # Code from module getprogname: 126 # Code from module getprogname:
106 # Code from module gettext-h: 127 # Code from module gettext-h:
107 # Code from module glibc-internal/dynarray: 128 # Code from module glibc-internal/dynarray:
129 # Code from module gnulib-i18n:
108 # Code from module hard-locale: 130 # Code from module hard-locale:
109 # Code from module hostent: 131 # Code from module hostent:
110 # Code from module ialloc: 132 # Code from module ialloc:
@@ -112,29 +134,35 @@ AC_DEFUN([gl_EARLY],
112 # Code from module idx: 134 # Code from module idx:
113 # Code from module include_next: 135 # Code from module include_next:
114 # Code from module inet_ntop: 136 # Code from module inet_ntop:
137 # Code from module inet_pton:
115 # Code from module intprops: 138 # Code from module intprops:
116 # Code from module inttypes-incomplete: 139 # Code from module inttypes-h-incomplete:
117 # Code from module iswblank: 140 # Code from module iswblank:
118 # Code from module iswctype: 141 # Code from module iswctype:
119 # Code from module iswdigit: 142 # Code from module iswdigit:
120 # Code from module iswpunct: 143 # Code from module iswpunct:
121 # Code from module iswxdigit: 144 # Code from module iswxdigit:
122 # Code from module langinfo: 145 # Code from module langinfo-h:
123 # Code from module largefile: 146 # Code from module largefile:
124 AC_REQUIRE([AC_SYS_LARGEFILE]) 147 AC_REQUIRE([AC_SYS_LARGEFILE])
125 # Code from module libc-config: 148 # Code from module libc-config:
126 # Code from module limits-h: 149 # Code from module limits-h:
127 # Code from module localcharset: 150 # Code from module localcharset:
128 # Code from module locale: 151 # Code from module locale-h:
129 # Code from module localeconv: 152 # Code from module localeconv:
130 # Code from module lock: 153 # Code from module lock:
131 # Code from module lseek: 154 # Code from module lseek:
155 # Code from module lstat:
132 # Code from module malloc-gnu: 156 # Code from module malloc-gnu:
133 # Code from module malloc-posix: 157 # Code from module malloc-posix:
134 # Code from module malloca: 158 # Code from module malloca:
135 # Code from module math: 159 # Code from module math-h:
160 # Code from module mbchar:
161 # Code from module mbiterf:
162 # Code from module mbrtoc32:
136 # Code from module mbrtowc: 163 # Code from module mbrtowc:
137 # Code from module mbsinit: 164 # Code from module mbsinit:
165 # Code from module mbsnlen:
138 # Code from module mbszero: 166 # Code from module mbszero:
139 # Code from module mbtowc: 167 # Code from module mbtowc:
140 # Code from module memchr: 168 # Code from module memchr:
@@ -145,16 +173,20 @@ AC_DEFUN([gl_EARLY],
145 # Code from module msvc-inval: 173 # Code from module msvc-inval:
146 # Code from module msvc-nothrow: 174 # Code from module msvc-nothrow:
147 # Code from module multiarch: 175 # Code from module multiarch:
148 # Code from module netdb: 176 # Code from module netdb-h:
149 # Code from module netinet_in: 177 # Code from module netinet_in-h:
150 # Code from module nl_langinfo: 178 # Code from module nl_langinfo:
151 # Code from module nocrash: 179 # Code from module nocrash:
180 # Code from module once:
152 # Code from module open: 181 # Code from module open:
153 # Code from module pathmax: 182 # Code from module pathmax:
154 # Code from module realloc-gnu: 183 # Code from module pthread-h:
184 gl_ANYTHREADLIB_EARLY
185 # Code from module pthread-once:
155 # Code from module realloc-posix: 186 # Code from module realloc-posix:
156 # Code from module reallocarray: 187 # Code from module reallocarray:
157 # Code from module regex: 188 # Code from module regex:
189 # Code from module sched-h:
158 # Code from module servent: 190 # Code from module servent:
159 # Code from module setenv: 191 # Code from module setenv:
160 # Code from module setlocale-null: 192 # Code from module setlocale-null:
@@ -172,33 +204,56 @@ AC_DEFUN([gl_EARLY],
172 # Code from module stat: 204 # Code from module stat:
173 # Code from module stat-time: 205 # Code from module stat-time:
174 # Code from module std-gnu11: 206 # Code from module std-gnu11:
175 # Code from module stdbool: 207 # Code from module stdckdint-h:
176 # Code from module stdckdint: 208 # Code from module stddef-h:
177 # Code from module stddef: 209 # Code from module stdint-h:
178 # Code from module stdint: 210 # Code from module stdio-h:
179 # Code from module stdio:
180 gl_STDIO_H_EARLY 211 gl_STDIO_H_EARLY
181 # Code from module stdlib: 212 # Code from module stdlib-h:
182 # Code from module strcase: 213 # Code from module strcase:
214 # Code from module strcasecmp:
183 # Code from module strcasestr: 215 # Code from module strcasestr:
184 # Code from module strcasestr-simple: 216 # Code from module strcasestr-simple:
185 # Code from module streq: 217 # Code from module streq:
186 # Code from module strerror: 218 # Code from module strerror:
187 # Code from module strerror-override: 219 # Code from module strerror-override:
188 # Code from module string: 220 # Code from module string-h:
189 # Code from module strings: 221 # Code from module strings-h:
222 # Code from module strncasecmp:
223 # Code from module strncpy:
190 # Code from module strsep: 224 # Code from module strsep:
191 # Code from module strstr-simple: 225 # Code from module strstr-simple:
192 # Code from module sys_socket: 226 # Code from module sys_socket-h:
193 # Code from module sys_stat: 227 # Code from module sys_stat-h:
194 # Code from module sys_types: 228 # Code from module sys_types-h:
195 # Code from module sys_uio: 229 AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
230 # Code from module sys_uio-h:
196 # Code from module threadlib: 231 # Code from module threadlib:
197 gl_THREADLIB_EARLY 232 gl_THREADLIB_EARLY
198 # Code from module time-h: 233 # Code from module time-h:
199 # Code from module time_r: 234 # Code from module time_r:
200 # Code from module timegm: 235 # Code from module timegm:
201 # Code from module unistd: 236 # Code from module uchar-h:
237 # Code from module unicase/base:
238 # Code from module unicase/tolower:
239 # Code from module unictype/base:
240 # Code from module unictype/ctype-alnum:
241 # Code from module unictype/ctype-alpha:
242 # Code from module unictype/ctype-blank:
243 # Code from module unictype/ctype-cntrl:
244 # Code from module unictype/ctype-digit:
245 # Code from module unictype/ctype-graph:
246 # Code from module unictype/ctype-lower:
247 # Code from module unictype/ctype-print:
248 # Code from module unictype/ctype-punct:
249 # Code from module unictype/ctype-space:
250 # Code from module unictype/ctype-upper:
251 # Code from module unictype/ctype-xdigit:
252 # Code from module uninorm/base:
253 # Code from module unistd-h:
254 # Code from module unitypes-h:
255 # Code from module uniwidth/base:
256 # Code from module uniwidth/width:
202 # Code from module unlocked-io-internal: 257 # Code from module unlocked-io-internal:
203 # Code from module unsetenv: 258 # Code from module unsetenv:
204 # Code from module vararrays: 259 # Code from module vararrays:
@@ -206,10 +261,12 @@ AC_DEFUN([gl_EARLY],
206 # Code from module vasprintf: 261 # Code from module vasprintf:
207 # Code from module verify: 262 # Code from module verify:
208 # Code from module vsnprintf: 263 # Code from module vsnprintf:
209 # Code from module wchar: 264 # Code from module vsnzprintf:
265 # Code from module wchar-h:
210 # Code from module wcrtomb: 266 # Code from module wcrtomb:
211 # Code from module wctype: 267 # Code from module wctype:
212 # Code from module wctype-h: 268 # Code from module wctype-h:
269 # Code from module wcwidth:
213 # Code from module windows-mutex: 270 # Code from module windows-mutex:
214 # Code from module windows-once: 271 # Code from module windows-once:
215 # Code from module windows-recmutex: 272 # Code from module windows-recmutex:
@@ -250,6 +307,7 @@ AC_DEFUN([gl_INIT],
250 gl_CONDITIONAL_HEADER([assert.h]) 307 gl_CONDITIONAL_HEADER([assert.h])
251 AC_PROG_MKDIR_P 308 AC_PROG_MKDIR_P
252 gl_FUNC_BASE64 309 gl_FUNC_BASE64
310 gl_C_BOOL
253 gl_FUNC_BTOWC 311 gl_FUNC_BTOWC
254 gl_CONDITIONAL([GL_COND_OBJ_BTOWC], 312 gl_CONDITIONAL([GL_COND_OBJ_BTOWC],
255 [test $HAVE_BTOWC = 0 || test $REPLACE_BTOWC = 1]) 313 [test $HAVE_BTOWC = 0 || test $REPLACE_BTOWC = 1])
@@ -261,6 +319,104 @@ AC_DEFUN([gl_INIT],
261 gl_BYTESWAP 319 gl_BYTESWAP
262 gl_CONDITIONAL_HEADER([byteswap.h]) 320 gl_CONDITIONAL_HEADER([byteswap.h])
263 AC_PROG_MKDIR_P 321 AC_PROG_MKDIR_P
322 AC_REQUIRE([gl_UCHAR_H])
323 dnl Determine REPLACE_MBSTATE_T, from which GNULIB_defined_mbstate_t is
324 dnl determined. It describes how mbrtoc32 is implemented.
325 AC_REQUIRE([gl_MBSTATE_T_BROKEN])
326 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
327 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
328 gl_UCHAR_MODULE_INDICATOR([c32isalnum])
329 AC_REQUIRE([gl_UCHAR_H])
330 dnl Determine REPLACE_MBSTATE_T, from which GNULIB_defined_mbstate_t is
331 dnl determined. It describes how mbrtoc32 is implemented.
332 AC_REQUIRE([gl_MBSTATE_T_BROKEN])
333 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
334 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
335 gl_UCHAR_MODULE_INDICATOR([c32isalpha])
336 AC_REQUIRE([gl_UCHAR_H])
337 dnl Determine REPLACE_MBSTATE_T, from which GNULIB_defined_mbstate_t is
338 dnl determined. It describes how mbrtoc32 is implemented.
339 AC_REQUIRE([gl_MBSTATE_T_BROKEN])
340 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
341 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
342 gl_UCHAR_MODULE_INDICATOR([c32isblank])
343 AC_REQUIRE([gl_UCHAR_H])
344 dnl Determine REPLACE_MBSTATE_T, from which GNULIB_defined_mbstate_t is
345 dnl determined. It describes how mbrtoc32 is implemented.
346 AC_REQUIRE([gl_MBSTATE_T_BROKEN])
347 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
348 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
349 gl_UCHAR_MODULE_INDICATOR([c32iscntrl])
350 AC_REQUIRE([gl_UCHAR_H])
351 dnl Determine REPLACE_MBSTATE_T, from which GNULIB_defined_mbstate_t is
352 dnl determined. It describes how mbrtoc32 is implemented.
353 AC_REQUIRE([gl_MBSTATE_T_BROKEN])
354 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
355 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
356 gl_UCHAR_MODULE_INDICATOR([c32isdigit])
357 AC_REQUIRE([gl_UCHAR_H])
358 dnl Determine REPLACE_MBSTATE_T, from which GNULIB_defined_mbstate_t is
359 dnl determined. It describes how mbrtoc32 is implemented.
360 AC_REQUIRE([gl_MBSTATE_T_BROKEN])
361 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
362 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
363 gl_UCHAR_MODULE_INDICATOR([c32isgraph])
364 AC_REQUIRE([gl_UCHAR_H])
365 dnl Determine REPLACE_MBSTATE_T, from which GNULIB_defined_mbstate_t is
366 dnl determined. It describes how mbrtoc32 is implemented.
367 AC_REQUIRE([gl_MBSTATE_T_BROKEN])
368 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
369 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
370 gl_UCHAR_MODULE_INDICATOR([c32islower])
371 AC_REQUIRE([gl_UCHAR_H])
372 dnl Determine REPLACE_MBSTATE_T, from which GNULIB_defined_mbstate_t is
373 dnl determined. It describes how mbrtoc32 is implemented.
374 AC_REQUIRE([gl_MBSTATE_T_BROKEN])
375 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
376 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
377 gl_UCHAR_MODULE_INDICATOR([c32isprint])
378 AC_REQUIRE([gl_UCHAR_H])
379 dnl Determine REPLACE_MBSTATE_T, from which GNULIB_defined_mbstate_t is
380 dnl determined. It describes how mbrtoc32 is implemented.
381 AC_REQUIRE([gl_MBSTATE_T_BROKEN])
382 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
383 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
384 gl_UCHAR_MODULE_INDICATOR([c32ispunct])
385 AC_REQUIRE([gl_UCHAR_H])
386 dnl Determine REPLACE_MBSTATE_T, from which GNULIB_defined_mbstate_t is
387 dnl determined. It describes how mbrtoc32 is implemented.
388 AC_REQUIRE([gl_MBSTATE_T_BROKEN])
389 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
390 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
391 gl_UCHAR_MODULE_INDICATOR([c32isspace])
392 AC_REQUIRE([gl_UCHAR_H])
393 dnl Determine REPLACE_MBSTATE_T, from which GNULIB_defined_mbstate_t is
394 dnl determined. It describes how mbrtoc32 is implemented.
395 AC_REQUIRE([gl_MBSTATE_T_BROKEN])
396 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
397 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
398 gl_UCHAR_MODULE_INDICATOR([c32isupper])
399 AC_REQUIRE([gl_UCHAR_H])
400 dnl Determine REPLACE_MBSTATE_T, from which GNULIB_defined_mbstate_t is
401 dnl determined. It describes how mbrtoc32 is implemented.
402 AC_REQUIRE([gl_MBSTATE_T_BROKEN])
403 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
404 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
405 gl_UCHAR_MODULE_INDICATOR([c32isxdigit])
406 AC_REQUIRE([gl_UCHAR_H])
407 dnl Determine REPLACE_MBSTATE_T, from which GNULIB_defined_mbstate_t is
408 dnl determined. It describes how mbrtoc32 is implemented.
409 AC_REQUIRE([gl_MBSTATE_T_BROKEN])
410 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
411 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
412 gl_UCHAR_MODULE_INDICATOR([c32tolower])
413 AC_REQUIRE([gl_UCHAR_H])
414 dnl Determine REPLACE_MBSTATE_T, from which GNULIB_defined_mbstate_t is
415 dnl determined. It describes how mbrtoc32 is implemented.
416 AC_REQUIRE([gl_MBSTATE_T_BROKEN])
417 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
418 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
419 gl_UCHAR_MODULE_INDICATOR([c32width])
264 gl_FUNC_CALLOC_GNU 420 gl_FUNC_CALLOC_GNU
265 if test $REPLACE_CALLOC_FOR_CALLOC_GNU = 1; then 421 if test $REPLACE_CALLOC_FOR_CALLOC_GNU = 1; then
266 AC_LIBOBJ([calloc]) 422 AC_LIBOBJ([calloc])
@@ -275,6 +431,7 @@ AC_DEFUN([gl_INIT],
275 gl_FUNC_CLOSE 431 gl_FUNC_CLOSE
276 gl_CONDITIONAL([GL_COND_OBJ_CLOSE], [test $REPLACE_CLOSE = 1]) 432 gl_CONDITIONAL([GL_COND_OBJ_CLOSE], [test $REPLACE_CLOSE = 1])
277 gl_UNISTD_MODULE_INDICATOR([close]) 433 gl_UNISTD_MODULE_INDICATOR([close])
434 gl_MODULE_INDICATOR([close])
278 gl_AF_ALG 435 gl_AF_ALG
279 AC_REQUIRE([AC_C_RESTRICT]) 436 AC_REQUIRE([AC_C_RESTRICT])
280 gl_SHA256 437 gl_SHA256
@@ -320,8 +477,11 @@ AC_DEFUN([gl_INIT],
320 gl_FLOAT_H 477 gl_FLOAT_H
321 gl_CONDITIONAL_HEADER([float.h]) 478 gl_CONDITIONAL_HEADER([float.h])
322 AC_PROG_MKDIR_P 479 AC_PROG_MKDIR_P
323 gl_CONDITIONAL([GL_COND_OBJ_FLOAT], [test $REPLACE_FLOAT_LDBL = 1]) 480 gl_CONDITIONAL([GL_COND_OBJ_FLOAT],
481 [test $REPLACE_FLOAT_LDBL = 1 || test $REPLACE_FLOAT_SNAN = 1])
324 gl_CONDITIONAL([GL_COND_OBJ_ITOLD], [test $REPLACE_ITOLD = 1]) 482 gl_CONDITIONAL([GL_COND_OBJ_ITOLD], [test $REPLACE_ITOLD = 1])
483 dnl Prerequisites of lib/float.c.
484 AC_REQUIRE([gl_BIGENDIAN])
325 gl_FUNC_FLOORF 485 gl_FUNC_FLOORF
326 gl_CONDITIONAL([GL_COND_OBJ_FLOORF], 486 gl_CONDITIONAL([GL_COND_OBJ_FLOORF],
327 [test $HAVE_DECL_FLOORF = 0 || test $REPLACE_FLOORF = 1]) 487 [test $HAVE_DECL_FLOORF = 0 || test $REPLACE_FLOORF = 1])
@@ -360,6 +520,8 @@ AC_DEFUN([gl_INIT],
360 gl_PREREQ_FSEEKO 520 gl_PREREQ_FSEEKO
361 ]) 521 ])
362 gl_STDIO_MODULE_INDICATOR([fseeko]) 522 gl_STDIO_MODULE_INDICATOR([fseeko])
523 gl_FUNC_FSETERR
524 gl_CONDITIONAL([GL_COND_OBJ_FSETERR], [test $ac_cv_func___fseterr = no])
363 gl_FUNC_FSTAT 525 gl_FUNC_FSTAT
364 gl_CONDITIONAL([GL_COND_OBJ_FSTAT], [test $REPLACE_FSTAT = 1]) 526 gl_CONDITIONAL([GL_COND_OBJ_FSTAT], [test $REPLACE_FSTAT = 1])
365 AM_COND_IF([GL_COND_OBJ_FSTAT], [ 527 AM_COND_IF([GL_COND_OBJ_FSTAT], [
@@ -371,6 +533,7 @@ AC_DEFUN([gl_INIT],
371 gl_PREREQ_FSTAT 533 gl_PREREQ_FSTAT
372 ]) 534 ])
373 gl_SYS_STAT_MODULE_INDICATOR([fstat]) 535 gl_SYS_STAT_MODULE_INDICATOR([fstat])
536 gl_MODULE_INDICATOR([fstat])
374 gl_FSUSAGE 537 gl_FSUSAGE
375 gl_CONDITIONAL([GL_COND_OBJ_FSUSAGE], [test $gl_cv_fs_space = yes]) 538 gl_CONDITIONAL([GL_COND_OBJ_FSUSAGE], [test $gl_cv_fs_space = yes])
376 AM_COND_IF([GL_COND_OBJ_FSUSAGE], [ 539 AM_COND_IF([GL_COND_OBJ_FSUSAGE], [
@@ -412,6 +575,7 @@ AC_DEFUN([gl_INIT],
412 gl_PREREQ_GETHOSTNAME 575 gl_PREREQ_GETHOSTNAME
413 ]) 576 ])
414 gl_UNISTD_MODULE_INDICATOR([gethostname]) 577 gl_UNISTD_MODULE_INDICATOR([gethostname])
578 gl_MODULE_INDICATOR([gethostname])
415 gl_FUNC_GETLINE 579 gl_FUNC_GETLINE
416 gl_CONDITIONAL([GL_COND_OBJ_GETLINE], [test $REPLACE_GETLINE = 1]) 580 gl_CONDITIONAL([GL_COND_OBJ_GETLINE], [test $REPLACE_GETLINE = 1])
417 AM_COND_IF([GL_COND_OBJ_GETLINE], [ 581 AM_COND_IF([GL_COND_OBJ_GETLINE], [
@@ -441,6 +605,8 @@ AC_DEFUN([gl_INIT],
441 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNISTD_H_GETOPT], [1]) 605 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNISTD_H_GETOPT], [1])
442 ]) 606 ])
443 gl_UNISTD_MODULE_INDICATOR([getopt-posix]) 607 gl_UNISTD_MODULE_INDICATOR([getopt-posix])
608 gl_MUSL_LIBC
609 AC_REQUIRE([AC_CANONICAL_HOST])
444 gl_FUNC_GETPROGNAME 610 gl_FUNC_GETPROGNAME
445 gl_CONDITIONAL([GL_COND_OBJ_GETPROGNAME], 611 gl_CONDITIONAL([GL_COND_OBJ_GETPROGNAME],
446 [test $HAVE_GETPROGNAME = 0 || test $REPLACE_GETPROGNAME = 1]) 612 [test $HAVE_GETPROGNAME = 0 || test $REPLACE_GETPROGNAME = 1])
@@ -451,6 +617,7 @@ AC_DEFUN([gl_INIT],
451 AC_SUBST([LIBINTL]) 617 AC_SUBST([LIBINTL])
452 AC_SUBST([LTLIBINTL]) 618 AC_SUBST([LTLIBINTL])
453 AC_PROG_MKDIR_P 619 AC_PROG_MKDIR_P
620 GNULIB_I18N
454 AC_REQUIRE([gl_FUNC_SETLOCALE_NULL]) 621 AC_REQUIRE([gl_FUNC_SETLOCALE_NULL])
455 HARD_LOCALE_LIB="$SETLOCALE_NULL_LIB" 622 HARD_LOCALE_LIB="$SETLOCALE_NULL_LIB"
456 AC_SUBST([HARD_LOCALE_LIB]) 623 AC_SUBST([HARD_LOCALE_LIB])
@@ -466,6 +633,13 @@ AC_DEFUN([gl_INIT],
466 gl_PREREQ_INET_NTOP 633 gl_PREREQ_INET_NTOP
467 ]) 634 ])
468 gl_ARPA_INET_MODULE_INDICATOR([inet_ntop]) 635 gl_ARPA_INET_MODULE_INDICATOR([inet_ntop])
636 gl_FUNC_INET_PTON
637 gl_CONDITIONAL([GL_COND_OBJ_INET_PTON],
638 [test $HAVE_INET_PTON = 0 || test $REPLACE_INET_PTON = 1])
639 AM_COND_IF([GL_COND_OBJ_INET_PTON], [
640 gl_PREREQ_INET_PTON
641 ])
642 gl_ARPA_INET_MODULE_INDICATOR([inet_pton])
469 gl_INTTYPES_INCOMPLETE 643 gl_INTTYPES_INCOMPLETE
470 gl_INTTYPES_H_REQUIRE_DEFAULTS 644 gl_INTTYPES_H_REQUIRE_DEFAULTS
471 AC_PROG_MKDIR_P 645 AC_PROG_MKDIR_P
@@ -510,11 +684,19 @@ AC_DEFUN([gl_INIT],
510 gl_PREREQ_LOCALECONV 684 gl_PREREQ_LOCALECONV
511 ]) 685 ])
512 gl_LOCALE_MODULE_INDICATOR([localeconv]) 686 gl_LOCALE_MODULE_INDICATOR([localeconv])
687 gl_MODULE_INDICATOR([localeconv])
513 gl_LOCK 688 gl_LOCK
514 gl_MODULE_INDICATOR([lock]) 689 gl_MODULE_INDICATOR([lock])
515 gl_FUNC_LSEEK 690 gl_FUNC_LSEEK
516 gl_CONDITIONAL([GL_COND_OBJ_LSEEK], [test $REPLACE_LSEEK = 1]) 691 gl_CONDITIONAL([GL_COND_OBJ_LSEEK], [test $REPLACE_LSEEK = 1])
517 gl_UNISTD_MODULE_INDICATOR([lseek]) 692 gl_UNISTD_MODULE_INDICATOR([lseek])
693 gl_FUNC_LSTAT
694 gl_CONDITIONAL([GL_COND_OBJ_LSTAT], [test $REPLACE_LSTAT = 1])
695 AM_COND_IF([GL_COND_OBJ_LSTAT], [
696 gl_PREREQ_LSTAT
697 ])
698 gl_SYS_STAT_MODULE_INDICATOR([lstat])
699 gl_MODULE_INDICATOR([lstat])
518 gl_FUNC_MALLOC_GNU 700 gl_FUNC_MALLOC_GNU
519 if test $REPLACE_MALLOC_FOR_MALLOC_GNU = 1; then 701 if test $REPLACE_MALLOC_FOR_MALLOC_GNU = 1; then
520 AC_LIBOBJ([malloc]) 702 AC_LIBOBJ([malloc])
@@ -529,6 +711,20 @@ AC_DEFUN([gl_INIT],
529 gl_MATH_H 711 gl_MATH_H
530 gl_MATH_H_REQUIRE_DEFAULTS 712 gl_MATH_H_REQUIRE_DEFAULTS
531 AC_PROG_MKDIR_P 713 AC_PROG_MKDIR_P
714 gl_MBCHAR
715 gl_MBITER
716 gl_FUNC_MBRTOC32
717 gl_CONDITIONAL([GL_COND_OBJ_MBRTOC32],
718 [test $HAVE_MBRTOC32 = 0 || test $REPLACE_MBRTOC32 = 1])
719 AM_COND_IF([GL_COND_OBJ_MBRTOC32], [
720 if test $REPLACE_MBSTATE_T = 1; then
721 AC_LIBOBJ([lc-charset-dispatch])
722 AC_LIBOBJ([mbtowc-lock])
723 gl_PREREQ_MBTOWC_LOCK
724 fi
725 gl_PREREQ_MBRTOC32
726 ])
727 gl_UCHAR_MODULE_INDICATOR([mbrtoc32])
532 gl_FUNC_MBRTOWC 728 gl_FUNC_MBRTOWC
533 gl_CONDITIONAL([GL_COND_OBJ_MBRTOWC], 729 gl_CONDITIONAL([GL_COND_OBJ_MBRTOWC],
534 [test $HAVE_MBRTOWC = 0 || test $REPLACE_MBRTOWC = 1]) 730 [test $HAVE_MBRTOWC = 0 || test $REPLACE_MBRTOWC = 1])
@@ -548,6 +744,7 @@ AC_DEFUN([gl_INIT],
548 gl_PREREQ_MBSINIT 744 gl_PREREQ_MBSINIT
549 ]) 745 ])
550 gl_WCHAR_MODULE_INDICATOR([mbsinit]) 746 gl_WCHAR_MODULE_INDICATOR([mbsinit])
747 gl_STRING_MODULE_INDICATOR([mbsnlen])
551 AC_REQUIRE([AC_TYPE_MBSTATE_T]) 748 AC_REQUIRE([AC_TYPE_MBSTATE_T])
552 gl_MBSTATE_T_BROKEN 749 gl_MBSTATE_T_BROKEN
553 gl_MUSL_LIBC 750 gl_MUSL_LIBC
@@ -578,10 +775,7 @@ AC_DEFUN([gl_INIT],
578 gl_PREREQ_MKTIME 775 gl_PREREQ_MKTIME
579 fi 776 fi
580 gl_MOUNTLIST 777 gl_MOUNTLIST
581 gl_CONDITIONAL([GL_COND_OBJ_MOUNTLIST], [test $gl_cv_list_mounted_fs = yes]) 778 gl_PREREQ_MOUNTLIST_EXTRA
582 AM_COND_IF([GL_COND_OBJ_MOUNTLIST], [
583 gl_PREREQ_MOUNTLIST_EXTRA
584 ])
585 AC_REQUIRE([gl_MSVC_INVAL]) 779 AC_REQUIRE([gl_MSVC_INVAL])
586 gl_CONDITIONAL([GL_COND_OBJ_MSVC_INVAL], 780 gl_CONDITIONAL([GL_COND_OBJ_MSVC_INVAL],
587 [test $HAVE_MSVC_INVALID_PARAMETER_HANDLER = 1]) 781 [test $HAVE_MSVC_INVALID_PARAMETER_HANDLER = 1])
@@ -605,6 +799,7 @@ AC_DEFUN([gl_INIT],
605 gl_PREREQ_NL_LANGINFO_LOCK 799 gl_PREREQ_NL_LANGINFO_LOCK
606 fi 800 fi
607 gl_LANGINFO_MODULE_INDICATOR([nl_langinfo]) 801 gl_LANGINFO_MODULE_INDICATOR([nl_langinfo])
802 gl_ONCE
608 gl_FUNC_OPEN 803 gl_FUNC_OPEN
609 gl_CONDITIONAL([GL_COND_OBJ_OPEN], [test $REPLACE_OPEN = 1]) 804 gl_CONDITIONAL([GL_COND_OBJ_OPEN], [test $REPLACE_OPEN = 1])
610 AM_COND_IF([GL_COND_OBJ_OPEN], [ 805 AM_COND_IF([GL_COND_OBJ_OPEN], [
@@ -612,15 +807,17 @@ AC_DEFUN([gl_INIT],
612 ]) 807 ])
613 gl_FCNTL_MODULE_INDICATOR([open]) 808 gl_FCNTL_MODULE_INDICATOR([open])
614 gl_PATHMAX 809 gl_PATHMAX
615 gl_FUNC_REALLOC_GNU 810 gl_PTHREAD_H
616 if test $REPLACE_REALLOC_FOR_REALLOC_GNU = 1; then 811 gl_PTHREAD_H_REQUIRE_DEFAULTS
617 AC_LIBOBJ([realloc]) 812 AC_PROG_MKDIR_P
618 fi 813 gl_PTHREAD_ONCE
619 gl_STDLIB_MODULE_INDICATOR([realloc-gnu]) 814 gl_CONDITIONAL([GL_COND_OBJ_PTHREAD_ONCE],
815 [test $HAVE_PTHREAD_ONCE = 0 || test $REPLACE_PTHREAD_ONCE = 1])
816 gl_PTHREAD_MODULE_INDICATOR([pthread-once])
620 gl_FUNC_REALLOC_POSIX 817 gl_FUNC_REALLOC_POSIX
621 if test $REPLACE_REALLOC_FOR_REALLOC_POSIX = 1; then 818 gl_FUNC_REALLOC_0_NONNULL
622 AC_LIBOBJ([realloc]) 819 gl_CONDITIONAL([GL_COND_OBJ_REALLOC_POSIX],
623 fi 820 [test $REPLACE_REALLOC_FOR_REALLOC_POSIX != 0])
624 gl_STDLIB_MODULE_INDICATOR([realloc-posix]) 821 gl_STDLIB_MODULE_INDICATOR([realloc-posix])
625 gl_FUNC_REALLOCARRAY 822 gl_FUNC_REALLOCARRAY
626 gl_CONDITIONAL([GL_COND_OBJ_REALLOCARRAY], 823 gl_CONDITIONAL([GL_COND_OBJ_REALLOCARRAY],
@@ -635,6 +832,9 @@ AC_DEFUN([gl_INIT],
635 AM_COND_IF([GL_COND_OBJ_REGEX], [ 832 AM_COND_IF([GL_COND_OBJ_REGEX], [
636 gl_PREREQ_REGEX 833 gl_PREREQ_REGEX
637 ]) 834 ])
835 gl_SCHED_H
836 gl_SCHED_H_REQUIRE_DEFAULTS
837 AC_PROG_MKDIR_P
638 gl_SERVENT 838 gl_SERVENT
639 gl_FUNC_SETENV 839 gl_FUNC_SETENV
640 gl_CONDITIONAL([GL_COND_OBJ_SETENV], 840 gl_CONDITIONAL([GL_COND_OBJ_SETENV],
@@ -666,15 +866,10 @@ AC_DEFUN([gl_INIT],
666 gl_PREREQ_STAT 866 gl_PREREQ_STAT
667 ]) 867 ])
668 gl_SYS_STAT_MODULE_INDICATOR([stat]) 868 gl_SYS_STAT_MODULE_INDICATOR([stat])
869 gl_MODULE_INDICATOR([stat])
669 gl_STAT_TIME 870 gl_STAT_TIME
670 gl_STAT_BIRTHTIME 871 gl_STAT_BIRTHTIME
671 gl_C_BOOL 872 gl_STDCKDINT_H
672 AC_CHECK_HEADERS_ONCE([stdckdint.h])
673 if test $ac_cv_header_stdckdint_h = yes; then
674 GL_GENERATE_STDCKDINT_H=false
675 else
676 GL_GENERATE_STDCKDINT_H=true
677 fi
678 gl_CONDITIONAL_HEADER([stdckdint.h]) 873 gl_CONDITIONAL_HEADER([stdckdint.h])
679 AC_PROG_MKDIR_P 874 AC_PROG_MKDIR_P
680 gl_STDDEF_H 875 gl_STDDEF_H
@@ -689,6 +884,19 @@ AC_DEFUN([gl_INIT],
689 gl_STDIO_H 884 gl_STDIO_H
690 gl_STDIO_H_REQUIRE_DEFAULTS 885 gl_STDIO_H_REQUIRE_DEFAULTS
691 AC_PROG_MKDIR_P 886 AC_PROG_MKDIR_P
887 USES_MSVCRT=0
888 case "$host_os" in
889 mingw* | windows*)
890 AC_EGREP_CPP([Special], [
891 #ifndef _UCRT
892 Special
893 #endif
894 ],
895 [USES_MSVCRT=1])
896 ;;
897 esac
898 gl_CONDITIONAL([GL_COND_OBJ_STDIO_CONSOLESAFE], [test $USES_MSVCRT = 1])
899 AC_CHECK_FUNCS([vasprintf])
692 gl_CONDITIONAL([GL_COND_OBJ_STDIO_READ], [test $REPLACE_STDIO_READ_FUNCS = 1]) 900 gl_CONDITIONAL([GL_COND_OBJ_STDIO_READ], [test $REPLACE_STDIO_READ_FUNCS = 1])
693 gl_CONDITIONAL([GL_COND_OBJ_STDIO_WRITE], [test $REPLACE_STDIO_WRITE_FUNCS = 1]) 901 gl_CONDITIONAL([GL_COND_OBJ_STDIO_WRITE], [test $REPLACE_STDIO_WRITE_FUNCS = 1])
694 dnl No need to create extra modules for these functions. Everyone who uses 902 dnl No need to create extra modules for these functions. Everyone who uses
@@ -717,15 +925,13 @@ AC_DEFUN([gl_INIT],
717 gl_STDLIB_H 925 gl_STDLIB_H
718 gl_STDLIB_H_REQUIRE_DEFAULTS 926 gl_STDLIB_H_REQUIRE_DEFAULTS
719 AC_PROG_MKDIR_P 927 AC_PROG_MKDIR_P
720 gl_STRCASE 928 gl_FUNC_STRCASECMP
721 gl_CONDITIONAL([GL_COND_OBJ_STRCASECMP], [test $HAVE_STRCASECMP = 0]) 929 gl_CONDITIONAL([GL_COND_OBJ_STRCASECMP],
930 [test $HAVE_STRCASECMP = 0 || test $REPLACE_STRCASECMP = 1])
722 AM_COND_IF([GL_COND_OBJ_STRCASECMP], [ 931 AM_COND_IF([GL_COND_OBJ_STRCASECMP], [
723 gl_PREREQ_STRCASECMP 932 gl_PREREQ_STRCASECMP
724 ]) 933 ])
725 gl_CONDITIONAL([GL_COND_OBJ_STRNCASECMP], [test $HAVE_STRNCASECMP = 0]) 934 gl_STRINGS_MODULE_INDICATOR([strcasecmp])
726 AM_COND_IF([GL_COND_OBJ_STRNCASECMP], [
727 gl_PREREQ_STRNCASECMP
728 ])
729 gl_FUNC_STRCASESTR 935 gl_FUNC_STRCASESTR
730 if test $HAVE_STRCASESTR = 0 || test $REPLACE_STRCASESTR = 1; then 936 if test $HAVE_STRCASESTR = 0 || test $REPLACE_STRCASESTR = 1; then
731 AC_LIBOBJ([strcasestr]) 937 AC_LIBOBJ([strcasestr])
@@ -754,6 +960,19 @@ AC_DEFUN([gl_INIT],
754 gl_STRINGS_H 960 gl_STRINGS_H
755 gl_STRINGS_H_REQUIRE_DEFAULTS 961 gl_STRINGS_H_REQUIRE_DEFAULTS
756 AC_PROG_MKDIR_P 962 AC_PROG_MKDIR_P
963 gl_FUNC_STRNCASECMP
964 gl_CONDITIONAL([GL_COND_OBJ_STRNCASECMP],
965 [test $HAVE_STRNCASECMP = 0 || test $REPLACE_STRNCASECMP = 1])
966 AM_COND_IF([GL_COND_OBJ_STRNCASECMP], [
967 gl_PREREQ_STRNCASECMP
968 ])
969 gl_STRINGS_MODULE_INDICATOR([strncasecmp])
970 gl_FUNC_STRNCPY
971 gl_CONDITIONAL([GL_COND_OBJ_STRNCPY], [test $REPLACE_STRNCPY = 1])
972 AM_COND_IF([GL_COND_OBJ_STRNCPY], [
973 gl_PREREQ_STRNCPY
974 ])
975 gl_STRING_MODULE_INDICATOR([strncpy])
757 gl_FUNC_STRSEP 976 gl_FUNC_STRSEP
758 gl_CONDITIONAL([GL_COND_OBJ_STRSEP], [test $HAVE_STRSEP = 0]) 977 gl_CONDITIONAL([GL_COND_OBJ_STRSEP], [test $HAVE_STRSEP = 0])
759 AM_COND_IF([GL_COND_OBJ_STRSEP], [ 978 AM_COND_IF([GL_COND_OBJ_STRSEP], [
@@ -795,9 +1014,55 @@ AC_DEFUN([gl_INIT],
795 gl_PREREQ_TIMEGM 1014 gl_PREREQ_TIMEGM
796 ]) 1015 ])
797 gl_TIME_MODULE_INDICATOR([timegm]) 1016 gl_TIME_MODULE_INDICATOR([timegm])
1017 gl_UCHAR_H
1018 gl_UCHAR_H_REQUIRE_DEFAULTS
1019 AC_PROG_MKDIR_P
1020 gl_LIBUNISTRING_LIBHEADER([1.2], [unicase.h])
1021 gl_UNICASE_H
1022 gl_UNICASE_H_REQUIRE_DEFAULTS
1023 AC_PROG_MKDIR_P
1024 gl_LIBUNISTRING_MODULE([1.3], [unicase/tolower])
1025 gl_LIBUNISTRING_LIBHEADER([1.3], [unictype.h])
1026 gl_UNICTYPE_H
1027 gl_UNICTYPE_H_REQUIRE_DEFAULTS
1028 AC_PROG_MKDIR_P
1029 AC_REQUIRE([AC_C_INLINE])
1030 gl_LIBUNISTRING_MODULE([1.3], [unictype/ctype-alnum])
1031 AC_REQUIRE([AC_C_INLINE])
1032 gl_LIBUNISTRING_MODULE([1.3], [unictype/ctype-alpha])
1033 AC_REQUIRE([AC_C_INLINE])
1034 gl_LIBUNISTRING_MODULE([0.9.8], [unictype/ctype-blank])
1035 AC_REQUIRE([AC_C_INLINE])
1036 gl_LIBUNISTRING_MODULE([0.9.8], [unictype/ctype-cntrl])
1037 AC_REQUIRE([AC_C_INLINE])
1038 gl_LIBUNISTRING_MODULE([0.9.8], [unictype/ctype-digit])
1039 AC_REQUIRE([AC_C_INLINE])
1040 gl_LIBUNISTRING_MODULE([1.3], [unictype/ctype-graph])
1041 AC_REQUIRE([AC_C_INLINE])
1042 gl_LIBUNISTRING_MODULE([1.3], [unictype/ctype-lower])
1043 AC_REQUIRE([AC_C_INLINE])
1044 gl_LIBUNISTRING_MODULE([1.3], [unictype/ctype-print])
1045 AC_REQUIRE([AC_C_INLINE])
1046 gl_LIBUNISTRING_MODULE([1.3], [unictype/ctype-punct])
1047 AC_REQUIRE([AC_C_INLINE])
1048 gl_LIBUNISTRING_MODULE([0.9.8], [unictype/ctype-space])
1049 AC_REQUIRE([AC_C_INLINE])
1050 gl_LIBUNISTRING_MODULE([1.3], [unictype/ctype-upper])
1051 AC_REQUIRE([AC_C_INLINE])
1052 gl_LIBUNISTRING_MODULE([0.9.8], [unictype/ctype-xdigit])
1053 gl_LIBUNISTRING_LIBHEADER([1.2], [uninorm.h])
1054 gl_UNINORM_H
1055 gl_UNINORM_H_REQUIRE_DEFAULTS
1056 AC_PROG_MKDIR_P
798 gl_UNISTD_H 1057 gl_UNISTD_H
799 gl_UNISTD_H_REQUIRE_DEFAULTS 1058 gl_UNISTD_H_REQUIRE_DEFAULTS
800 AC_PROG_MKDIR_P 1059 AC_PROG_MKDIR_P
1060 gl_LIBUNISTRING_LIBHEADER([0.9.11], [unitypes.h])
1061 AC_PROG_MKDIR_P
1062 gl_UNITYPES_H
1063 gl_LIBUNISTRING_LIBHEADER([0.9.11], [uniwidth.h])
1064 AC_PROG_MKDIR_P
1065 gl_LIBUNISTRING_MODULE([1.3], [uniwidth/width])
801 gl_FUNC_GLIBC_UNLOCKED_IO 1066 gl_FUNC_GLIBC_UNLOCKED_IO
802 gl_FUNC_UNSETENV 1067 gl_FUNC_UNSETENV
803 gl_CONDITIONAL([GL_COND_OBJ_UNSETENV], 1068 gl_CONDITIONAL([GL_COND_OBJ_UNSETENV],
@@ -816,6 +1081,7 @@ AC_DEFUN([gl_INIT],
816 AM_][XGETTEXT_OPTION([--flag=vasprintf:2:c-format])]) 1081 AM_][XGETTEXT_OPTION([--flag=vasprintf:2:c-format])])
817 gl_FUNC_VSNPRINTF 1082 gl_FUNC_VSNPRINTF
818 gl_STDIO_MODULE_INDICATOR([vsnprintf]) 1083 gl_STDIO_MODULE_INDICATOR([vsnprintf])
1084 gl_STDIO_MODULE_INDICATOR([vsnzprintf])
819 gl_WCHAR_H 1085 gl_WCHAR_H
820 gl_WCHAR_H_REQUIRE_DEFAULTS 1086 gl_WCHAR_H_REQUIRE_DEFAULTS
821 AC_PROG_MKDIR_P 1087 AC_PROG_MKDIR_P
@@ -832,6 +1098,13 @@ AC_DEFUN([gl_INIT],
832 gl_WCTYPE_H 1098 gl_WCTYPE_H
833 gl_WCTYPE_H_REQUIRE_DEFAULTS 1099 gl_WCTYPE_H_REQUIRE_DEFAULTS
834 AC_PROG_MKDIR_P 1100 AC_PROG_MKDIR_P
1101 gl_FUNC_WCWIDTH
1102 gl_CONDITIONAL([GL_COND_OBJ_WCWIDTH],
1103 [test $HAVE_WCWIDTH = 0 || test $REPLACE_WCWIDTH = 1])
1104 AM_COND_IF([GL_COND_OBJ_WCWIDTH], [
1105 gl_PREREQ_WCWIDTH
1106 ])
1107 gl_WCHAR_MODULE_INDICATOR([wcwidth])
835 AC_REQUIRE([AC_CANONICAL_HOST]) 1108 AC_REQUIRE([AC_CANONICAL_HOST])
836 gl_CONDITIONAL([GL_COND_OBJ_WINDOWS_MUTEX], 1109 gl_CONDITIONAL([GL_COND_OBJ_WINDOWS_MUTEX],
837 [case "$host_os" in mingw* | windows*) true;; *) false;; esac]) 1110 [case "$host_os" in mingw* | windows*) true;; *) false;; esac])
@@ -871,27 +1144,35 @@ AC_DEFUN([gl_INIT],
871 gl_libobjs= 1144 gl_libobjs=
872 gl_ltlibobjs= 1145 gl_ltlibobjs=
873 gl_libobjdeps= 1146 gl_libobjdeps=
1147 gl_libgnu_libobjs=
1148 gl_libgnu_ltlibobjs=
1149 gl_libgnu_libobjdeps=
874 if test -n "$gl_LIBOBJS"; then 1150 if test -n "$gl_LIBOBJS"; then
875 # Remove the extension. 1151 # Remove the extension.
876changequote(,)dnl 1152changequote(,)dnl
877 sed_drop_objext='s/\.o$//;s/\.obj$//' 1153 sed_drop_objext='s/\.o$//;s/\.obj$//'
878 sed_dirname1='s,//*,/,g' 1154 sed_dirname1='s,//*,/,g'
879 sed_dirname2='s,\(.\)/$,\1,' 1155 sed_dirname2='s,\(.\)/$,\1,'
880 sed_dirname3='s,^[^/]*$,.,' 1156 sed_dirname3='s,[^/]*$,,'
881 sed_dirname4='s,\(.\)/[^/]*$,\1,'
882 sed_basename1='s,.*/,,' 1157 sed_basename1='s,.*/,,'
883changequote([, ])dnl 1158changequote([, ])dnl
884 for i in `for i in $gl_LIBOBJS; do echo "$i"; done | sed -e "$sed_drop_objext" | sort | uniq`; do 1159 for i in `for i in $gl_LIBOBJS; do echo "$i"; done | sed -e "$sed_drop_objext" | sort | uniq`; do
885 gl_libobjs="$gl_libobjs $i.$ac_objext" 1160 gl_libobjs="$gl_libobjs $i.$ac_objext"
886 gl_ltlibobjs="$gl_ltlibobjs $i.lo" 1161 gl_ltlibobjs="$gl_ltlibobjs $i.lo"
887 i_dir=`echo "$i" | sed -e "$sed_dirname1" -e "$sed_dirname2" -e "$sed_dirname3" -e "$sed_dirname4"` 1162 i_dir=`echo "$i" | sed -e "$sed_dirname1" -e "$sed_dirname2" -e "$sed_dirname3"`
888 i_base=`echo "$i" | sed -e "$sed_basename1"` 1163 i_base=`echo "$i" | sed -e "$sed_basename1"`
889 gl_libobjdeps="$gl_libobjdeps $i_dir/\$(DEPDIR)/$i_base.Po" 1164 gl_libgnu_libobjs="$gl_libgnu_libobjs $i_dir""libgnu_a-$i_base.$ac_objext"
1165 gl_libgnu_ltlibobjs="$gl_libgnu_ltlibobjs $i_dir""libgnu_la-$i_base.lo"
1166 gl_libobjdeps="$gl_libobjdeps $i_dir\$(DEPDIR)/$i_base.Po"
1167 gl_libgnu_libobjdeps="$gl_libgnu_libobjdeps $i_dir\$(DEPDIR)/libgnu_a-$i_base.Po"
890 done 1168 done
891 fi 1169 fi
892 AC_SUBST([gl_LIBOBJS], [$gl_libobjs]) 1170 AC_SUBST([gl_LIBOBJS], [$gl_libobjs])
893 AC_SUBST([gl_LTLIBOBJS], [$gl_ltlibobjs]) 1171 AC_SUBST([gl_LTLIBOBJS], [$gl_ltlibobjs])
894 AC_SUBST([gl_LIBOBJDEPS], [$gl_libobjdeps]) 1172 AC_SUBST([gl_LIBOBJDEPS], [$gl_libobjdeps])
1173 AC_SUBST([gl_libgnu_LIBOBJS], [$gl_libgnu_libobjs])
1174 AC_SUBST([gl_libgnu_LTLIBOBJS], [$gl_libgnu_ltlibobjs])
1175 AC_SUBST([gl_libgnu_LIBOBJDEPS], [$gl_libgnu_libobjdeps])
895 ]) 1176 ])
896 gltests_libdeps= 1177 gltests_libdeps=
897 gltests_ltlibdeps= 1178 gltests_ltlibdeps=
@@ -934,27 +1215,35 @@ changequote([, ])dnl
934 gltests_libobjs= 1215 gltests_libobjs=
935 gltests_ltlibobjs= 1216 gltests_ltlibobjs=
936 gltests_libobjdeps= 1217 gltests_libobjdeps=
1218 gltests_libgnu_libobjs=
1219 gltests_libgnu_ltlibobjs=
1220 gltests_libgnu_libobjdeps=
937 if test -n "$gltests_LIBOBJS"; then 1221 if test -n "$gltests_LIBOBJS"; then
938 # Remove the extension. 1222 # Remove the extension.
939changequote(,)dnl 1223changequote(,)dnl
940 sed_drop_objext='s/\.o$//;s/\.obj$//' 1224 sed_drop_objext='s/\.o$//;s/\.obj$//'
941 sed_dirname1='s,//*,/,g' 1225 sed_dirname1='s,//*,/,g'
942 sed_dirname2='s,\(.\)/$,\1,' 1226 sed_dirname2='s,\(.\)/$,\1,'
943 sed_dirname3='s,^[^/]*$,.,' 1227 sed_dirname3='s,[^/]*$,,'
944 sed_dirname4='s,\(.\)/[^/]*$,\1,'
945 sed_basename1='s,.*/,,' 1228 sed_basename1='s,.*/,,'
946changequote([, ])dnl 1229changequote([, ])dnl
947 for i in `for i in $gltests_LIBOBJS; do echo "$i"; done | sed -e "$sed_drop_objext" | sort | uniq`; do 1230 for i in `for i in $gltests_LIBOBJS; do echo "$i"; done | sed -e "$sed_drop_objext" | sort | uniq`; do
948 gltests_libobjs="$gltests_libobjs $i.$ac_objext" 1231 gltests_libobjs="$gltests_libobjs $i.$ac_objext"
949 gltests_ltlibobjs="$gltests_ltlibobjs $i.lo" 1232 gltests_ltlibobjs="$gltests_ltlibobjs $i.lo"
950 i_dir=`echo "$i" | sed -e "$sed_dirname1" -e "$sed_dirname2" -e "$sed_dirname3" -e "$sed_dirname4"` 1233 i_dir=`echo "$i" | sed -e "$sed_dirname1" -e "$sed_dirname2" -e "$sed_dirname3"`
951 i_base=`echo "$i" | sed -e "$sed_basename1"` 1234 i_base=`echo "$i" | sed -e "$sed_basename1"`
952 gltests_libobjdeps="$gltests_libobjdeps $i_dir/\$(DEPDIR)/$i_base.Po" 1235 gltests_libgnu_libobjs="$gltests_libgnu_libobjs $i_dir""libgnu_a-$i_base.$ac_objext"
1236 gltests_libgnu_ltlibobjs="$gltests_libgnu_ltlibobjs $i_dir""libgnu_la-$i_base.lo"
1237 gltests_libobjdeps="$gltests_libobjdeps $i_dir\$(DEPDIR)/$i_base.Po"
1238 gltests_libgnu_libobjdeps="$gltests_libgnu_libobjdeps $i_dir\$(DEPDIR)/libgnu_a-$i_base.Po"
953 done 1239 done
954 fi 1240 fi
955 AC_SUBST([gltests_LIBOBJS], [$gltests_libobjs]) 1241 AC_SUBST([gltests_LIBOBJS], [$gltests_libobjs])
956 AC_SUBST([gltests_LTLIBOBJS], [$gltests_ltlibobjs]) 1242 AC_SUBST([gltests_LTLIBOBJS], [$gltests_ltlibobjs])
957 AC_SUBST([gltests_LIBOBJDEPS], [$gltests_libobjdeps]) 1243 AC_SUBST([gltests_LIBOBJDEPS], [$gltests_libobjdeps])
1244 AC_SUBST([gltests_libgnu_LIBOBJS], [$gltests_libgnu_libobjs])
1245 AC_SUBST([gltests_libgnu_LTLIBOBJS], [$gltests_libgnu_ltlibobjs])
1246 AC_SUBST([gltests_libgnu_LIBOBJDEPS], [$gltests_libgnu_libobjdeps])
958 ]) 1247 ])
959 AC_REQUIRE([gl_CC_GNULIB_WARNINGS]) 1248 AC_REQUIRE([gl_CC_GNULIB_WARNINGS])
960 LIBGNU_LIBDEPS="$gl_libdeps" 1249 LIBGNU_LIBDEPS="$gl_libdeps"
@@ -1025,6 +1314,7 @@ AC_DEFUN([gl_FILE_LIST], [
1025 lib/af_alg.h 1314 lib/af_alg.h
1026 lib/alloca.in.h 1315 lib/alloca.in.h
1027 lib/arg-nonnull.h 1316 lib/arg-nonnull.h
1317 lib/arpa_inet.c
1028 lib/arpa_inet.in.h 1318 lib/arpa_inet.in.h
1029 lib/asnprintf.c 1319 lib/asnprintf.c
1030 lib/asprintf.c 1320 lib/asprintf.c
@@ -1036,8 +1326,27 @@ AC_DEFUN([gl_FILE_LIST], [
1036 lib/basename-lgpl.h 1326 lib/basename-lgpl.h
1037 lib/basename.c 1327 lib/basename.c
1038 lib/btowc.c 1328 lib/btowc.c
1329 lib/byteswap.c
1039 lib/byteswap.in.h 1330 lib/byteswap.in.h
1040 lib/c++defs.h 1331 lib/c++defs.h
1332 lib/c-ctype.c
1333 lib/c-ctype.h
1334 lib/c32is-impl.h
1335 lib/c32isalnum.c
1336 lib/c32isalpha.c
1337 lib/c32isblank.c
1338 lib/c32iscntrl.c
1339 lib/c32isdigit.c
1340 lib/c32isgraph.c
1341 lib/c32islower.c
1342 lib/c32isprint.c
1343 lib/c32ispunct.c
1344 lib/c32isspace.c
1345 lib/c32isupper.c
1346 lib/c32isxdigit.c
1347 lib/c32to-impl.h
1348 lib/c32tolower.c
1349 lib/c32width.c
1041 lib/calloc.c 1350 lib/calloc.c
1042 lib/cdefs.h 1351 lib/cdefs.h
1043 lib/cloexec.c 1352 lib/cloexec.c
@@ -1071,6 +1380,8 @@ AC_DEFUN([gl_FILE_LIST], [
1071 lib/free.c 1380 lib/free.c
1072 lib/fseek.c 1381 lib/fseek.c
1073 lib/fseeko.c 1382 lib/fseeko.c
1383 lib/fseterr.c
1384 lib/fseterr.h
1074 lib/fstat.c 1385 lib/fstat.c
1075 lib/fsusage.c 1386 lib/fsusage.c
1076 lib/fsusage.h 1387 lib/fsusage.h
@@ -1098,6 +1409,8 @@ AC_DEFUN([gl_FILE_LIST], [
1098 lib/gl_openssl.h 1409 lib/gl_openssl.h
1099 lib/glthread/lock.c 1410 lib/glthread/lock.c
1100 lib/glthread/lock.h 1411 lib/glthread/lock.h
1412 lib/glthread/once.c
1413 lib/glthread/once.h
1101 lib/glthread/threadlib.c 1414 lib/glthread/threadlib.c
1102 lib/hard-locale.c 1415 lib/hard-locale.c
1103 lib/hard-locale.h 1416 lib/hard-locale.h
@@ -1107,6 +1420,7 @@ AC_DEFUN([gl_FILE_LIST], [
1107 lib/idpriv.h 1420 lib/idpriv.h
1108 lib/idx.h 1421 lib/idx.h
1109 lib/inet_ntop.c 1422 lib/inet_ntop.c
1423 lib/inet_pton.c
1110 lib/intprops-internal.h 1424 lib/intprops-internal.h
1111 lib/intprops.h 1425 lib/intprops.h
1112 lib/inttypes.in.h 1426 lib/inttypes.in.h
@@ -1127,6 +1441,7 @@ AC_DEFUN([gl_FILE_LIST], [
1127 lib/locale.in.h 1441 lib/locale.in.h
1128 lib/localeconv.c 1442 lib/localeconv.c
1129 lib/lseek.c 1443 lib/lseek.c
1444 lib/lstat.c
1130 lib/malloc.c 1445 lib/malloc.c
1131 lib/malloc/dynarray-skeleton.c 1446 lib/malloc/dynarray-skeleton.c
1132 lib/malloc/dynarray.h 1447 lib/malloc/dynarray.h
@@ -1139,10 +1454,16 @@ AC_DEFUN([gl_FILE_LIST], [
1139 lib/malloca.h 1454 lib/malloca.h
1140 lib/math.c 1455 lib/math.c
1141 lib/math.in.h 1456 lib/math.in.h
1457 lib/mbchar.c
1458 lib/mbchar.h
1459 lib/mbiterf.c
1460 lib/mbiterf.h
1461 lib/mbrtoc32.c
1142 lib/mbrtowc-impl-utf8.h 1462 lib/mbrtowc-impl-utf8.h
1143 lib/mbrtowc-impl.h 1463 lib/mbrtowc-impl.h
1144 lib/mbrtowc.c 1464 lib/mbrtowc.c
1145 lib/mbsinit.c 1465 lib/mbsinit.c
1466 lib/mbsnlen.c
1146 lib/mbszero.c 1467 lib/mbszero.c
1147 lib/mbtowc-impl.h 1468 lib/mbtowc-impl.h
1148 lib/mbtowc-lock.c 1469 lib/mbtowc-lock.c
@@ -1169,6 +1490,8 @@ AC_DEFUN([gl_FILE_LIST], [
1169 lib/printf-args.h 1490 lib/printf-args.h
1170 lib/printf-parse.c 1491 lib/printf-parse.c
1171 lib/printf-parse.h 1492 lib/printf-parse.h
1493 lib/pthread-once.c
1494 lib/pthread.in.h
1172 lib/realloc.c 1495 lib/realloc.c
1173 lib/reallocarray.c 1496 lib/reallocarray.c
1174 lib/regcomp.c 1497 lib/regcomp.c
@@ -1177,6 +1500,7 @@ AC_DEFUN([gl_FILE_LIST], [
1177 lib/regex_internal.c 1500 lib/regex_internal.c
1178 lib/regex_internal.h 1501 lib/regex_internal.h
1179 lib/regexec.c 1502 lib/regexec.c
1503 lib/sched.in.h
1180 lib/setenv.c 1504 lib/setenv.c
1181 lib/setlocale-lock.c 1505 lib/setlocale-lock.c
1182 lib/setlocale_null-unlocked.c 1506 lib/setlocale_null-unlocked.c
@@ -1197,10 +1521,12 @@ AC_DEFUN([gl_FILE_LIST], [
1197 lib/stdckdint.in.h 1521 lib/stdckdint.in.h
1198 lib/stddef.in.h 1522 lib/stddef.in.h
1199 lib/stdint.in.h 1523 lib/stdint.in.h
1524 lib/stdio-consolesafe.c
1200 lib/stdio-impl.h 1525 lib/stdio-impl.h
1201 lib/stdio-read.c 1526 lib/stdio-read.c
1202 lib/stdio-write.c 1527 lib/stdio-write.c
1203 lib/stdio.in.h 1528 lib/stdio.in.h
1529 lib/stdlib.c
1204 lib/stdlib.in.h 1530 lib/stdlib.in.h
1205 lib/str-two-way.h 1531 lib/str-two-way.h
1206 lib/strcasecmp.c 1532 lib/strcasecmp.c
@@ -1213,6 +1539,7 @@ AC_DEFUN([gl_FILE_LIST], [
1213 lib/strings.in.h 1539 lib/strings.in.h
1214 lib/stripslash.c 1540 lib/stripslash.c
1215 lib/strncasecmp.c 1541 lib/strncasecmp.c
1542 lib/strncpy.c
1216 lib/strsep.c 1543 lib/strsep.c
1217 lib/strstr.c 1544 lib/strstr.c
1218 lib/sys-limits.h 1545 lib/sys-limits.h
@@ -1224,8 +1551,46 @@ AC_DEFUN([gl_FILE_LIST], [
1224 lib/time.in.h 1551 lib/time.in.h
1225 lib/time_r.c 1552 lib/time_r.c
1226 lib/timegm.c 1553 lib/timegm.c
1554 lib/uchar.in.h
1555 lib/unicase.in.h
1556 lib/unicase/simple-mapping.h
1557 lib/unicase/tolower.c
1558 lib/unicase/tolower.h
1559 lib/unictype.in.h
1560 lib/unictype/bitmap.h
1561 lib/unictype/ctype_alnum.c
1562 lib/unictype/ctype_alnum.h
1563 lib/unictype/ctype_alpha.c
1564 lib/unictype/ctype_alpha.h
1565 lib/unictype/ctype_blank.c
1566 lib/unictype/ctype_blank.h
1567 lib/unictype/ctype_cntrl.c
1568 lib/unictype/ctype_cntrl.h
1569 lib/unictype/ctype_digit.c
1570 lib/unictype/ctype_digit.h
1571 lib/unictype/ctype_graph.c
1572 lib/unictype/ctype_graph.h
1573 lib/unictype/ctype_lower.c
1574 lib/unictype/ctype_lower.h
1575 lib/unictype/ctype_print.c
1576 lib/unictype/ctype_print.h
1577 lib/unictype/ctype_punct.c
1578 lib/unictype/ctype_punct.h
1579 lib/unictype/ctype_space.c
1580 lib/unictype/ctype_space.h
1581 lib/unictype/ctype_upper.c
1582 lib/unictype/ctype_upper.h
1583 lib/unictype/ctype_xdigit.c
1584 lib/unictype/ctype_xdigit.h
1585 lib/uninorm.in.h
1227 lib/unistd.c 1586 lib/unistd.c
1228 lib/unistd.in.h 1587 lib/unistd.in.h
1588 lib/unitypes.in.h
1589 lib/uniwidth.in.h
1590 lib/uniwidth/cjk.h
1591 lib/uniwidth/width.c
1592 lib/uniwidth/width0.h
1593 lib/uniwidth/width2.h
1229 lib/unlocked-io.h 1594 lib/unlocked-io.h
1230 lib/unsetenv.c 1595 lib/unsetenv.c
1231 lib/vasnprintf.c 1596 lib/vasnprintf.c
@@ -1233,6 +1598,7 @@ AC_DEFUN([gl_FILE_LIST], [
1233 lib/vasprintf.c 1598 lib/vasprintf.c
1234 lib/verify.h 1599 lib/verify.h
1235 lib/vsnprintf.c 1600 lib/vsnprintf.c
1601 lib/vsnzprintf.c
1236 lib/w32sock.h 1602 lib/w32sock.h
1237 lib/warn-on-use.h 1603 lib/warn-on-use.h
1238 lib/wchar.in.h 1604 lib/wchar.in.h
@@ -1241,6 +1607,7 @@ AC_DEFUN([gl_FILE_LIST], [
1241 lib/wctype-impl.h 1607 lib/wctype-impl.h
1242 lib/wctype.c 1608 lib/wctype.c
1243 lib/wctype.in.h 1609 lib/wctype.in.h
1610 lib/wcwidth.c
1244 lib/windows-initguard.h 1611 lib/windows-initguard.h
1245 lib/windows-mutex.c 1612 lib/windows-mutex.c
1246 lib/windows-mutex.h 1613 lib/windows-mutex.h
@@ -1265,20 +1632,22 @@ AC_DEFUN([gl_FILE_LIST], [
1265 m4/assert_h.m4 1632 m4/assert_h.m4
1266 m4/base64.m4 1633 m4/base64.m4
1267 m4/btowc.m4 1634 m4/btowc.m4
1635 m4/build-to-host.m4
1268 m4/builtin-expect.m4 1636 m4/builtin-expect.m4
1269 m4/byteswap.m4 1637 m4/byteswap.m4
1270 m4/c-bool.m4 1638 m4/c-bool.m4
1639 m4/c32rtomb.m4
1271 m4/calloc.m4 1640 m4/calloc.m4
1272 m4/close.m4 1641 m4/close.m4
1273 m4/codeset.m4 1642 m4/codeset.m4
1274 m4/double-slash-root.m4 1643 m4/double-slash-root.m4
1275 m4/dup2.m4 1644 m4/dup2.m4
1276 m4/eealloc.m4
1277 m4/environ.m4 1645 m4/environ.m4
1278 m4/errno_h.m4 1646 m4/errno_h.m4
1279 m4/error.m4 1647 m4/error.m4
1280 m4/error_h.m4 1648 m4/error_h.m4
1281 m4/exponentd.m4 1649 m4/exponentd.m4
1650 m4/extensions-aix.m4
1282 m4/extensions.m4 1651 m4/extensions.m4
1283 m4/extern-inline.m4 1652 m4/extern-inline.m4
1284 m4/fclose.m4 1653 m4/fclose.m4
@@ -1294,6 +1663,7 @@ AC_DEFUN([gl_FILE_LIST], [
1294 m4/free.m4 1663 m4/free.m4
1295 m4/fseek.m4 1664 m4/fseek.m4
1296 m4/fseeko.m4 1665 m4/fseeko.m4
1666 m4/fseterr.m4
1297 m4/fstat.m4 1667 m4/fstat.m4
1298 m4/fstypename.m4 1668 m4/fstypename.m4
1299 m4/fsusage.m4 1669 m4/fsusage.m4
@@ -1309,10 +1679,12 @@ AC_DEFUN([gl_FILE_LIST], [
1309 m4/getprogname.m4 1679 m4/getprogname.m4
1310 m4/gl-openssl.m4 1680 m4/gl-openssl.m4
1311 m4/gnulib-common.m4 1681 m4/gnulib-common.m4
1682 m4/gnulib-i18n.m4
1312 m4/hostent.m4 1683 m4/hostent.m4
1313 m4/idpriv.m4 1684 m4/idpriv.m4
1314 m4/include_next.m4 1685 m4/include_next.m4
1315 m4/inet_ntop.m4 1686 m4/inet_ntop.m4
1687 m4/inet_pton.m4
1316 m4/intmax_t.m4 1688 m4/intmax_t.m4
1317 m4/inttypes.m4 1689 m4/inttypes.m4
1318 m4/inttypes_h.m4 1690 m4/inttypes_h.m4
@@ -1323,8 +1695,10 @@ AC_DEFUN([gl_FILE_LIST], [
1323 m4/iswxdigit.m4 1695 m4/iswxdigit.m4
1324 m4/langinfo_h.m4 1696 m4/langinfo_h.m4
1325 m4/largefile.m4 1697 m4/largefile.m4
1698 m4/libunistring-base.m4
1326 m4/limits-h.m4 1699 m4/limits-h.m4
1327 m4/localcharset.m4 1700 m4/localcharset.m4
1701 m4/locale-en.m4
1328 m4/locale-fr.m4 1702 m4/locale-fr.m4
1329 m4/locale-ja.m4 1703 m4/locale-ja.m4
1330 m4/locale-zh.m4 1704 m4/locale-zh.m4
@@ -1332,9 +1706,13 @@ AC_DEFUN([gl_FILE_LIST], [
1332 m4/localeconv.m4 1706 m4/localeconv.m4
1333 m4/lock.m4 1707 m4/lock.m4
1334 m4/lseek.m4 1708 m4/lseek.m4
1709 m4/lstat.m4
1335 m4/malloc.m4 1710 m4/malloc.m4
1336 m4/malloca.m4 1711 m4/malloca.m4
1337 m4/math_h.m4 1712 m4/math_h.m4
1713 m4/mbchar.m4
1714 m4/mbiter.m4
1715 m4/mbrtoc32.m4
1338 m4/mbrtowc.m4 1716 m4/mbrtowc.m4
1339 m4/mbsinit.m4 1717 m4/mbsinit.m4
1340 m4/mbstate_t.m4 1718 m4/mbstate_t.m4
@@ -1353,17 +1731,23 @@ AC_DEFUN([gl_FILE_LIST], [
1353 m4/netinet_in_h.m4 1731 m4/netinet_in_h.m4
1354 m4/nl_langinfo.m4 1732 m4/nl_langinfo.m4
1355 m4/nocrash.m4 1733 m4/nocrash.m4
1734 m4/off64_t.m4
1356 m4/off_t.m4 1735 m4/off_t.m4
1736 m4/once.m4
1357 m4/open-cloexec.m4 1737 m4/open-cloexec.m4
1358 m4/open-slash.m4 1738 m4/open-slash.m4
1359 m4/open.m4 1739 m4/open.m4
1360 m4/pathmax.m4 1740 m4/pathmax.m4
1361 m4/pid_t.m4 1741 m4/pid_t.m4
1362 m4/printf.m4 1742 m4/printf.m4
1743 m4/pthread-once.m4
1744 m4/pthread-spin.m4
1745 m4/pthread_h.m4
1363 m4/pthread_rwlock_rdlock.m4 1746 m4/pthread_rwlock_rdlock.m4
1364 m4/realloc.m4 1747 m4/realloc.m4
1365 m4/reallocarray.m4 1748 m4/reallocarray.m4
1366 m4/regex.m4 1749 m4/regex.m4
1750 m4/sched_h.m4
1367 m4/servent.m4 1751 m4/servent.m4
1368 m4/setenv.m4 1752 m4/setenv.m4
1369 m4/setlocale_null.m4 1753 m4/setlocale_null.m4
@@ -1379,18 +1763,22 @@ AC_DEFUN([gl_FILE_LIST], [
1379 m4/stat.m4 1763 m4/stat.m4
1380 m4/std-gnu11.m4 1764 m4/std-gnu11.m4
1381 m4/stdalign.m4 1765 m4/stdalign.m4
1766 m4/stdckdint_h.m4
1382 m4/stddef_h.m4 1767 m4/stddef_h.m4
1383 m4/stdint.m4 1768 m4/stdint.m4
1384 m4/stdint_h.m4 1769 m4/stdint_h.m4
1385 m4/stdio_h.m4 1770 m4/stdio_h.m4
1386 m4/stdlib_h.m4 1771 m4/stdlib_h.m4
1387 m4/strcase.m4 1772 m4/strcasecmp.m4
1388 m4/strcasestr.m4 1773 m4/strcasestr.m4
1389 m4/strerror.m4 1774 m4/strerror.m4
1390 m4/string_h.m4 1775 m4/string_h.m4
1391 m4/strings_h.m4 1776 m4/strings_h.m4
1777 m4/strncasecmp.m4
1778 m4/strncpy.m4
1392 m4/strsep.m4 1779 m4/strsep.m4
1393 m4/strstr.m4 1780 m4/strstr.m4
1781 m4/sys_cdefs_h.m4
1394 m4/sys_socket_h.m4 1782 m4/sys_socket_h.m4
1395 m4/sys_stat_h.m4 1783 m4/sys_stat_h.m4
1396 m4/sys_types_h.m4 1784 m4/sys_types_h.m4
@@ -1399,8 +1787,13 @@ AC_DEFUN([gl_FILE_LIST], [
1399 m4/time_h.m4 1787 m4/time_h.m4
1400 m4/time_r.m4 1788 m4/time_r.m4
1401 m4/timegm.m4 1789 m4/timegm.m4
1790 m4/uchar_h.m4
1402 m4/ungetc.m4 1791 m4/ungetc.m4
1792 m4/unicase_h.m4
1793 m4/unictype_h.m4
1794 m4/uninorm_h.m4
1403 m4/unistd_h.m4 1795 m4/unistd_h.m4
1796 m4/unitypes_h.m4
1404 m4/unlocked-io.m4 1797 m4/unlocked-io.m4
1405 m4/vararrays.m4 1798 m4/vararrays.m4
1406 m4/vasnprintf.m4 1799 m4/vasnprintf.m4
@@ -1409,10 +1802,10 @@ AC_DEFUN([gl_FILE_LIST], [
1409 m4/vsnprintf.m4 1802 m4/vsnprintf.m4
1410 m4/warn-on-use.m4 1803 m4/warn-on-use.m4
1411 m4/wchar_h.m4 1804 m4/wchar_h.m4
1412 m4/wchar_t.m4
1413 m4/wcrtomb.m4 1805 m4/wcrtomb.m4
1414 m4/wctype.m4 1806 m4/wctype.m4
1415 m4/wctype_h.m4 1807 m4/wctype_h.m4
1808 m4/wcwidth.m4
1416 m4/wint_t.m4 1809 m4/wint_t.m4
1417 m4/xalloc.m4 1810 m4/xalloc.m4
1418 m4/xsize.m4 1811 m4/xsize.m4
diff --git a/gl/m4/gnulib-i18n.m4 b/gl/m4/gnulib-i18n.m4
new file mode 100644
index 00000000..868043e7
--- /dev/null
+++ b/gl/m4/gnulib-i18n.m4
@@ -0,0 +1,61 @@
1# gnulib-i18n.m4
2# serial 1
3dnl Copyright (C) 2005-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9dnl From Bruno Haible.
10
11dnl Support for internationalization of Gnulib code.
12
13dnl GNULIB_I18N
14dnl Sets GNULIB_LOCALEDIR to indicate where to find the gnulib.mo files.
15dnl Also it defines GNULIB_LOCALEDIR as macro in config.h, that expands to
16dnl the corresponding C string.
17AC_DEFUN([GNULIB_I18N],
18[
19 dnl It is best to not test "$USE_NLS" here, because: It would be empty
20 dnl in case the package is internationalized but this macro is used before
21 dnl AM_GNU_GETTEXT. We would need to warn about this situation. But since
22 dnl this module is used as a dependency of many packages, such a warning is
23 dnl not welcome.
24
25 dnl Determine gnulib's localedir.
26 dnl Generally, accept an option --with-gnulib-prefix=PREFIX to indicate
27 dnl where to find gnulib's runtime data.
28 dnl Usually ${prefix}/share/locale, but can be influenced by the configure
29 dnl options --datarootdir and --localedir.
30 GNULIB_LOCALEDIR="${localedir}"
31 AC_ARG_WITH([gnulib-prefix],
32 [[ --with-gnulib-prefix=DIR search for gnulib's runtime data in DIR/share]],
33 [if test "X$withval" != "X" && test "X$withval" != "Xno"; then
34 GNULIB_LOCALEDIR="$withval/share/locale"
35 fi
36 ])
37 AC_SUBST([GNULIB_LOCALEDIR])
38
39 dnl Define GNULIB_LOCALEDIR_c and GNULIB_LOCALEDIR_c_make.
40 dnl Find the final value of GNULIB_LOCALEDIR.
41 gl_saved_prefix="${prefix}"
42 gl_saved_datarootdir="${datarootdir}"
43 gl_saved_localedir="${localedir}"
44 gl_saved_gnuliblocaledir="${GNULIB_LOCALEDIR}"
45 dnl Unfortunately, prefix gets only finally determined at the end of
46 dnl configure.
47 if test "X$prefix" = "XNONE"; then
48 prefix="$ac_default_prefix"
49 fi
50 eval datarootdir="$datarootdir"
51 eval localedir="$localedir"
52 eval GNULIB_LOCALEDIR="$GNULIB_LOCALEDIR"
53 gl_BUILD_TO_HOST([GNULIB_LOCALEDIR])
54 GNULIB_LOCALEDIR="${gl_saved_gnuliblocaledir}"
55 localedir="${gl_saved_localedir}"
56 datarootdir="${gl_saved_datarootdir}"
57 prefix="${gl_saved_prefix}"
58
59 AC_DEFINE_UNQUOTED([GNULIB_LOCALEDIR], [${GNULIB_LOCALEDIR_c}],
60 [Define to the directory where to find the localizations of the translation domain 'gnulib', as a C string.])
61])
diff --git a/gl/m4/gnulib-tool.m4 b/gl/m4/gnulib-tool.m4
index ef45f51f..8634a6e9 100644
--- a/gl/m4/gnulib-tool.m4
+++ b/gl/m4/gnulib-tool.m4
@@ -1,9 +1,10 @@
1# gnulib-tool.m4 1# gnulib-tool.m4
2# serial 4 2# serial 5
3dnl Copyright (C) 2004-2005, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2004-2005, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl The following macros need not be invoked explicitly. 9dnl The following macros need not be invoked explicitly.
9dnl Invoking them does nothing except to declare default arguments 10dnl Invoking them does nothing except to declare default arguments
@@ -42,6 +43,9 @@ AC_DEFUN([gl_LIB], [])
42dnl Usage: gl_LGPL or gl_LGPL([VERSION]) 43dnl Usage: gl_LGPL or gl_LGPL([VERSION])
43AC_DEFUN([gl_LGPL], []) 44AC_DEFUN([gl_LGPL], [])
44 45
46dnl Usage: gl_GPL([VERSION])
47AC_DEFUN([gl_GPL], [])
48
45dnl Usage: gl_MAKEFILE_NAME([FILENAME]) 49dnl Usage: gl_MAKEFILE_NAME([FILENAME])
46AC_DEFUN([gl_MAKEFILE_NAME], []) 50AC_DEFUN([gl_MAKEFILE_NAME], [])
47 51
diff --git a/gl/m4/hostent.m4 b/gl/m4/hostent.m4
index 36dc636e..9278285c 100644
--- a/gl/m4/hostent.m4
+++ b/gl/m4/hostent.m4
@@ -1,9 +1,10 @@
1# hostent.m4 1# hostent.m4
2# serial 5 2# serial 5
3dnl Copyright (C) 2008, 2010-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2008, 2010-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_HOSTENT], 9AC_DEFUN([gl_HOSTENT],
9[ 10[
diff --git a/gl/m4/idpriv.m4 b/gl/m4/idpriv.m4
index 53693527..6e855e9a 100644
--- a/gl/m4/idpriv.m4
+++ b/gl/m4/idpriv.m4
@@ -1,9 +1,10 @@
1# idpriv.m4 1# idpriv.m4
2# serial 1 2# serial 1
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_IDPRIV], 9AC_DEFUN([gl_IDPRIV],
9[ 10[
diff --git a/gl/m4/include_next.m4 b/gl/m4/include_next.m4
index 03e85251..80de991e 100644
--- a/gl/m4/include_next.m4
+++ b/gl/m4/include_next.m4
@@ -1,9 +1,10 @@
1# include_next.m4 1# include_next.m4
2# serial 27 2# serial 27
3dnl Copyright (C) 2006-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2006-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Paul Eggert and Derek Price. 9dnl From Paul Eggert and Derek Price.
9 10
diff --git a/gl/m4/inet_ntop.m4 b/gl/m4/inet_ntop.m4
index 168e17e0..693bd51b 100644
--- a/gl/m4/inet_ntop.m4
+++ b/gl/m4/inet_ntop.m4
@@ -1,9 +1,10 @@
1# inet_ntop.m4 1# inet_ntop.m4
2# serial 22 2# serial 22
3dnl Copyright (C) 2005-2006, 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2005-2006, 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_INET_NTOP], 9AC_DEFUN([gl_FUNC_INET_NTOP],
9[ 10[
diff --git a/gl/m4/inet_pton.m4 b/gl/m4/inet_pton.m4
new file mode 100644
index 00000000..b6e59a25
--- /dev/null
+++ b/gl/m4/inet_pton.m4
@@ -0,0 +1,72 @@
1# inet_pton.m4
2# serial 20
3dnl Copyright (C) 2006, 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9AC_DEFUN([gl_FUNC_INET_PTON],
10[
11 AC_REQUIRE([gl_ARPA_INET_H_DEFAULTS])
12
13 dnl Persuade Solaris <arpa/inet.h> to declare inet_pton.
14 AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
15
16 AC_REQUIRE([AC_C_RESTRICT])
17
18 dnl Most platforms that provide inet_pton define it in libc.
19 dnl Solaris 8..10 provide inet_pton in libnsl instead.
20 dnl Solaris 2.6..7 provide inet_pton in libresolv instead.
21 dnl Haiku provides it in -lnetwork.
22 dnl Native Windows provides it in -lws2_32 instead, with a declaration in
23 dnl <ws2tcpip.h>, and it uses stdcall calling convention, not cdecl
24 dnl (hence we cannot use AC_CHECK_FUNCS, AC_SEARCH_LIBS to find it).
25 HAVE_INET_PTON=1
26 INET_PTON_LIB=
27 gl_PREREQ_SYS_H_WINSOCK2
28 if test $HAVE_WINSOCK2_H = 1; then
29 dnl It needs to be overridden, because the stdcall calling convention
30 dnl is not compliant with POSIX. Set REPLACE_INET_PTON in order to avoid
31 dnl a name conflict at the linker level, even though the header file
32 dnl <ws2tcpip.h> declares inet_pton only if _WIN32_WINNT >= 0x0600.
33 REPLACE_INET_PTON=1
34 AC_CHECK_DECLS([inet_pton],,, [[#include <ws2tcpip.h>]])
35 if test $ac_cv_have_decl_inet_pton = yes; then
36 INET_PTON_LIB="-lws2_32"
37 else
38 HAVE_DECL_INET_PTON=0
39 fi
40 else
41 gl_saved_LIBS=$LIBS
42 AC_SEARCH_LIBS([inet_pton], [nsl resolv network], [],
43 [AC_CHECK_FUNCS([inet_pton])
44 if test $ac_cv_func_inet_pton = no; then
45 HAVE_INET_PTON=0
46 fi
47 ])
48 LIBS=$gl_saved_LIBS
49
50 if test "$ac_cv_search_inet_pton" != "no" \
51 && test "$ac_cv_search_inet_pton" != "none required"; then
52 INET_PTON_LIB="$ac_cv_search_inet_pton"
53 fi
54
55 AC_CHECK_HEADERS_ONCE([netdb.h])
56 AC_CHECK_DECLS([inet_pton],,,
57 [[#include <arpa/inet.h>
58 #if HAVE_NETDB_H
59 # include <netdb.h>
60 #endif
61 ]])
62 if test $ac_cv_have_decl_inet_pton = no; then
63 HAVE_DECL_INET_PTON=0
64 fi
65 fi
66 AC_SUBST([INET_PTON_LIB])
67])
68
69# Prerequisites of lib/inet_pton.c.
70AC_DEFUN([gl_PREREQ_INET_PTON], [
71 AC_REQUIRE([gl_SOCKET_FAMILIES])
72])
diff --git a/gl/m4/intmax_t.m4 b/gl/m4/intmax_t.m4
index 72858ea8..c1df7b27 100644
--- a/gl/m4/intmax_t.m4
+++ b/gl/m4/intmax_t.m4
@@ -1,10 +1,11 @@
1# intmax_t.m4 1# intmax_t.m4
2# serial 9 2# serial 9
3dnl Copyright (C) 1997-2004, 2006-2007, 2009-2024 Free Software Foundation, 3dnl Copyright (C) 1997-2004, 2006-2007, 2009-2025 Free Software Foundation,
4dnl Inc. 4dnl Inc.
5dnl This file is free software; the Free Software Foundation 5dnl This file is free software; the Free Software Foundation
6dnl gives unlimited permission to copy and/or distribute it, 6dnl gives unlimited permission to copy and/or distribute it,
7dnl with or without modifications, as long as this notice is preserved. 7dnl with or without modifications, as long as this notice is preserved.
8dnl This file is offered as-is, without any warranty.
8 9
9dnl From Paul Eggert. 10dnl From Paul Eggert.
10 11
diff --git a/gl/m4/inttypes.m4 b/gl/m4/inttypes.m4
index c43cd162..63c82c61 100644
--- a/gl/m4/inttypes.m4
+++ b/gl/m4/inttypes.m4
@@ -1,9 +1,10 @@
1# inttypes.m4 1# inttypes.m4
2# serial 37 2# serial 37
3dnl Copyright (C) 2006-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2006-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Derek Price, Bruno Haible. 9dnl From Derek Price, Bruno Haible.
9dnl Test whether <inttypes.h> is supported or must be substituted. 10dnl Test whether <inttypes.h> is supported or must be substituted.
diff --git a/gl/m4/inttypes_h.m4 b/gl/m4/inttypes_h.m4
index 3b9da5b0..ad939a53 100644
--- a/gl/m4/inttypes_h.m4
+++ b/gl/m4/inttypes_h.m4
@@ -1,9 +1,10 @@
1# inttypes_h.m4 1# inttypes_h.m4
2# serial 10 2# serial 10
3dnl Copyright (C) 1997-2004, 2006, 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 1997-2004, 2006, 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Paul Eggert. 9dnl From Paul Eggert.
9 10
diff --git a/gl/m4/iswblank.m4 b/gl/m4/iswblank.m4
index 4dc12d9a..d06b16a2 100644
--- a/gl/m4/iswblank.m4
+++ b/gl/m4/iswblank.m4
@@ -1,9 +1,10 @@
1# iswblank.m4 1# iswblank.m4
2# serial 7 2# serial 7
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2011-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_ISWBLANK], 9AC_DEFUN([gl_FUNC_ISWBLANK],
9[ 10[
diff --git a/gl/m4/iswctype.m4 b/gl/m4/iswctype.m4
index 16031be4..f5a3b760 100644
--- a/gl/m4/iswctype.m4
+++ b/gl/m4/iswctype.m4
@@ -1,9 +1,10 @@
1# iswctype.m4 1# iswctype.m4
2# serial 3 2# serial 3
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2011-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_ISWCTYPE], 9AC_DEFUN([gl_FUNC_ISWCTYPE],
9[ 10[
diff --git a/gl/m4/iswdigit.m4 b/gl/m4/iswdigit.m4
index 999acd28..4582f598 100644
--- a/gl/m4/iswdigit.m4
+++ b/gl/m4/iswdigit.m4
@@ -1,9 +1,10 @@
1# iswdigit.m4 1# iswdigit.m4
2# serial 7 2# serial 9
3dnl Copyright (C) 2020-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2020-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_ISWDIGIT], 9AC_DEFUN([gl_FUNC_ISWDIGIT],
9[ 10[
@@ -11,7 +12,7 @@ AC_DEFUN([gl_FUNC_ISWDIGIT],
11 AC_REQUIRE([gl_WCTYPE_H]) 12 AC_REQUIRE([gl_WCTYPE_H])
12 AC_REQUIRE([gt_LOCALE_FR]) 13 AC_REQUIRE([gt_LOCALE_FR])
13 AC_REQUIRE([gt_LOCALE_JA]) 14 AC_REQUIRE([gt_LOCALE_JA])
14 AC_REQUIRE([gt_LOCALE_FR_UTF8]) 15 AC_REQUIRE([gt_LOCALE_EN_UTF8])
15 AC_REQUIRE([gt_LOCALE_ZH_CN]) 16 AC_REQUIRE([gt_LOCALE_ZH_CN])
16 AC_REQUIRE([AC_CANONICAL_HOST]) 17 AC_REQUIRE([AC_CANONICAL_HOST])
17 18
@@ -26,14 +27,14 @@ AC_DEFUN([gl_FUNC_ISWDIGIT],
26 dnl is present. 27 dnl is present.
27changequote(,)dnl 28changequote(,)dnl
28 case "$host_os" in 29 case "$host_os" in
29 # Guess no on FreeBSD, NetBSD, Solaris, native Windows. 30 # Guess no on FreeBSD, NetBSD, OpenBSD, Solaris, native Windows, Haiku, Android.
30 freebsd* | dragonfly* | netbsd* | solaris* | mingw* | windows*) 31 freebsd* | dragonfly* | netbsd* | openbsd* | solaris* | mingw* | windows* | haiku* | *-android*)
31 gl_cv_func_iswdigit_works="guessing no" ;; 32 gl_cv_func_iswdigit_works="guessing no" ;;
32 # Guess yes otherwise. 33 # Guess yes otherwise.
33 *) gl_cv_func_iswdigit_works="guessing yes" ;; 34 *) gl_cv_func_iswdigit_works="guessing yes" ;;
34 esac 35 esac
35changequote([,])dnl 36changequote([,])dnl
36 if test $LOCALE_FR != none || test $LOCALE_JA != none || test $LOCALE_FR_UTF8 != none || test $LOCALE_ZH_CN != none; then 37 if test $LOCALE_FR != none || test $LOCALE_JA != none || test "$LOCALE_EN_UTF8" != none || test $LOCALE_ZH_CN != none; then
37 AC_RUN_IFELSE( 38 AC_RUN_IFELSE(
38 [AC_LANG_SOURCE([[ 39 [AC_LANG_SOURCE([[
39#include <locale.h> 40#include <locale.h>
@@ -83,15 +84,15 @@ main (int argc, char *argv[])
83 if (!(is == 0)) 84 if (!(is == 0))
84 result |= 2; 85 result |= 2;
85 } 86 }
86 if (strcmp ("$LOCALE_FR_UTF8", "none") != 0 87 if (strcmp ("$LOCALE_EN_UTF8", "none") != 0
87 && setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL) 88 && setlocale (LC_ALL, "$LOCALE_EN_UTF8") != NULL)
88 { 89 {
89 /* This fails on FreeBSD 13.0, NetBSD 10.0, MSVC 14. */ 90 /* This fails on FreeBSD 13.0, NetBSD 10.0, OpenBSD 7.5, MSVC 14, Haiku, Android. */
90 /* U+0663 ARABIC-INDIC DIGIT THREE */ 91 /* U+0663 ARABIC-INDIC DIGIT THREE */
91 is = for_character ("\331\243", 2); 92 is = for_character ("\331\243", 2);
92 if (!(is == 0)) 93 if (!(is == 0))
93 result |= 4; 94 result |= 4;
94 /* This fails on FreeBSD 13.0, NetBSD 10.0, MSVC 14. */ 95 /* This fails on FreeBSD 13.0, NetBSD 10.0, OpenBSD 7.5, MSVC 14, Haiku, Android. */
95 /* U+FF11 FULLWIDTH DIGIT ONE */ 96 /* U+FF11 FULLWIDTH DIGIT ONE */
96 is = for_character ("\357\274\221", 3); 97 is = for_character ("\357\274\221", 3);
97 if (!(is == 0)) 98 if (!(is == 0))
diff --git a/gl/m4/iswpunct.m4 b/gl/m4/iswpunct.m4
index 1edf58aa..d8e8d712 100644
--- a/gl/m4/iswpunct.m4
+++ b/gl/m4/iswpunct.m4
@@ -1,9 +1,10 @@
1# iswpunct.m4 1# iswpunct.m4
2# serial 2 2# serial 2
3dnl Copyright (C) 2023-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2023-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_ISWPUNCT], 9AC_DEFUN([gl_FUNC_ISWPUNCT],
9[ 10[
diff --git a/gl/m4/iswxdigit.m4 b/gl/m4/iswxdigit.m4
index 6085bf6b..95226fc4 100644
--- a/gl/m4/iswxdigit.m4
+++ b/gl/m4/iswxdigit.m4
@@ -1,16 +1,17 @@
1# iswxdigit.m4 1# iswxdigit.m4
2# serial 7 2# serial 9
3dnl Copyright (C) 2020-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2020-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_ISWXDIGIT], 9AC_DEFUN([gl_FUNC_ISWXDIGIT],
9[ 10[
10 AC_REQUIRE([gl_WCTYPE_H_DEFAULTS]) 11 AC_REQUIRE([gl_WCTYPE_H_DEFAULTS])
11 AC_REQUIRE([gl_WCTYPE_H]) 12 AC_REQUIRE([gl_WCTYPE_H])
12 AC_REQUIRE([gt_LOCALE_JA]) 13 AC_REQUIRE([gt_LOCALE_JA])
13 AC_REQUIRE([gt_LOCALE_FR_UTF8]) 14 AC_REQUIRE([gt_LOCALE_EN_UTF8])
14 AC_REQUIRE([gt_LOCALE_ZH_CN]) 15 AC_REQUIRE([gt_LOCALE_ZH_CN])
15 AC_REQUIRE([AC_CANONICAL_HOST]) 16 AC_REQUIRE([AC_CANONICAL_HOST])
16 17
@@ -25,14 +26,14 @@ AC_DEFUN([gl_FUNC_ISWXDIGIT],
25 dnl is present. 26 dnl is present.
26changequote(,)dnl 27changequote(,)dnl
27 case "$host_os" in 28 case "$host_os" in
28 # Guess no on FreeBSD, NetBSD, Solaris, native Windows. 29 # Guess no on FreeBSD, NetBSD, OpenBSD, Solaris, native Windows, Haiku, Android.
29 freebsd* | dragonfly* | netbsd* | solaris* | mingw* | windows*) 30 freebsd* | dragonfly* | netbsd* | openbsd* | solaris* | mingw* | windows* | haiku* | *-android*)
30 gl_cv_func_iswxdigit_works="guessing no" ;; 31 gl_cv_func_iswxdigit_works="guessing no" ;;
31 # Guess yes otherwise. 32 # Guess yes otherwise.
32 *) gl_cv_func_iswxdigit_works="guessing yes" ;; 33 *) gl_cv_func_iswxdigit_works="guessing yes" ;;
33 esac 34 esac
34changequote([,])dnl 35changequote([,])dnl
35 if test $LOCALE_JA != none || test $LOCALE_FR_UTF8 != none || test $LOCALE_ZH_CN != none; then 36 if test $LOCALE_JA != none || test "$LOCALE_EN_UTF8" != none || test $LOCALE_ZH_CN != none; then
36 AC_RUN_IFELSE( 37 AC_RUN_IFELSE(
37 [AC_LANG_SOURCE([[ 38 [AC_LANG_SOURCE([[
38#include <locale.h> 39#include <locale.h>
@@ -73,15 +74,15 @@ main (int argc, char *argv[])
73 if (!(is == 0)) 74 if (!(is == 0))
74 result |= 1; 75 result |= 1;
75 } 76 }
76 if (strcmp ("$LOCALE_FR_UTF8", "none") != 0 77 if (strcmp ("$LOCALE_EN_UTF8", "none") != 0
77 && setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL) 78 && setlocale (LC_ALL, "$LOCALE_EN_UTF8") != NULL)
78 { 79 {
79 /* This fails on FreeBSD 13.0. */ 80 /* This fails on FreeBSD 13.0, Haiku, Android. */
80 /* U+0663 ARABIC-INDIC DIGIT THREE */ 81 /* U+0663 ARABIC-INDIC DIGIT THREE */
81 is = for_character ("\331\243", 2); 82 is = for_character ("\331\243", 2);
82 if (!(is == 0)) 83 if (!(is == 0))
83 result |= 2; 84 result |= 2;
84 /* This fails on NetBSD 10.0, MSVC 14. */ 85 /* This fails on NetBSD 10.0, OpenBSD 7.5, MSVC 14, Haiku, Android. */
85 /* U+FF21 FULLWIDTH LATIN CAPITAL LETTER A */ 86 /* U+FF21 FULLWIDTH LATIN CAPITAL LETTER A */
86 is = for_character ("\357\274\241", 3); 87 is = for_character ("\357\274\241", 3);
87 if (!(is == 0)) 88 if (!(is == 0))
diff --git a/gl/m4/langinfo_h.m4 b/gl/m4/langinfo_h.m4
index 5eee8a71..69f936f0 100644
--- a/gl/m4/langinfo_h.m4
+++ b/gl/m4/langinfo_h.m4
@@ -1,9 +1,10 @@
1# langinfo_h.m4 1# langinfo_h.m4
2# serial 12 2# serial 13
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN_ONCE([gl_LANGINFO_H], 9AC_DEFUN_ONCE([gl_LANGINFO_H],
9[ 10[
@@ -19,6 +20,7 @@ AC_DEFUN_ONCE([gl_LANGINFO_H],
19 HAVE_LANGINFO_CODESET=0 20 HAVE_LANGINFO_CODESET=0
20 HAVE_LANGINFO_T_FMT_AMPM=0 21 HAVE_LANGINFO_T_FMT_AMPM=0
21 HAVE_LANGINFO_ALTMON=0 22 HAVE_LANGINFO_ALTMON=0
23 HAVE_LANGINFO_ABALTMON=0
22 HAVE_LANGINFO_ERA=0 24 HAVE_LANGINFO_ERA=0
23 HAVE_LANGINFO_YESEXPR=0 25 HAVE_LANGINFO_YESEXPR=0
24 AC_CHECK_HEADERS_ONCE([langinfo.h]) 26 AC_CHECK_HEADERS_ONCE([langinfo.h])
@@ -29,6 +31,7 @@ AC_DEFUN_ONCE([gl_LANGINFO_H],
29 dnl ERA etc. are missing on OpenBSD 6.7. 31 dnl ERA etc. are missing on OpenBSD 6.7.
30 dnl T_FMT_AMPM and YESEXPR, NOEXPR are missing on IRIX 5.3. 32 dnl T_FMT_AMPM and YESEXPR, NOEXPR are missing on IRIX 5.3.
31 dnl ALTMON_* are missing on glibc 2.26 and many other systems. 33 dnl ALTMON_* are missing on glibc 2.26 and many other systems.
34 dnl ABALTMON_* are missing on glibc 2.41 and many other systems.
32 AC_CACHE_CHECK([whether langinfo.h defines CODESET], 35 AC_CACHE_CHECK([whether langinfo.h defines CODESET],
33 [gl_cv_header_langinfo_codeset], 36 [gl_cv_header_langinfo_codeset],
34 [AC_COMPILE_IFELSE( 37 [AC_COMPILE_IFELSE(
@@ -65,6 +68,18 @@ int a = ALTMON_1;
65 if test $gl_cv_header_langinfo_altmon = yes; then 68 if test $gl_cv_header_langinfo_altmon = yes; then
66 HAVE_LANGINFO_ALTMON=1 69 HAVE_LANGINFO_ALTMON=1
67 fi 70 fi
71 AC_CACHE_CHECK([whether langinfo.h defines ABALTMON_1],
72 [gl_cv_header_langinfo_abaltmon],
73 [AC_COMPILE_IFELSE(
74 [AC_LANG_PROGRAM([[#include <langinfo.h>
75int a = ABALTMON_1;
76]])],
77 [gl_cv_header_langinfo_abaltmon=yes],
78 [gl_cv_header_langinfo_abaltmon=no])
79 ])
80 if test $gl_cv_header_langinfo_abaltmon = yes; then
81 HAVE_LANGINFO_ABALTMON=1
82 fi
68 AC_CACHE_CHECK([whether langinfo.h defines ERA], 83 AC_CACHE_CHECK([whether langinfo.h defines ERA],
69 [gl_cv_header_langinfo_era], 84 [gl_cv_header_langinfo_era],
70 [AC_COMPILE_IFELSE( 85 [AC_COMPILE_IFELSE(
@@ -96,6 +111,7 @@ int a = YESEXPR;
96 AC_SUBST([HAVE_LANGINFO_CODESET]) 111 AC_SUBST([HAVE_LANGINFO_CODESET])
97 AC_SUBST([HAVE_LANGINFO_T_FMT_AMPM]) 112 AC_SUBST([HAVE_LANGINFO_T_FMT_AMPM])
98 AC_SUBST([HAVE_LANGINFO_ALTMON]) 113 AC_SUBST([HAVE_LANGINFO_ALTMON])
114 AC_SUBST([HAVE_LANGINFO_ABALTMON])
99 AC_SUBST([HAVE_LANGINFO_ERA]) 115 AC_SUBST([HAVE_LANGINFO_ERA])
100 AC_SUBST([HAVE_LANGINFO_YESEXPR]) 116 AC_SUBST([HAVE_LANGINFO_YESEXPR])
101 117
diff --git a/gl/m4/largefile.m4 b/gl/m4/largefile.m4
index 2f824089..b24f657d 100644
--- a/gl/m4/largefile.m4
+++ b/gl/m4/largefile.m4
@@ -1,9 +1,10 @@
1# largefile.m4 1# largefile.m4
2# serial 1 2# serial 2
3dnl Copyright 1992-1996, 1998-2024 Free Software Foundation, Inc. 3dnl Copyright 1992-1996, 1998-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Enable large files on systems where this is not the default. 9# Enable large files on systems where this is not the default.
9# Enable support for files on Linux file systems with 64-bit inode numbers. 10# Enable support for files on Linux file systems with 64-bit inode numbers.
@@ -88,7 +89,7 @@ m4_define([_AC_SYS_YEAR2038_OPTIONS], m4_normalize(
88# If you change this macro you may also need to change 89# If you change this macro you may also need to change
89# _AC_SYS_YEAR2038_OPTIONS. 90# _AC_SYS_YEAR2038_OPTIONS.
90AC_DEFUN([_AC_SYS_YEAR2038_PROBE], 91AC_DEFUN([_AC_SYS_YEAR2038_PROBE],
91[AC_CACHE_CHECK([for $CPPFLAGS option for timestamps after 2038], 92[AC_CACHE_CHECK([for $CC option to support timestamps after 2038],
92 [ac_cv_sys_year2038_opts], 93 [ac_cv_sys_year2038_opts],
93 [ac_save_CPPFLAGS="$CPPFLAGS" 94 [ac_save_CPPFLAGS="$CPPFLAGS"
94 ac_opt_found=no 95 ac_opt_found=no
@@ -234,7 +235,7 @@ m4_define([_AC_SYS_LARGEFILE_OPTIONS], m4_normalize(
234# If you change this macro you may also need to change 235# If you change this macro you may also need to change
235# _AC_SYS_LARGEFILE_OPTIONS. 236# _AC_SYS_LARGEFILE_OPTIONS.
236AC_DEFUN([_AC_SYS_LARGEFILE_PROBE], 237AC_DEFUN([_AC_SYS_LARGEFILE_PROBE],
237[AC_CACHE_CHECK([for $CPPFLAGS option for large files], 238[AC_CACHE_CHECK([for $CC option to support large files],
238 [ac_cv_sys_largefile_opts], 239 [ac_cv_sys_largefile_opts],
239 [ac_save_CPPFLAGS=$CPPFLAGS 240 [ac_save_CPPFLAGS=$CPPFLAGS
240 ac_opt_found=no 241 ac_opt_found=no
@@ -294,7 +295,7 @@ AC_CONFIG_COMMANDS_PRE([_AC_SYS_YEAR2038_ENABLE])])
294# By default, many hosts won't let programs access large files; 295# By default, many hosts won't let programs access large files;
295# one must use special compiler options to get large-file access to work. 296# one must use special compiler options to get large-file access to work.
296# For more details about this brain damage please see: 297# For more details about this brain damage please see:
297# http://www.unix.org/version2/whatsnew/lfs20mar.html 298# https://www.unix.org/version2/whatsnew/lfs20mar.html
298# Additionally, on Linux file systems with 64-bit inodes a file that happens 299# Additionally, on Linux file systems with 64-bit inodes a file that happens
299# to have a 64-bit inode number cannot be accessed by 32-bit applications on 300# to have a 64-bit inode number cannot be accessed by 32-bit applications on
300# Linux x86/x86_64. This can occur with file systems such as XFS and NFS. 301# Linux x86/x86_64. This can occur with file systems such as XFS and NFS.
diff --git a/gl/m4/libunistring-base.m4 b/gl/m4/libunistring-base.m4
new file mode 100644
index 00000000..9b5795ed
--- /dev/null
+++ b/gl/m4/libunistring-base.m4
@@ -0,0 +1,204 @@
1# libunistring-base.m4
2# serial 10
3dnl Copyright (C) 2010-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9dnl From Paolo Bonzini and Bruno Haible.
10
11dnl gl_LIBUNISTRING_MODULE([VERSION], [Module])
12dnl Declares that the source files of Module should be compiled, unless we
13dnl are linking with libunistring and its version is >= the given VERSION.
14dnl Defines an automake conditional LIBUNISTRING_COMPILE_$MODULE that is
15dnl true if the source files of Module should be compiled.
16dnl This macro is to be used for public libunistring API, not for
17dnl undocumented API.
18dnl
19dnl You have to bump the VERSION argument to the next projected version
20dnl number each time you make a change that affects the behaviour of the
21dnl functions defined in Module (even if the sources of Module itself do not
22dnl change).
23dnl
24dnl This macro invocation must not occur in macros that are AC_REQUIREd.
25
26AC_DEFUN([gl_LIBUNISTRING_MODULE],
27[
28 AC_REQUIRE([gl_LIBUNISTRING_LIB_PREPARE])
29 dnl Use the variables HAVE_LIBUNISTRING, LIBUNISTRING_VERSION from
30 dnl gl_LIBUNISTRING_CORE if that macro has been run.
31 gl_CONDITIONAL(AS_TR_CPP([LIBUNISTRING_COMPILE_$2]),
32 [gl_LIBUNISTRING_VERSION_CMP([$1])])
33])
34
35dnl gl_LIBUNISTRING_MODULE_WITH_VARIABLE([VERSION], [Module])
36dnl is like gl_LIBUNISTRING_MODULE([VERSION], [Module]), except that it also
37dnl defines an AC_SUBSTed autoconf variable GNULIB_$MODULE_DLL_VARIABLE.
38dnl What's the expansion of this autoconf variable?
39dnl - When building libunistring, it expands to LIBUNISTRING_DLL_VARIABLE.
40dnl (This is necessary because this token must be present in the .h files
41dnl when the .h files get installed.)
42dnl - When building gnulib or application code it expands to
43dnl - LIBUNISTRING_DLL_VARIABLE by default,
44dnl - if the automake conditional LIBUNISTRING_COMPILE_$MODULE evaluates
45dnl to true: the value of
46dnl ${module_indicator_prefix}_GNULIB_LIBUNISTRING_DLL_VARIABLE_NAME
47dnl (which usually is empty, unless explicitly set in configure.ac).
48dnl (This is necessary because when the conditional evaluates to false,
49dnl the application code expects to use the declared variable from the
50dnl installed libunistring; it's in this case that the
51dnl LIBUNISTRING_DLL_VARIABLE macro from the installed
52dnl <unistring/woe32dll.h> must be used.)
53dnl
54dnl This macro invocation must not occur in macros that are AC_REQUIREd.
55
56AC_DEFUN([gl_LIBUNISTRING_MODULE_WITH_VARIABLE],
57[
58 gl_LIBUNISTRING_MODULE([$1], [$2])
59 m4_ifndef([gl_IN_LIBUNISTRING],
60 [if test -z "${AS_TR_CPP([LIBUNISTRING_COMPILE_$2])_TRUE}"; then
61 GL_MODULE_INDICATOR_PREFIX[]_GNULIB_[]AS_TR_CPP([$2_DLL_VARIABLE])=$GL_MODULE_INDICATOR_PREFIX[]_GNULIB_LIBUNISTRING_DLL_VARIABLE_NAME
62 fi
63 ])
64])
65
66dnl gl_LIBUNISTRING_LIBHEADER([VERSION], [HeaderFile])
67dnl Declares that HeaderFile should be created, unless we are linking
68dnl with libunistring and its version is >= the given VERSION.
69dnl HeaderFile should be relative to the lib directory and end in '.h'.
70dnl Prepares for substituting LIBUNISTRING_HEADERFILE (to HeaderFile or empty).
71dnl
72dnl When we are linking with the already installed libunistring and its version
73dnl is < VERSION, we create HeaderFile here, because we may compile functions
74dnl (via gl_LIBUNISTRING_MODULE above) that are not contained in the installed
75dnl version.
76dnl When we are linking with the already installed libunistring and its version
77dnl is > VERSION, we don't create HeaderFile here: it could cause compilation
78dnl errors in other libunistring header files if some types are missing.
79dnl
80dnl You have to bump the VERSION argument to the next projected version
81dnl number each time you make a non-comment change to the HeaderFile.
82
83AC_DEFUN([gl_LIBUNISTRING_LIBHEADER],
84[
85 AC_REQUIRE([gl_LIBUNISTRING_LIB_PREPARE])
86 dnl Use the variables HAVE_LIBUNISTRING, LIBUNISTRING_VERSION from
87 dnl gl_LIBUNISTRING_CORE if that macro has been run.
88 if gl_LIBUNISTRING_VERSION_CMP([$1]); then
89 dnl It is OK to use a .h file in lib/ from within tests/, but not vice
90 dnl versa.
91 if test -z "$LIBUNISTRING_[]AS_TR_CPP([$2])"; then
92 LIBUNISTRING_[]AS_TR_CPP([$2])="${gl_source_base_prefix}$2"
93 fi
94 else
95 LIBUNISTRING_[]AS_TR_CPP([$2])=
96 fi
97 AC_SUBST([LIBUNISTRING_]AS_TR_CPP([$2]))
98])
99
100dnl Miscellaneous preparations/initializations.
101
102AC_DEFUN([gl_LIBUNISTRING_LIB_PREPARE],
103[
104 dnl Ensure that HAVE_LIBUNISTRING is fully determined at this point.
105 m4_ifdef([gl_LIBUNISTRING], [AC_REQUIRE([gl_LIBUNISTRING])])
106
107 AC_REQUIRE([AC_PROG_AWK])
108
109dnl Sed expressions to extract the parts of a version number.
110changequote(,)
111gl_libunistring_sed_extract_major='/^[0-9]/{s/^\([0-9]*\).*/\1/p;q;}
112i\
1130
114q
115'
116gl_libunistring_sed_extract_minor='/^[0-9][0-9]*[.][0-9]/{s/^[0-9]*[.]\([0-9]*\).*/\1/p;q;}
117i\
1180
119q
120'
121gl_libunistring_sed_extract_subminor='/^[0-9][0-9]*[.][0-9][0-9]*[.][0-9]/{s/^[0-9]*[.][0-9]*[.]\([0-9]*\).*/\1/p;q;}
122i\
1230
124q
125'
126changequote([,])
127
128 if test "$HAVE_LIBUNISTRING" = yes; then
129 LIBUNISTRING_VERSION_MAJOR=`echo "$LIBUNISTRING_VERSION" | sed -n -e "$gl_libunistring_sed_extract_major"`
130 LIBUNISTRING_VERSION_MINOR=`echo "$LIBUNISTRING_VERSION" | sed -n -e "$gl_libunistring_sed_extract_minor"`
131 LIBUNISTRING_VERSION_SUBMINOR=`echo "$LIBUNISTRING_VERSION" | sed -n -e "$gl_libunistring_sed_extract_subminor"`
132 fi
133
134 dnl Determine whether <unistring/woe32dll.h> from an installed libunistring
135 dnl is available.
136 m4_ifdef([gl_IN_LIBUNISTRING],
137 [dnl In libunistring, all .h files that declare variables need to
138 dnl #include <unistring/woe32dll.h>. This references the file
139 dnl unistring/woe32dll.h in libunistring.
140 HAVE_UNISTRING_WOE32DLL_H=1
141 ],
142 [dnl In gnulib or in applications, we need a #include <unistring/woe32dll.h>
143 dnl if and only if an installed libunistring is available.
144 if test "$HAVE_LIBUNISTRING" = yes; then
145 AC_CHECK_HEADERS([unistring/woe32dll.h],
146 [HAVE_UNISTRING_WOE32DLL_H=1],
147 [HAVE_UNISTRING_WOE32DLL_H=0])
148 else
149 HAVE_UNISTRING_WOE32DLL_H=0
150 fi
151 ])
152 AC_SUBST([HAVE_UNISTRING_WOE32DLL_H])
153])
154
155dnl gl_LIBUNISTRING_VERSION_CMP([VERSION])
156dnl Expands to a shell statement that evaluates to true if LIBUNISTRING_VERSION
157dnl is less than the VERSION argument.
158AC_DEFUN([gl_LIBUNISTRING_VERSION_CMP],
159[dnl VERSION = 999.9 means to evaluates to true always, i.e. to ignore
160dnl the installed libunistring regardless of its version.
161m4_if([$1], [999.9],
162[true],
163[ { test "$HAVE_LIBUNISTRING" != yes \
164 || {
165 dnl AS_LITERAL_IF exists and works fine since autoconf-2.59 at least.
166 AS_LITERAL_IF([$1],
167 [dnl This is the optimized variant, that assumes the argument is a literal:
168 m4_pushdef([requested_version_major],
169 [gl_LIBUNISTRING_ARG_OR_ZERO(m4_bpatsubst([$1], [^\([0-9]*\).*], [\1]), [])])
170 m4_pushdef([requested_version_minor],
171 [gl_LIBUNISTRING_ARG_OR_ZERO(m4_bpatsubst([$1], [^[0-9]*[.]\([0-9]*\).*], [\1]), [$1])])
172 m4_pushdef([requested_version_subminor],
173 [gl_LIBUNISTRING_ARG_OR_ZERO(m4_bpatsubst([$1], [^[0-9]*[.][0-9]*[.]\([0-9]*\).*], [\1]), [$1])])
174 test $LIBUNISTRING_VERSION_MAJOR -lt requested_version_major \
175 || { test $LIBUNISTRING_VERSION_MAJOR -eq requested_version_major \
176 && { test $LIBUNISTRING_VERSION_MINOR -lt requested_version_minor \
177 || { test $LIBUNISTRING_VERSION_MINOR -eq requested_version_minor \
178 && test $LIBUNISTRING_VERSION_SUBMINOR -lt requested_version_subminor
179 }
180 }
181 }
182 m4_popdef([requested_version_subminor])
183 m4_popdef([requested_version_minor])
184 m4_popdef([requested_version_major])
185 ],
186 [dnl This is the unoptimized variant:
187 requested_version_major=`echo '$1' | sed -n -e "$gl_libunistring_sed_extract_major"`
188 requested_version_minor=`echo '$1' | sed -n -e "$gl_libunistring_sed_extract_minor"`
189 requested_version_subminor=`echo '$1' | sed -n -e "$gl_libunistring_sed_extract_subminor"`
190 test $LIBUNISTRING_VERSION_MAJOR -lt $requested_version_major \
191 || { test $LIBUNISTRING_VERSION_MAJOR -eq $requested_version_major \
192 && { test $LIBUNISTRING_VERSION_MINOR -lt $requested_version_minor \
193 || { test $LIBUNISTRING_VERSION_MINOR -eq $requested_version_minor \
194 && test $LIBUNISTRING_VERSION_SUBMINOR -lt $requested_version_subminor
195 }
196 }
197 }
198 ])
199 }
200 }])])
201
202dnl gl_LIBUNISTRING_ARG_OR_ZERO([ARG], [ORIG]) expands to ARG if it is not the
203dnl same as ORIG, otherwise to 0.
204m4_define([gl_LIBUNISTRING_ARG_OR_ZERO], [m4_if([$1], [$2], [0], [$1])])
diff --git a/gl/m4/limits-h.m4 b/gl/m4/limits-h.m4
index 1b619e1e..202df492 100644
--- a/gl/m4/limits-h.m4
+++ b/gl/m4/limits-h.m4
@@ -1,9 +1,10 @@
1# limits-h.m4 1# limits-h.m4
2# serial 1 2# serial 1
3dnl Copyright 2016-2024 Free Software Foundation, Inc. 3dnl Copyright 2016-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Check whether limits.h has needed features. 9dnl Check whether limits.h has needed features.
9 10
diff --git a/gl/m4/localcharset.m4 b/gl/m4/localcharset.m4
index 807a5eed..374a48f1 100644
--- a/gl/m4/localcharset.m4
+++ b/gl/m4/localcharset.m4
@@ -1,9 +1,10 @@
1# localcharset.m4 1# localcharset.m4
2# serial 8 2# serial 8
3dnl Copyright (C) 2002, 2004, 2006, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2002, 2004, 2006, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_LOCALCHARSET], 9AC_DEFUN([gl_LOCALCHARSET],
9[ 10[
diff --git a/gl/m4/locale-en.m4 b/gl/m4/locale-en.m4
new file mode 100644
index 00000000..4151428a
--- /dev/null
+++ b/gl/m4/locale-en.m4
@@ -0,0 +1,138 @@
1# locale-en.m4
2# serial 1
3dnl Copyright (C) 2003-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9dnl From Bruno Haible.
10
11dnl Determine the name of an English (or American English) locale with
12dnl UTF-8 encoding.
13AC_DEFUN_ONCE([gt_LOCALE_EN_UTF8],
14[
15 AC_REQUIRE([AC_CANONICAL_HOST])
16 AC_REQUIRE([AM_LANGINFO_CODESET])
17 AC_CACHE_CHECK([for an english Unicode locale], [gt_cv_locale_en_utf8], [
18 case "$host_os" in
19 *-musl* | midipix*)
20 dnl On musl libc, all kinds of ll_CC.UTF-8 locales exist, even without
21 dnl any locale file on disk. But they are effectively equivalent to the
22 dnl C.UTF-8 locale, except for locale categories (such as LC_MESSSAGES)
23 dnl for which localizations (.mo files) have been installed.
24 gt_cv_locale_en_utf8=en_US.UTF-8
25 ;;
26 *)
27 AC_LANG_CONFTEST([AC_LANG_SOURCE([[
28#include <locale.h>
29#include <time.h>
30#if HAVE_LANGINFO_CODESET
31# include <langinfo.h>
32#endif
33#include <stdlib.h>
34#include <string.h>
35struct tm t;
36char buf[16];
37int main () {
38 /* On BeOS and Haiku, locales are not implemented in libc. Rather, libintl
39 imitates locale dependent behaviour by looking at the environment
40 variables, and all locales use the UTF-8 encoding. */
41#if !(defined __BEOS__ || defined __HAIKU__)
42 /* Check whether the given locale name is recognized by the system. */
43# if defined _WIN32 && !defined __CYGWIN__
44 /* On native Windows, setlocale(category, "") looks at the system settings,
45 not at the environment variables. Also, when an encoding suffix such
46 as ".65001" or ".54936" is specified, it succeeds but sets the LC_CTYPE
47 category of the locale to "C". */
48 if (setlocale (LC_ALL, getenv ("LC_ALL")) == NULL
49 || strcmp (setlocale (LC_CTYPE, NULL), "C") == 0)
50 return 1;
51# else
52 if (setlocale (LC_ALL, "") == NULL) return 1;
53# endif
54 /* Check whether nl_langinfo(CODESET) is "UTF-8" or equivalent. */
55# if HAVE_LANGINFO_CODESET
56 {
57 const char *cs = nl_langinfo (CODESET);
58 if (!(strcmp (cs, "UTF-8") == 0 || strcmp (cs, "UTF8") == 0
59 || strcmp (cs, "utf-8") == 0 || strcmp (cs, "utf8") == 0))
60 return 1;
61 }
62# endif
63# ifdef __CYGWIN__
64 /* On Cygwin, avoid locale names without encoding suffix, because the
65 locale_charset() function relies on the encoding suffix. Note that
66 LC_ALL is set on the command line. */
67 if (strchr (getenv ("LC_ALL"), '.') == NULL) return 1;
68# endif
69 /* Check the third month name. */
70 t.tm_year = 1975 - 1900; t.tm_mon = 3 - 1; t.tm_mday = 24;
71 if (strftime (buf, sizeof (buf), "%B", &t) < 5 || strcmp (buf, "March") != 0)
72 return 1;
73#endif
74#if !defined __BIONIC__ /* Bionic libc's 'struct lconv' is just a dummy. */
75 /* Check whether the decimal separator is a dot. */
76 if (localeconv () ->decimal_point[0] != '.') return 1;
77#endif
78 return 0;
79}
80 ]])])
81 if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then
82 case "$host_os" in
83 # Handle native Windows specially, because there setlocale() interprets
84 # "ar" or "ara" as "Arabic" or "Arabic_Saudi Arabia.1256",
85 # "en" or "eng" as "English" or "English_United States.1252",
86 # "fr" or "fra" as "French" or "French_France.1252",
87 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252",
88 # "ja" or "jpn" as "Japanese" or "Japanese_Japan.932",
89 # and similar.
90 mingw* | windows*)
91 # Test for the hypothetical native Windows locale name.
92 if (LC_ALL='English_United States.65001' LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
93 gt_cv_locale_en_utf8='English_United States.65001'
94 else
95 # None found.
96 gt_cv_locale_en_utf8=none
97 fi
98 ;;
99 *)
100 # Setting LC_ALL is not enough. Need to set LC_TIME to empty, because
101 # otherwise on Mac OS X 10.3.5 the LC_TIME=C from the beginning of the
102 # configure script would override the LC_ALL setting. Likewise for
103 # LC_CTYPE, which is also set at the beginning of the configure script.
104 # Test for the locale name with explicit encoding suffix first
105 # (this is necessary on Haiku).
106 if (LC_ALL=en_US.UTF-8 LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
107 gt_cv_locale_en_utf8=en_US.UTF-8
108 else
109 # Test for the locale name without encoding suffix.
110 if (LC_ALL=en_US LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
111 gt_cv_locale_en_utf8=en_US
112 else
113 # Test for the Solaris 10 locale name.
114 if (LC_ALL=en.UTF-8 LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
115 gt_cv_locale_en_utf8=en.UTF-8
116 else
117 # None found.
118 gt_cv_locale_en_utf8=none
119 fi
120 fi
121 fi
122 ;;
123 esac
124 fi
125 rm -fr conftest*
126 ;;
127 esac
128 ])
129 LOCALE_EN_UTF8="$gt_cv_locale_en_utf8"
130 case "$LOCALE_EN_UTF8" in #(
131 '' | *[[\"\$\'*@<:@]]*)
132 dnl The empty value occurs when the conftest.c program above could not
133 dnl be compiled. The other values might cause trouble with sh or make.
134 AC_MSG_WARN([invalid locale "$LOCALE_EN_UTF8"; assuming "none"])
135 LOCALE_EN_UTF8=none;;
136 esac
137 AC_SUBST([LOCALE_EN_UTF8])
138])
diff --git a/gl/m4/locale-fr.m4 b/gl/m4/locale-fr.m4
index f8d7c543..f504d5b5 100644
--- a/gl/m4/locale-fr.m4
+++ b/gl/m4/locale-fr.m4
@@ -1,9 +1,10 @@
1# locale-fr.m4 1# locale-fr.m4
2# serial 23 2# serial 24
3dnl Copyright (C) 2003, 2005-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2003, 2005-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Bruno Haible. 9dnl From Bruno Haible.
9 10
@@ -71,8 +72,9 @@ int main () {
71 if (strftime (buf, sizeof (buf), "%b", &t) < 3 || buf[2] != 'v') return 1; 72 if (strftime (buf, sizeof (buf), "%b", &t) < 3 || buf[2] != 'v') return 1;
72# if !defined __BIONIC__ /* Bionic libc's 'struct lconv' is just a dummy. */ 73# if !defined __BIONIC__ /* Bionic libc's 'struct lconv' is just a dummy. */
73 /* Check whether the decimal separator is a comma. 74 /* Check whether the decimal separator is a comma.
74 On NetBSD 3.0 in the fr_FR.ISO8859-1 locale, localeconv()->decimal_point 75 On NetBSD 3.0 in the fr_FR.ISO8859-1 locale
75 are nl_langinfo(RADIXCHAR) are both ".". */ 76 and on Haiku in the fr_FR.UTF-8 locale,
77 localeconv()->decimal_point are nl_langinfo(RADIXCHAR) are both ".". */
76 if (localeconv () ->decimal_point[0] != ',') return 1; 78 if (localeconv () ->decimal_point[0] != ',') return 1;
77# endif 79# endif
78 return 0; 80 return 0;
@@ -82,10 +84,11 @@ int main () {
82 if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then 84 if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then
83 case "$host_os" in 85 case "$host_os" in
84 # Handle native Windows specially, because there setlocale() interprets 86 # Handle native Windows specially, because there setlocale() interprets
85 # "ar" as "Arabic" or "Arabic_Saudi Arabia.1256", 87 # "ar" or "ara" as "Arabic" or "Arabic_Saudi Arabia.1256",
88 # "en" or "eng" as "English" or "English_United States.1252",
86 # "fr" or "fra" as "French" or "French_France.1252", 89 # "fr" or "fra" as "French" or "French_France.1252",
87 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252", 90 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252",
88 # "ja" as "Japanese" or "Japanese_Japan.932", 91 # "ja" or "jpn" as "Japanese" or "Japanese_Japan.932",
89 # and similar. 92 # and similar.
90 mingw* | windows*) 93 mingw* | windows*)
91 # Test for the native Windows locale name. 94 # Test for the native Windows locale name.
@@ -214,8 +217,9 @@ int main () {
214#endif 217#endif
215#if !defined __BIONIC__ /* Bionic libc's 'struct lconv' is just a dummy. */ 218#if !defined __BIONIC__ /* Bionic libc's 'struct lconv' is just a dummy. */
216 /* Check whether the decimal separator is a comma. 219 /* Check whether the decimal separator is a comma.
217 On NetBSD 3.0 in the fr_FR.ISO8859-1 locale, localeconv()->decimal_point 220 On NetBSD 3.0 in the fr_FR.ISO8859-1 locale
218 are nl_langinfo(RADIXCHAR) are both ".". */ 221 and on Haiku in the fr_FR.UTF-8 locale,
222 localeconv()->decimal_point are nl_langinfo(RADIXCHAR) are both ".". */
219 if (localeconv () ->decimal_point[0] != ',') return 1; 223 if (localeconv () ->decimal_point[0] != ',') return 1;
220#endif 224#endif
221 return 0; 225 return 0;
@@ -224,10 +228,11 @@ int main () {
224 if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then 228 if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then
225 case "$host_os" in 229 case "$host_os" in
226 # Handle native Windows specially, because there setlocale() interprets 230 # Handle native Windows specially, because there setlocale() interprets
227 # "ar" as "Arabic" or "Arabic_Saudi Arabia.1256", 231 # "ar" or "ara" as "Arabic" or "Arabic_Saudi Arabia.1256",
232 # "en" or "eng" as "English" or "English_United States.1252",
228 # "fr" or "fra" as "French" or "French_France.1252", 233 # "fr" or "fra" as "French" or "French_France.1252",
229 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252", 234 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252",
230 # "ja" as "Japanese" or "Japanese_Japan.932", 235 # "ja" or "jpn" as "Japanese" or "Japanese_Japan.932",
231 # and similar. 236 # and similar.
232 mingw* | windows*) 237 mingw* | windows*)
233 # Test for the hypothetical native Windows locale name. 238 # Test for the hypothetical native Windows locale name.
diff --git a/gl/m4/locale-ja.m4 b/gl/m4/locale-ja.m4
index 8423bcb9..1c813b89 100644
--- a/gl/m4/locale-ja.m4
+++ b/gl/m4/locale-ja.m4
@@ -1,9 +1,10 @@
1# locale-ja.m4 1# locale-ja.m4
2# serial 18 2# serial 19
3dnl Copyright (C) 2003, 2005-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2003, 2005-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Bruno Haible. 9dnl From Bruno Haible.
9 10
@@ -86,10 +87,11 @@ int main ()
86 if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then 87 if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then
87 case "$host_os" in 88 case "$host_os" in
88 # Handle native Windows specially, because there setlocale() interprets 89 # Handle native Windows specially, because there setlocale() interprets
89 # "ar" as "Arabic" or "Arabic_Saudi Arabia.1256", 90 # "ar" or "ara" as "Arabic" or "Arabic_Saudi Arabia.1256",
91 # "en" or "eng" as "English" or "English_United States.1252",
90 # "fr" or "fra" as "French" or "French_France.1252", 92 # "fr" or "fra" as "French" or "French_France.1252",
91 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252", 93 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252",
92 # "ja" as "Japanese" or "Japanese_Japan.932", 94 # "ja" or "jpn" as "Japanese" or "Japanese_Japan.932",
93 # and similar. 95 # and similar.
94 mingw* | windows*) 96 mingw* | windows*)
95 # Note that on native Windows, the Japanese locale is 97 # Note that on native Windows, the Japanese locale is
diff --git a/gl/m4/locale-zh.m4 b/gl/m4/locale-zh.m4
index 7f1a10be..6f9374d2 100644
--- a/gl/m4/locale-zh.m4
+++ b/gl/m4/locale-zh.m4
@@ -1,9 +1,10 @@
1# locale-zh.m4 1# locale-zh.m4
2# serial 18 2# serial 20
3dnl Copyright (C) 2003, 2005-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2003, 2005-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Bruno Haible. 9dnl From Bruno Haible.
9 10
@@ -22,6 +23,7 @@ AC_DEFUN_ONCE([gt_LOCALE_ZH_CN],
22#endif 23#endif
23#include <stdlib.h> 24#include <stdlib.h>
24#include <string.h> 25#include <string.h>
26#include <wchar.h>
25struct tm t; 27struct tm t;
26char buf[16]; 28char buf[16];
27int main () 29int main ()
@@ -80,6 +82,19 @@ int main ()
80 single wide character. This excludes the GB2312 and GBK encodings. */ 82 single wide character. This excludes the GB2312 and GBK encodings. */
81 if (mblen ("\203\062\332\066", 5) != 4) 83 if (mblen ("\203\062\332\066", 5) != 4)
82 return 1; 84 return 1;
85 /* Check whether mbrtowc accept this character one byte at a time.
86 This excludes NetBSD 10.0. */
87 if (sizeof (wchar_t) > 2)
88 {
89 wchar_t wc;
90 mbstate_t state;
91 memset (&state, 0, sizeof (state));
92 if (!(mbrtowc (&wc, "\203", 1, &state) == (size_t)(-2)
93 && mbrtowc (&wc, "\062", 1, &state) == (size_t)(-2)
94 && mbrtowc (&wc, "\332", 1, &state) == (size_t)(-2)
95 && mbrtowc (&wc, "\066", 1, &state) == 1))
96 return 1;
97 }
83 return 0; 98 return 0;
84#endif 99#endif
85} 100}
@@ -87,10 +102,11 @@ int main ()
87 if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then 102 if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then
88 case "$host_os" in 103 case "$host_os" in
89 # Handle native Windows specially, because there setlocale() interprets 104 # Handle native Windows specially, because there setlocale() interprets
90 # "ar" as "Arabic" or "Arabic_Saudi Arabia.1256", 105 # "ar" or "ara" as "Arabic" or "Arabic_Saudi Arabia.1256",
106 # "en" or "eng" as "English" or "English_United States.1252",
91 # "fr" or "fra" as "French" or "French_France.1252", 107 # "fr" or "fra" as "French" or "French_France.1252",
92 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252", 108 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252",
93 # "ja" as "Japanese" or "Japanese_Japan.932", 109 # "ja" or "jpn" as "Japanese" or "Japanese_Japan.932",
94 # and similar. 110 # and similar.
95 mingw* | windows*) 111 mingw* | windows*)
96 # Test for the hypothetical native Windows locale name. 112 # Test for the hypothetical native Windows locale name.
diff --git a/gl/m4/locale_h.m4 b/gl/m4/locale_h.m4
index cd1c81ec..e1afbc16 100644
--- a/gl/m4/locale_h.m4
+++ b/gl/m4/locale_h.m4
@@ -1,9 +1,10 @@
1# locale_h.m4 1# locale_h.m4
2# serial 31 2# serial 37
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN_ONCE([gl_LOCALE_H], 9AC_DEFUN_ONCE([gl_LOCALE_H],
9[ 10[
@@ -19,6 +20,26 @@ AC_DEFUN_ONCE([gl_LOCALE_H],
19 AC_REQUIRE([gl_STDDEF_H]) 20 AC_REQUIRE([gl_STDDEF_H])
20 21
21 AC_REQUIRE([gl_LOCALE_T]) 22 AC_REQUIRE([gl_LOCALE_T])
23 dnl On native Windows, there is a type '_locale_t' that can be used to
24 dnl define locale_t.
25 AC_CACHE_CHECK([whether locale.h defines _locale_t],
26 [gl_cv_header_locale_has_windows_locale_t],
27 [AC_COMPILE_IFELSE(
28 [AC_LANG_PROGRAM(
29 [[#include <locale.h>
30 _locale_t x;]],
31 [[]])],
32 [gl_cv_header_locale_has_windows_locale_t=yes],
33 [gl_cv_header_locale_has_windows_locale_t=no])
34 ])
35 if test $gl_cv_header_locale_has_windows_locale_t = yes; then
36 HAVE_WINDOWS_LOCALE_T=1
37 AC_DEFINE([HAVE_WINDOWS_LOCALE_T], [1],
38 [Define to 1 if <locale.h> defines the _locale_t type.])
39 else
40 HAVE_WINDOWS_LOCALE_T=0
41 fi
42 AC_SUBST([HAVE_WINDOWS_LOCALE_T])
22 43
23 dnl Solaris 11.0 defines the int_p_*, int_n_* members of 'struct lconv' 44 dnl Solaris 11.0 defines the int_p_*, int_n_* members of 'struct lconv'
24 dnl only if _LCONV_C99 is defined. 45 dnl only if _LCONV_C99 is defined.
@@ -86,7 +107,7 @@ AC_DEFUN_ONCE([gl_LOCALE_H],
86# include <xlocale.h> 107# include <xlocale.h>
87#endif 108#endif
88 ]], 109 ]],
89 [setlocale newlocale duplocale freelocale]) 110 [setlocale newlocale duplocale freelocale getlocalename_l])
90]) 111])
91 112
92dnl Checks to determine whether the system has the locale_t type, 113dnl Checks to determine whether the system has the locale_t type,
@@ -130,6 +151,7 @@ AC_DEFUN([gl_LOCALE_T],
130 fi 151 fi
131 fi 152 fi
132 AC_SUBST([HAVE_XLOCALE_H]) 153 AC_SUBST([HAVE_XLOCALE_H])
154 AC_SUBST([HAVE_LOCALE_T])
133]) 155])
134 156
135# gl_LOCALE_MODULE_INDICATOR([modulename]) 157# gl_LOCALE_MODULE_INDICATOR([modulename])
@@ -154,7 +176,11 @@ AC_DEFUN([gl_LOCALE_H_REQUIRE_DEFAULTS],
154 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOCALECONV]) 176 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOCALECONV])
155 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETLOCALE]) 177 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETLOCALE])
156 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETLOCALE_NULL]) 178 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETLOCALE_NULL])
179 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_NEWLOCALE])
157 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DUPLOCALE]) 180 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DUPLOCALE])
181 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREELOCALE])
182 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLOCALENAME_L])
183 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLOCALENAME_L_UNSAFE])
158 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOCALENAME_UNSAFE]) 184 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOCALENAME_UNSAFE])
159 ]) 185 ])
160 m4_require(GL_MODULE_INDICATOR_PREFIX[_LOCALE_H_MODULE_INDICATOR_DEFAULTS]) 186 m4_require(GL_MODULE_INDICATOR_PREFIX[_LOCALE_H_MODULE_INDICATOR_DEFAULTS])
@@ -164,14 +190,16 @@ AC_DEFUN([gl_LOCALE_H_REQUIRE_DEFAULTS],
164AC_DEFUN([gl_LOCALE_H_DEFAULTS], 190AC_DEFUN([gl_LOCALE_H_DEFAULTS],
165[ 191[
166 dnl Assume proper GNU behavior unless another module says otherwise. 192 dnl Assume proper GNU behavior unless another module says otherwise.
167 HAVE_NEWLOCALE=1; AC_SUBST([HAVE_NEWLOCALE]) 193 HAVE_NEWLOCALE=1; AC_SUBST([HAVE_NEWLOCALE])
168 HAVE_DUPLOCALE=1; AC_SUBST([HAVE_DUPLOCALE]) 194 HAVE_DUPLOCALE=1; AC_SUBST([HAVE_DUPLOCALE])
169 HAVE_FREELOCALE=1; AC_SUBST([HAVE_FREELOCALE]) 195 HAVE_FREELOCALE=1; AC_SUBST([HAVE_FREELOCALE])
170 REPLACE_LOCALECONV=0; AC_SUBST([REPLACE_LOCALECONV]) 196 HAVE_GETLOCALENAME_L=1; AC_SUBST([HAVE_GETLOCALENAME_L])
171 REPLACE_SETLOCALE=0; AC_SUBST([REPLACE_SETLOCALE]) 197 REPLACE_LOCALECONV=0; AC_SUBST([REPLACE_LOCALECONV])
172 REPLACE_NEWLOCALE=0; AC_SUBST([REPLACE_NEWLOCALE]) 198 REPLACE_SETLOCALE=0; AC_SUBST([REPLACE_SETLOCALE])
173 REPLACE_DUPLOCALE=0; AC_SUBST([REPLACE_DUPLOCALE]) 199 REPLACE_NEWLOCALE=0; AC_SUBST([REPLACE_NEWLOCALE])
174 REPLACE_FREELOCALE=0; AC_SUBST([REPLACE_FREELOCALE]) 200 REPLACE_DUPLOCALE=0; AC_SUBST([REPLACE_DUPLOCALE])
175 REPLACE_STRUCT_LCONV=0; AC_SUBST([REPLACE_STRUCT_LCONV]) 201 REPLACE_FREELOCALE=0; AC_SUBST([REPLACE_FREELOCALE])
202 REPLACE_GETLOCALENAME_L=0; AC_SUBST([REPLACE_GETLOCALENAME_L])
203 REPLACE_STRUCT_LCONV=0; AC_SUBST([REPLACE_STRUCT_LCONV])
176 LOCALENAME_ENHANCE_LOCALE_FUNCS=0; AC_SUBST([LOCALENAME_ENHANCE_LOCALE_FUNCS]) 204 LOCALENAME_ENHANCE_LOCALE_FUNCS=0; AC_SUBST([LOCALENAME_ENHANCE_LOCALE_FUNCS])
177]) 205])
diff --git a/gl/m4/localeconv.m4 b/gl/m4/localeconv.m4
index 77d5684f..55a669d0 100644
--- a/gl/m4/localeconv.m4
+++ b/gl/m4/localeconv.m4
@@ -1,9 +1,10 @@
1# localeconv.m4 1# localeconv.m4
2# serial 3 2# serial 3
3dnl Copyright (C) 2012-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2012-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_LOCALECONV], 9AC_DEFUN([gl_FUNC_LOCALECONV],
9[ 10[
diff --git a/gl/m4/lock.m4 b/gl/m4/lock.m4
index eb0fc6a1..b1d3f435 100644
--- a/gl/m4/lock.m4
+++ b/gl/m4/lock.m4
@@ -1,9 +1,10 @@
1# lock.m4 1# lock.m4
2# serial 14 2# serial 14
3dnl Copyright (C) 2005-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2005-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Bruno Haible. 9dnl From Bruno Haible.
9 10
diff --git a/gl/m4/lseek.m4 b/gl/m4/lseek.m4
index 0bc3d65e..ddfadd38 100644
--- a/gl/m4/lseek.m4
+++ b/gl/m4/lseek.m4
@@ -1,9 +1,10 @@
1# lseek.m4 1# lseek.m4
2# serial 15 2# serial 15
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_LSEEK], 9AC_DEFUN([gl_FUNC_LSEEK],
9[ 10[
diff --git a/gl/m4/lstat.m4 b/gl/m4/lstat.m4
new file mode 100644
index 00000000..efae2485
--- /dev/null
+++ b/gl/m4/lstat.m4
@@ -0,0 +1,82 @@
1# lstat.m4
2# serial 36
3dnl Copyright (C) 1997-2001, 2003-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9dnl From Jim Meyering.
10
11AC_DEFUN([gl_FUNC_LSTAT],
12[
13 AC_REQUIRE([AC_CANONICAL_HOST])
14 AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
15 dnl If lstat does not exist, the replacement <sys/stat.h> does
16 dnl "#define lstat stat", and lstat.c is a no-op.
17 AC_CHECK_FUNCS_ONCE([lstat])
18 if test $ac_cv_func_lstat = yes; then
19 AC_REQUIRE([gl_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK])
20 case $host_os,$gl_cv_func_lstat_dereferences_slashed_symlink in
21 darwin* | solaris* | *no)
22 REPLACE_LSTAT=1
23 ;;
24 esac
25 else
26 HAVE_LSTAT=0
27 fi
28])
29
30# Prerequisites of lib/lstat.c.
31AC_DEFUN([gl_PREREQ_LSTAT], [:])
32
33AC_DEFUN([gl_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK],
34[
35 dnl We don't use AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK any more, because it
36 dnl is no longer maintained in Autoconf and because it invokes AC_LIBOBJ.
37 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
38 AC_CACHE_CHECK([whether lstat correctly handles trailing slash],
39 [gl_cv_func_lstat_dereferences_slashed_symlink],
40 [rm -f conftest.sym conftest.file
41 echo >conftest.file
42 AC_RUN_IFELSE(
43 [AC_LANG_PROGRAM(
44 [AC_INCLUDES_DEFAULT],
45 [[struct stat sbuf;
46 if (symlink ("conftest.file", "conftest.sym") != 0)
47 return 1;
48 /* Linux will dereference the symlink and fail, as required by
49 POSIX. That is better in the sense that it means we will not
50 have to compile and use the lstat wrapper. */
51 return lstat ("conftest.sym/", &sbuf) == 0;
52 ]])],
53 [gl_cv_func_lstat_dereferences_slashed_symlink=yes],
54 [gl_cv_func_lstat_dereferences_slashed_symlink=no],
55 [case "$host_os" in
56 linux-* | linux)
57 # Guess yes on Linux systems.
58 gl_cv_func_lstat_dereferences_slashed_symlink="guessing yes" ;;
59 midipix*)
60 # Guess yes on systems that emulate the Linux system calls.
61 gl_cv_func_lstat_dereferences_slashed_symlink="guessing yes" ;;
62 *-gnu* | gnu*)
63 # Guess yes on glibc systems.
64 gl_cv_func_lstat_dereferences_slashed_symlink="guessing yes" ;;
65 mingw* | windows*)
66 # Guess no on native Windows.
67 gl_cv_func_lstat_dereferences_slashed_symlink="guessing no" ;;
68 *)
69 # If we don't know, obey --enable-cross-guesses.
70 gl_cv_func_lstat_dereferences_slashed_symlink="$gl_cross_guess_normal" ;;
71 esac
72 ])
73 rm -f conftest.sym conftest.file
74 ])
75 case "$gl_cv_func_lstat_dereferences_slashed_symlink" in
76 *yes)
77 AC_DEFINE_UNQUOTED([LSTAT_FOLLOWS_SLASHED_SYMLINK], [1],
78 [Define to 1 if 'lstat' dereferences a symlink specified
79 with a trailing slash.])
80 ;;
81 esac
82])
diff --git a/gl/m4/malloc.m4 b/gl/m4/malloc.m4
index 41a46937..547b4e4d 100644
--- a/gl/m4/malloc.m4
+++ b/gl/m4/malloc.m4
@@ -1,12 +1,24 @@
1# malloc.m4 1# malloc.m4
2# serial 31 2# serial 43.1
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# This is adapted with modifications from upstream Autoconf here: 9m4_version_prereq([2.73], [], [
9# https://git.savannah.gnu.org/cgit/autoconf.git/tree/lib/autoconf/functions.m4?id=v2.70#n949 10# Modules that use this macro directly or indirectly should depend
11# on extensions-aix, so that _LINUX_SOURCE_COMPAT gets defined
12# before this macro gets invoked. This helps on AIX 7.2 and earlier
13# if !(__VEC__ || __AIXVEC), and doesn't hurt otherwise.
14#
15# This is copied from upstream Autoconf here:
16# https://git.savannah.gnu.org/cgit/autoconf.git/tree/lib/autoconf/functions.m4?id=1f38316f6af7bf63e5e7dd187ff6456e07ad743e#n971
17# _AC_FUNC_MALLOC_IF(IF-WORKS, IF-NOT[, UNKNOWN-ASSUME])
18# ------------------------------------------------------
19# If 'malloc (0)' returns nonnull, run IF-WORKS, otherwise, IF-NOT.
20# If it is not known whether it works, assume the shell word UNKNOWN-ASSUME,
21# which should end in "yes" or in something else (the latter is the default).
10AC_DEFUN([_AC_FUNC_MALLOC_IF], 22AC_DEFUN([_AC_FUNC_MALLOC_IF],
11[ 23[
12 AC_REQUIRE([AC_CANONICAL_HOST])dnl for cross-compiles 24 AC_REQUIRE([AC_CANONICAL_HOST])dnl for cross-compiles
@@ -15,56 +27,81 @@ AC_DEFUN([_AC_FUNC_MALLOC_IF],
15 [AC_RUN_IFELSE( 27 [AC_RUN_IFELSE(
16 [AC_LANG_PROGRAM( 28 [AC_LANG_PROGRAM(
17 [[#include <stdlib.h> 29 [[#include <stdlib.h>
18 ]], 30 /* Use pmalloc to test; 'volatile' prevents the compiler
19 [[void *p = malloc (0); 31 from optimizing the malloc call away. */
20 void * volatile vp = p; 32 void *(*volatile pmalloc) (size_t) = malloc;]],
21 int result = !vp; 33 [[void *p = pmalloc (0);
34 int result = !p;
22 free (p); 35 free (p);
23 return result;]]) 36 return result;]])],
24 ],
25 [ac_cv_func_malloc_0_nonnull=yes], 37 [ac_cv_func_malloc_0_nonnull=yes],
26 [ac_cv_func_malloc_0_nonnull=no], 38 [ac_cv_func_malloc_0_nonnull=no],
27 [case "$host_os" in 39 [AS_CASE([$host_os],
28 # Guess yes on platforms where we know the result. 40 [# Guess yes on platforms where we know the result.
29 *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \ 41 *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \
30 | gnu* | *-musl* | midipix* | midnightbsd* \ 42 | gnu* | *-musl* | midipix* | midnightbsd* \
31 | hpux* | solaris* | cygwin* | mingw* | windows* | msys* ) 43 | hpux* | solaris* | cygwin* | mingw* | windows* | msys*],
32 ac_cv_func_malloc_0_nonnull="guessing yes" ;; 44 [ac_cv_func_malloc_0_nonnull="guessing yes"],
33 # If we don't know, obey --enable-cross-guesses. 45 [# Guess as follows if we don't know.
34 *) ac_cv_func_malloc_0_nonnull="$gl_cross_guess_normal" ;; 46 ac_cv_func_malloc_0_nonnull=m4_default([$3], ["guessing no"])])])])
35 esac
36 ])
37 ])
38 AS_CASE([$ac_cv_func_malloc_0_nonnull], [*yes], [$1], [$2]) 47 AS_CASE([$ac_cv_func_malloc_0_nonnull], [*yes], [$1], [$2])
39])# _AC_FUNC_MALLOC_IF 48])# _AC_FUNC_MALLOC_IF
49])
50
51# gl_FUNC_MALLOC_0_NONNULL
52# ------------------------
53# If 'malloc (0)' returns nonnull define HAVE_MALLOC_0_NONNULL.
54# Also, set ac_cv_func_malloc_0_nonnull to a string that ends in
55# "yes", otherwise set it to something else. If unknown whether
56# malloc (0) works, guess as normal for cross-builds.
57AC_DEFUN([gl_FUNC_MALLOC_0_NONNULL],
58[
59 _AC_FUNC_MALLOC_IF(
60 [AC_DEFINE([HAVE_MALLOC_0_NONNULL], [1],
61 [Define to 1 if malloc (0) returns nonnull.])],
62 [],
63 ["$gl_cross_guess_normal"])
64])
40 65
41# gl_FUNC_MALLOC_GNU 66# gl_FUNC_MALLOC_GNU
42# ------------------ 67# ------------------
43# Replace malloc if it is not compatible with GNU libc. 68# Test whether malloc (0) is compatible with GNU libc.
69# Replace malloc if not.
70# Define HAVE_MALLOC_0_NONNULL if malloc (0) returns nonnull (except upon
71# out-of-memory).
72# Define HAVE_MALLOC_PTRDIFF if malloc (N) reliably fails when N exceeds
73# PTRDIFF_MAX.
44AC_DEFUN([gl_FUNC_MALLOC_GNU], 74AC_DEFUN([gl_FUNC_MALLOC_GNU],
45[ 75[
46 AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) 76 AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
47 AC_REQUIRE([gl_FUNC_MALLOC_POSIX]) 77 AC_REQUIRE([gl_FUNC_MALLOC_POSIX])
48 REPLACE_MALLOC_FOR_MALLOC_GNU="$REPLACE_MALLOC_FOR_MALLOC_POSIX" 78 AC_REQUIRE([gl_FUNC_MALLOC_0_NONNULL])
49 if test $REPLACE_MALLOC_FOR_MALLOC_GNU = 0; then 79
50 _AC_FUNC_MALLOC_IF([], [REPLACE_MALLOC_FOR_MALLOC_GNU=1]) 80 AS_CASE([$ac_cv_func_malloc_0_nonnull],
51 fi 81 [*yes],
82 [REPLACE_MALLOC_FOR_MALLOC_GNU=$REPLACE_MALLOC_FOR_MALLOC_POSIX],
83 [REPLACE_MALLOC_FOR_MALLOC_GNU=1])
52]) 84])
53 85
54# gl_FUNC_MALLOC_PTRDIFF 86# gl_FUNC_MALLOC_PTRDIFF
55# ---------------------- 87# ----------------------
56# Test whether malloc (N) reliably fails when N exceeds PTRDIFF_MAX, 88# Test whether malloc (N) reliably fails when N exceeds PTRDIFF_MAX.
57# and replace malloc otherwise. 89# Define HAVE_MALLOC_PTRDIFF if yes.
90# Replace malloc if not.
58AC_DEFUN([gl_FUNC_MALLOC_PTRDIFF], 91AC_DEFUN([gl_FUNC_MALLOC_PTRDIFF],
59[ 92[
60 AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) 93 AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
61 AC_REQUIRE([gl_CHECK_MALLOC_PTRDIFF]) 94 AC_REQUIRE([gl_CHECK_MALLOC_PTRDIFF])
62 test "$gl_cv_malloc_ptrdiff" = yes || REPLACE_MALLOC_FOR_MALLOC_POSIX=1 95 AS_IF([test "$gl_cv_malloc_ptrdiff" = yes],
96 [AC_DEFINE([HAVE_MALLOC_PTRDIFF], 1,
97 [Define to 1 if malloc-like functions do not allocate objects
98 larger than PTRDIFF_MAX bytes.])],
99 [REPLACE_MALLOC_FOR_MALLOC_POSIX=1])
63]) 100])
64 101
65# Test whether malloc, realloc, calloc refuse to create objects 102# Test whether malloc, calloc refuse to create objects
66# larger than what can be expressed in ptrdiff_t. 103# larger than what can be expressed in ptrdiff_t.
67# Set gl_cv_func_malloc_gnu to yes or no accordingly. 104# Set gl_cv_func_malloc_gnu.
68AC_DEFUN([gl_CHECK_MALLOC_PTRDIFF], 105AC_DEFUN([gl_CHECK_MALLOC_PTRDIFF],
69[ 106[
70 AC_CACHE_CHECK([whether malloc is ptrdiff_t safe], 107 AC_CACHE_CHECK([whether malloc is ptrdiff_t safe],
@@ -108,30 +145,48 @@ AC_DEFUN([gl_FUNC_MALLOC_POSIX],
108 AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) 145 AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
109 AC_REQUIRE([gl_FUNC_MALLOC_PTRDIFF]) 146 AC_REQUIRE([gl_FUNC_MALLOC_PTRDIFF])
110 AC_REQUIRE([gl_CHECK_MALLOC_POSIX]) 147 AC_REQUIRE([gl_CHECK_MALLOC_POSIX])
111 if test "$gl_cv_func_malloc_posix" = yes; then 148 case "$gl_cv_func_malloc_posix" in
112 AC_DEFINE([HAVE_MALLOC_POSIX], [1], 149 *yes)
113 [Define if malloc, realloc, and calloc set errno on allocation failure.]) 150 AC_DEFINE([HAVE_MALLOC_POSIX], [1],
114 else 151 [Define if malloc and calloc set errno on allocation failure.])
115 REPLACE_MALLOC_FOR_MALLOC_POSIX=1 152 ;;
116 fi 153 *)
154 REPLACE_MALLOC_FOR_MALLOC_POSIX=1
155 ;;
156 esac
117]) 157])
118 158
119# Test whether malloc, realloc, calloc set errno to ENOMEM on failure. 159# Test whether malloc, calloc set errno to ENOMEM on failure.
120# Set gl_cv_func_malloc_posix to yes or no accordingly. 160# Set gl_cv_func_malloc_posix to *yes or *no accordingly.
121AC_DEFUN([gl_CHECK_MALLOC_POSIX], 161AC_DEFUN([gl_CHECK_MALLOC_POSIX],
122[ 162[
123 AC_REQUIRE([AC_CANONICAL_HOST]) 163 AC_REQUIRE([AC_CANONICAL_HOST])
124 AC_CACHE_CHECK([whether malloc, realloc, calloc set errno on failure], 164 AC_CACHE_CHECK([whether malloc, calloc set errno on failure],
125 [gl_cv_func_malloc_posix], 165 [gl_cv_func_malloc_posix],
126 [ 166 [
127 dnl It is too dangerous to try to allocate a large amount of memory: 167 dnl It is too dangerous to try to allocate a large amount of memory:
128 dnl some systems go to their knees when you do that. So assume that 168 dnl some systems go to their knees when you do that. So assume that
129 dnl all Unix implementations of the function set errno on failure, 169 dnl all Unix implementations of the function set errno on failure,
130 dnl except on those platforms where we have seen 'test-malloc-gnu', 170 dnl except on those platforms where we have seen 'test-malloc-gnu',
131 dnl 'test-realloc-gnu', 'test-calloc-gnu' fail. 171 dnl 'test-realloc-posix', 'test-calloc-gnu' fail. For platforms
172 dnl where only 'test-realloc-posix', see realloc.m4.
132 case "$host_os" in 173 case "$host_os" in
133 mingw* | windows*) 174 mingw* | windows*)
134 gl_cv_func_malloc_posix=no ;; 175 dnl Old MSVCRT from 2001 did not set errno=ENOMEM when malloc failed.
176 dnl More recent MSVCRT from 2019 does so.
177 dnl UCRT is the successor of MSVCRT. Assume that UCRT does so as well.
178 AC_COMPILE_IFELSE(
179 [AC_LANG_PROGRAM(
180 [[#include <stdio.h>
181 #ifndef _UCRT
182 msvcrt yuck
183 #endif
184 ]],
185 [[]])
186 ],
187 [gl_cv_func_malloc_posix="guessing yes"],
188 [gl_cv_func_malloc_posix="guessing no"])
189 ;;
135 irix* | solaris*) 190 irix* | solaris*)
136 dnl On IRIX 6.5, the three functions return NULL with errno unset 191 dnl On IRIX 6.5, the three functions return NULL with errno unset
137 dnl when the argument is larger than PTRDIFF_MAX. 192 dnl when the argument is larger than PTRDIFF_MAX.
diff --git a/gl/m4/malloca.m4 b/gl/m4/malloca.m4
index 9e09d22c..cabe5fe7 100644
--- a/gl/m4/malloca.m4
+++ b/gl/m4/malloca.m4
@@ -1,15 +1,16 @@
1# malloca.m4 1# malloca.m4
2# serial 2 2# serial 3
3dnl Copyright (C) 2003-2004, 2006-2007, 2009-2024 Free Software Foundation, 3dnl Copyright (C) 2003-2004, 2006-2007, 2009-2025 Free Software Foundation,
4dnl Inc. 4dnl Inc.
5dnl This file is free software; the Free Software Foundation 5dnl This file is free software; the Free Software Foundation
6dnl gives unlimited permission to copy and/or distribute it, 6dnl gives unlimited permission to copy and/or distribute it,
7dnl with or without modifications, as long as this notice is preserved. 7dnl with or without modifications, as long as this notice is preserved.
8dnl This file is offered as-is, without any warranty.
8 9
9AC_DEFUN([gl_MALLOCA], 10AC_DEFUN([gl_MALLOCA],
10[ 11[
11 dnl Use the autoconf tests for alloca(), but not the AC_SUBSTed variables 12 dnl Use the autoconf tests for alloca(), but not the AC_SUBSTed variables
12 dnl @ALLOCA@ and @LTALLOCA@. 13 dnl @ALLOCA@ and @LTALLOCA@.
13 dnl gl_FUNC_ALLOCA dnl Already brought in by the module dependencies. 14 dnl gl_FUNC_ALLOCA dnl Already brought in by the module dependencies.
14 AC_REQUIRE([gl_EEMALLOC]) 15 AC_REQUIRE([gl_FUNC_MALLOC_GNU])
15]) 16])
diff --git a/gl/m4/math_h.m4 b/gl/m4/math_h.m4
index 4b26c9e9..8c27503b 100644
--- a/gl/m4/math_h.m4
+++ b/gl/m4/math_h.m4
@@ -1,9 +1,10 @@
1# math_h.m4 1# math_h.m4
2# serial 138 2# serial 140.1
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN_ONCE([gl_MATH_H], 9AC_DEFUN_ONCE([gl_MATH_H],
9[ 10[
@@ -49,7 +50,7 @@ AC_DEFUN_ONCE([gl_MATH_H],
49 ilogb ilogbf ilogbl 50 ilogb ilogbf ilogbl
50 ldexpf ldexpl 51 ldexpf ldexpl
51 log logf logl log10 log10f log10l log1p log1pf log1pl log2 log2f log2l 52 log logf logl log10 log10f log10l log1p log1pf log1pl log2 log2f log2l
52 logb logbf logbl 53 logb logbf logbl logp1 log1pf logp1l
53 modf modff modfl powf 54 modf modff modfl powf
54 remainder remainderf remainderl 55 remainder remainderf remainderl
55 rint rintf rintl round roundf roundl 56 rint rintf rintl round roundf roundl
@@ -153,6 +154,9 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS],
153 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOGB]) 154 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOGB])
154 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOGBF]) 155 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOGBF])
155 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOGBL]) 156 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOGBL])
157 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOGP1])
158 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOGP1F])
159 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOGP1L])
156 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MODF]) 160 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MODF])
157 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MODFF]) 161 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MODFF])
158 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MODFL]) 162 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MODFL])
@@ -253,6 +257,9 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
253 HAVE_LOG1PL=1; AC_SUBST([HAVE_LOG1PL]) 257 HAVE_LOG1PL=1; AC_SUBST([HAVE_LOG1PL])
254 HAVE_LOGBF=1; AC_SUBST([HAVE_LOGBF]) 258 HAVE_LOGBF=1; AC_SUBST([HAVE_LOGBF])
255 HAVE_LOGBL=1; AC_SUBST([HAVE_LOGBL]) 259 HAVE_LOGBL=1; AC_SUBST([HAVE_LOGBL])
260 HAVE_LOGP1=1; AC_SUBST([HAVE_LOGP1])
261 HAVE_LOGP1F=1; AC_SUBST([HAVE_LOGP1F])
262 HAVE_LOGP1L=1; AC_SUBST([HAVE_LOGP1L])
256 HAVE_MODFF=1; AC_SUBST([HAVE_MODFF]) 263 HAVE_MODFF=1; AC_SUBST([HAVE_MODFF])
257 HAVE_MODFL=1; AC_SUBST([HAVE_MODFL]) 264 HAVE_MODFL=1; AC_SUBST([HAVE_MODFL])
258 HAVE_POWF=1; AC_SUBST([HAVE_POWF]) 265 HAVE_POWF=1; AC_SUBST([HAVE_POWF])
@@ -392,6 +399,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
392 REPLACE_SIGNBIT_USING_BUILTINS=0; AC_SUBST([REPLACE_SIGNBIT_USING_BUILTINS]) 399 REPLACE_SIGNBIT_USING_BUILTINS=0; AC_SUBST([REPLACE_SIGNBIT_USING_BUILTINS])
393 REPLACE_SINF=0; AC_SUBST([REPLACE_SINF]) 400 REPLACE_SINF=0; AC_SUBST([REPLACE_SINF])
394 REPLACE_SINHF=0; AC_SUBST([REPLACE_SINHF]) 401 REPLACE_SINHF=0; AC_SUBST([REPLACE_SINHF])
402 REPLACE_SINL=0; AC_SUBST([REPLACE_SINL])
395 REPLACE_SQRTF=0; AC_SUBST([REPLACE_SQRTF]) 403 REPLACE_SQRTF=0; AC_SUBST([REPLACE_SQRTF])
396 REPLACE_SQRTL=0; AC_SUBST([REPLACE_SQRTL]) 404 REPLACE_SQRTL=0; AC_SUBST([REPLACE_SQRTL])
397 REPLACE_TANF=0; AC_SUBST([REPLACE_TANF]) 405 REPLACE_TANF=0; AC_SUBST([REPLACE_TANF])
diff --git a/gl/m4/mbchar.m4 b/gl/m4/mbchar.m4
new file mode 100644
index 00000000..b76f1d7b
--- /dev/null
+++ b/gl/m4/mbchar.m4
@@ -0,0 +1,15 @@
1# mbchar.m4
2# serial 9
3dnl Copyright (C) 2005-2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9dnl autoconf tests required for use of mbchar.m4
10dnl From Bruno Haible.
11
12AC_DEFUN([gl_MBCHAR],
13[
14 AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
15])
diff --git a/gl/m4/mbiter.m4 b/gl/m4/mbiter.m4
new file mode 100644
index 00000000..b51242e6
--- /dev/null
+++ b/gl/m4/mbiter.m4
@@ -0,0 +1,16 @@
1# mbiter.m4
2# serial 7
3dnl Copyright (C) 2005, 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9dnl autoconf tests required for use of mbiter.h
10dnl From Bruno Haible.
11
12AC_DEFUN([gl_MBITER],
13[
14 AC_REQUIRE([AC_TYPE_MBSTATE_T])
15 :
16])
diff --git a/gl/m4/mbrtoc32.m4 b/gl/m4/mbrtoc32.m4
new file mode 100644
index 00000000..1991529c
--- /dev/null
+++ b/gl/m4/mbrtoc32.m4
@@ -0,0 +1,326 @@
1# mbrtoc32.m4
2# serial 21
3dnl Copyright (C) 2014-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9AC_DEFUN([gl_FUNC_MBRTOC32],
10[
11 AC_REQUIRE([gl_UCHAR_H_DEFAULTS])
12
13 AC_REQUIRE([AC_TYPE_MBSTATE_T])
14 dnl Determine REPLACE_MBSTATE_T, from which GNULIB_defined_mbstate_t is
15 dnl determined. It describes how our overridden mbrtowc is implemented.
16 dnl We then implement mbrtoc32 accordingly.
17 AC_REQUIRE([gl_MBSTATE_T_BROKEN])
18
19 AC_REQUIRE([gl_TYPE_CHAR32_T])
20 AC_REQUIRE([gl_MBRTOC32_SANITYCHECK])
21
22 AC_REQUIRE([gl_CHECK_FUNC_MBRTOC32])
23 if test $gl_cv_func_mbrtoc32 = no; then
24 HAVE_MBRTOC32=0
25 else
26 if test $GNULIBHEADERS_OVERRIDE_CHAR32_T = 1 || test $REPLACE_MBSTATE_T = 1; then
27 REPLACE_MBRTOC32=1
28 else
29 gl_MBRTOC32_EMPTY_INPUT
30 gl_MBRTOC32_C_LOCALE
31 gl_MBRTOC32_UTF8_LOCALE
32 case "$gl_cv_func_mbrtoc32_empty_input" in
33 *yes) ;;
34 *) AC_DEFINE([MBRTOC32_EMPTY_INPUT_BUG], [1],
35 [Define if the mbrtoc32 function does not return (size_t) -2 for empty input.])
36 REPLACE_MBRTOC32=1
37 ;;
38 esac
39 case "$gl_cv_func_mbrtoc32_C_locale_sans_EILSEQ" in
40 *yes) ;;
41 *) AC_DEFINE([MBRTOC32_IN_C_LOCALE_MAYBE_EILSEQ], [1],
42 [Define if the mbrtoc32 function may signal encoding errors in the C locale.])
43 REPLACE_MBRTOC32=1
44 ;;
45 esac
46 case "$gl_cv_func_mbrtoc32_utf8_locale_works" in
47 *yes) ;;
48 *) AC_DEFINE([MBRTOC32_MULTIBYTE_LOCALE_BUG], [1],
49 [Define if the mbrtoc32 function does not accept the input bytes one-by-one.])
50 REPLACE_MBRTOC32=1
51 dnl Our replacement mbrtoc32 can handle UTF-8, but not GB18030.
52 LOCALE_ZH_CN=none
53 ;;
54 esac
55 fi
56 if test $HAVE_WORKING_MBRTOC32 = 0; then
57 REPLACE_MBRTOC32=1
58 fi
59 fi
60])
61
62AC_DEFUN([gl_CHECK_FUNC_MBRTOC32],
63[
64 dnl Cf. gl_CHECK_FUNCS_ANDROID
65 AC_CHECK_DECL([mbrtoc32], , ,
66 [[#ifdef __HAIKU__
67 #include <stdint.h>
68 #endif
69 #include <uchar.h>
70 ]])
71 if test $ac_cv_have_decl_mbrtoc32 = yes; then
72 dnl We can't use AC_CHECK_FUNC here, because mbrtoc32() is defined as a
73 dnl static inline function on Haiku 2020.
74 AC_CACHE_CHECK([for mbrtoc32], [gl_cv_func_mbrtoc32],
75 [AC_LINK_IFELSE(
76 [AC_LANG_PROGRAM(
77 [[#include <stdlib.h>
78 #ifdef __HAIKU__
79 #include <stdint.h>
80 #endif
81 #include <uchar.h>
82 ]],
83 [[char32_t c;
84 return mbrtoc32 (&c, "", 1, NULL) == 0;
85 ]])
86 ],
87 [gl_cv_func_mbrtoc32=yes],
88 [gl_cv_func_mbrtoc32=no])
89 ])
90 else
91 gl_cv_func_mbrtoc32=no
92 fi
93])
94
95dnl Test whether mbrtoc32 returns the correct value on empty input.
96
97AC_DEFUN([gl_MBRTOC32_EMPTY_INPUT],
98[
99 AC_REQUIRE([AC_PROG_CC])
100 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
101 AC_CACHE_CHECK([whether mbrtoc32 works on empty input],
102 [gl_cv_func_mbrtoc32_empty_input],
103 [
104 AC_RUN_IFELSE(
105 [AC_LANG_SOURCE([[
106 #ifdef __HAIKU__
107 #include <stdint.h>
108 #endif
109 #include <uchar.h>
110 static char32_t wc;
111 static mbstate_t mbs;
112 int
113 main (void)
114 {
115 return mbrtoc32 (&wc, "", 0, &mbs) != (size_t) -2;
116 }]])],
117 [gl_cv_func_mbrtoc32_empty_input=yes],
118 [gl_cv_func_mbrtoc32_empty_input=no],
119 [case "$host_os" in
120 # Guess no on glibc systems.
121 *-gnu* | gnu*) gl_cv_func_mbrtoc32_empty_input="guessing no" ;;
122 # Guess no on Android.
123 linux*-android*) gl_cv_func_mbrtoc32_empty_input="guessing no" ;;
124 # Guess no on native Windows.
125 mingw* | windows*) gl_cv_func_mbrtoc32_empty_input="guessing no" ;;
126 *) gl_cv_func_mbrtoc32_empty_input="guessing yes" ;;
127 esac
128 ])
129 ])
130])
131
132dnl <https://pubs.opengroup.org/onlinepubs/9699919799/functions/mbrtowc.html>
133dnl POSIX:2018 says regarding mbrtowc: "In the POSIX locale an [EILSEQ] error
134dnl cannot occur since all byte values are valid characters." It is reasonable
135dnl to expect mbrtoc32 to behave in the same way.
136
137AC_DEFUN([gl_MBRTOC32_C_LOCALE],
138[
139 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
140 AC_CACHE_CHECK([whether the C locale is free of encoding errors],
141 [gl_cv_func_mbrtoc32_C_locale_sans_EILSEQ],
142 [AC_RUN_IFELSE(
143 [AC_LANG_PROGRAM(
144 [[#include <limits.h>
145 #include <locale.h>
146 #ifdef __HAIKU__
147 #include <stdint.h>
148 #endif
149 #include <uchar.h>
150 ]], [[
151 int i;
152 char *locale = setlocale (LC_ALL, "C");
153 if (! locale)
154 return 2;
155 for (i = CHAR_MIN; i <= CHAR_MAX; i++)
156 {
157 char c = i;
158 char32_t wc;
159 mbstate_t mbs = { 0, };
160 size_t ss = mbrtoc32 (&wc, &c, 1, &mbs);
161 if (1 < ss)
162 return 3;
163 }
164 return 0;
165 ]])],
166 [gl_cv_func_mbrtoc32_C_locale_sans_EILSEQ=yes],
167 [gl_cv_func_mbrtoc32_C_locale_sans_EILSEQ=no],
168 [case "$host_os" in
169 # Guess yes on native Windows.
170 mingw* | windows*) gl_cv_func_mbrtoc32_C_locale_sans_EILSEQ="guessing yes" ;;
171 *) gl_cv_func_mbrtoc32_C_locale_sans_EILSEQ="$gl_cross_guess_normal" ;;
172 esac
173 ])
174 ])
175])
176
177dnl Test whether mbrtoc32 works when it's fed the bytes one-by-one in an UTF-8
178dnl locale.
179
180AC_DEFUN([gl_MBRTOC32_UTF8_LOCALE],
181[
182 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
183 AC_CACHE_CHECK([whether mbrtoc32 works in an UTF-8 locale],
184 [gl_cv_func_mbrtoc32_utf8_locale_works],
185 [AC_RUN_IFELSE(
186 [AC_LANG_PROGRAM(
187 [[#include <locale.h>
188 #ifdef __HAIKU__
189 #include <stdint.h>
190 #endif
191 #include <uchar.h>
192 ]], [[
193 char *locale = setlocale (LC_ALL, "en_US.UTF-8");
194 if (locale)
195 {
196 /* This test fails on Cygwin 3.5.3. */
197 mbstate_t state = { 0, };
198 char32_t uc = 0xDEADBEEF;
199 /* \360\237\220\203 = U+0001F403 */
200 if (mbrtoc32 (&uc, "\360", 1, &state) != (size_t)-2)
201 return 1;
202 if (mbrtoc32 (&uc, "\237", 1, &state) != (size_t)-2)
203 return 2;
204 if (mbrtoc32 (&uc, "\220", 1, &state) != (size_t)-2)
205 return 3;
206 if (mbrtoc32 (&uc, "\203", 1, &state) != 1)
207 return 4;
208 if (uc != 0x0001F403)
209 return 5;
210 }
211 return 0;
212 ]])],
213 [gl_cv_func_mbrtoc32_utf8_locale_works=yes],
214 [gl_cv_func_mbrtoc32_utf8_locale_works=no],
215 [case "$host_os" in
216 # Guess no on Cygwin.
217 cygwin*) gl_cv_func_mbrtoc32_utf8_locale_works="guessing no" ;;
218 *) gl_cv_func_mbrtoc32_utf8_locale_works="$gl_cross_guess_normal" ;;
219 esac
220 ])
221 ])
222])
223
224dnl Test whether mbrtoc32 works not worse than mbrtowc.
225dnl Result is HAVE_WORKING_MBRTOC32.
226
227AC_DEFUN([gl_MBRTOC32_SANITYCHECK],
228[
229 AC_REQUIRE([AC_PROG_CC])
230 AC_REQUIRE([gl_TYPE_CHAR32_T])
231 AC_REQUIRE([gl_CHECK_FUNC_MBRTOC32])
232 AC_REQUIRE([gt_LOCALE_FR])
233 AC_REQUIRE([gt_LOCALE_ZH_CN])
234 AC_REQUIRE([AC_CANONICAL_HOST])
235 if test $GNULIBHEADERS_OVERRIDE_CHAR32_T = 1 || test $gl_cv_func_mbrtoc32 = no; then
236 HAVE_WORKING_MBRTOC32=0
237 else
238 AC_CACHE_CHECK([whether mbrtoc32 works as well as mbrtowc],
239 [gl_cv_func_mbrtoc32_sanitycheck],
240 [
241 dnl Initial guess, used when cross-compiling or when no suitable locale
242 dnl is present.
243changequote(,)dnl
244 case "$host_os" in
245 # Guess no on FreeBSD, Solaris, native Windows.
246 freebsd* | midnightbsd* | solaris* | mingw* | windows*)
247 gl_cv_func_mbrtoc32_sanitycheck="guessing no"
248 ;;
249 # Guess yes otherwise.
250 *)
251 gl_cv_func_mbrtoc32_sanitycheck="guessing yes"
252 ;;
253 esac
254changequote([,])dnl
255 if test $LOCALE_FR != none || test $LOCALE_ZH_CN != none; then
256 AC_RUN_IFELSE(
257 [AC_LANG_SOURCE([[
258#include <locale.h>
259#include <stdlib.h>
260#include <string.h>
261#include <wchar.h>
262#ifdef __HAIKU__
263 #include <stdint.h>
264#endif
265#include <uchar.h>
266int main ()
267{
268 int result = 0;
269 /* This fails on native Windows:
270 mbrtoc32 returns (size_t)-1.
271 mbrtowc returns 1 (correct). */
272 if (strcmp ("$LOCALE_FR", "none") != 0
273 && setlocale (LC_ALL, "$LOCALE_FR") != NULL)
274 {
275 mbstate_t state;
276 wchar_t wc = (wchar_t) 0xBADFACE;
277 memset (&state, '\0', sizeof (mbstate_t));
278 if (mbrtowc (&wc, "\374", 1, &state) == 1)
279 {
280 char32_t c32 = (wchar_t) 0xBADFACE;
281 memset (&state, '\0', sizeof (mbstate_t));
282 if (mbrtoc32 (&c32, "\374", 1, &state) != 1)
283 result |= 1;
284 }
285 }
286 /* This fails on FreeBSD 13.0 and Solaris 11.4:
287 mbrtoc32 returns (size_t)-2 or (size_t)-1.
288 mbrtowc returns 4 (correct). */
289 if (strcmp ("$LOCALE_ZH_CN", "none") != 0
290 && setlocale (LC_ALL, "$LOCALE_ZH_CN") != NULL)
291 {
292 mbstate_t state;
293 wchar_t wc = (wchar_t) 0xBADFACE;
294 memset (&state, '\0', sizeof (mbstate_t));
295 if (mbrtowc (&wc, "\224\071\375\067", 4, &state) == 4)
296 {
297 char32_t c32 = (wchar_t) 0xBADFACE;
298 memset (&state, '\0', sizeof (mbstate_t));
299 if (mbrtoc32 (&c32, "\224\071\375\067", 4, &state) != 4)
300 result |= 2;
301 }
302 }
303 return result;
304}]])],
305 [gl_cv_func_mbrtoc32_sanitycheck=yes],
306 [gl_cv_func_mbrtoc32_sanitycheck=no],
307 [:])
308 fi
309 ])
310 case "$gl_cv_func_mbrtoc32_sanitycheck" in
311 *yes)
312 HAVE_WORKING_MBRTOC32=1
313 AC_DEFINE([HAVE_WORKING_MBRTOC32], [1],
314 [Define if the mbrtoc32 function basically works.])
315 ;;
316 *) HAVE_WORKING_MBRTOC32=0 ;;
317 esac
318 fi
319 AC_SUBST([HAVE_WORKING_MBRTOC32])
320])
321
322# Prerequisites of lib/mbrtoc32.c and lib/lc-charset-dispatch.c.
323AC_DEFUN([gl_PREREQ_MBRTOC32], [
324 AC_REQUIRE([gl_C32RTOMB_SANITYCHECK])
325 :
326])
diff --git a/gl/m4/mbrtowc.m4 b/gl/m4/mbrtowc.m4
index 62c4fdb3..cc09a5fb 100644
--- a/gl/m4/mbrtowc.m4
+++ b/gl/m4/mbrtowc.m4
@@ -1,10 +1,11 @@
1# mbrtowc.m4 1# mbrtowc.m4
2# serial 44 -*- coding: utf-8 -*- 2# serial 46
3dnl Copyright (C) 2001-2002, 2004-2005, 2008-2024 Free Software Foundation, 3dnl Copyright (C) 2001-2002, 2004-2005, 2008-2025 Free Software Foundation,
4dnl Inc. 4dnl Inc.
5dnl This file is free software; the Free Software Foundation 5dnl This file is free software; the Free Software Foundation
6dnl gives unlimited permission to copy and/or distribute it, 6dnl gives unlimited permission to copy and/or distribute it,
7dnl with or without modifications, as long as this notice is preserved. 7dnl with or without modifications, as long as this notice is preserved.
8dnl This file is offered as-is, without any warranty.
8 9
9AC_DEFUN([gl_FUNC_MBRTOWC], 10AC_DEFUN([gl_FUNC_MBRTOWC],
10[ 11[
@@ -160,7 +161,7 @@ AC_DEFUN([gl_MBRTOWC_INCOMPLETE_STATE],
160[ 161[
161 AC_REQUIRE([AC_PROG_CC]) 162 AC_REQUIRE([AC_PROG_CC])
162 AC_REQUIRE([gt_LOCALE_JA]) 163 AC_REQUIRE([gt_LOCALE_JA])
163 AC_REQUIRE([gt_LOCALE_FR_UTF8]) 164 AC_REQUIRE([gt_LOCALE_EN_UTF8])
164 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles 165 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
165 AC_CACHE_CHECK([whether mbrtowc handles incomplete characters], 166 AC_CACHE_CHECK([whether mbrtowc handles incomplete characters],
166 [gl_cv_func_mbrtowc_incomplete_state], 167 [gl_cv_func_mbrtowc_incomplete_state],
@@ -200,7 +201,7 @@ int main ()
200 [gl_cv_func_mbrtowc_incomplete_state=no], 201 [gl_cv_func_mbrtowc_incomplete_state=no],
201 [:]) 202 [:])
202 else 203 else
203 if test $LOCALE_FR_UTF8 != none; then 204 if test "$LOCALE_EN_UTF8" != none; then
204 AC_RUN_IFELSE( 205 AC_RUN_IFELSE(
205 [AC_LANG_SOURCE([[ 206 [AC_LANG_SOURCE([[
206#include <locale.h> 207#include <locale.h>
@@ -208,7 +209,7 @@ int main ()
208#include <wchar.h> 209#include <wchar.h>
209int main () 210int main ()
210{ 211{
211 if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL) 212 if (setlocale (LC_ALL, "$LOCALE_EN_UTF8") != NULL)
212 { 213 {
213 const char input[] = "B\303\274\303\237er"; /* "Büßer" */ 214 const char input[] = "B\303\274\303\237er"; /* "Büßer" */
214 mbstate_t state; 215 mbstate_t state;
@@ -288,7 +289,7 @@ dnl Result is gl_cv_func_mbrtowc_null_arg1.
288AC_DEFUN([gl_MBRTOWC_NULL_ARG1], 289AC_DEFUN([gl_MBRTOWC_NULL_ARG1],
289[ 290[
290 AC_REQUIRE([AC_PROG_CC]) 291 AC_REQUIRE([AC_PROG_CC])
291 AC_REQUIRE([gt_LOCALE_FR_UTF8]) 292 AC_REQUIRE([gt_LOCALE_EN_UTF8])
292 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles 293 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
293 AC_CACHE_CHECK([whether mbrtowc handles a NULL pwc argument], 294 AC_CACHE_CHECK([whether mbrtowc handles a NULL pwc argument],
294 [gl_cv_func_mbrtowc_null_arg1], 295 [gl_cv_func_mbrtowc_null_arg1],
@@ -303,7 +304,7 @@ changequote(,)dnl
303 *) gl_cv_func_mbrtowc_null_arg1="guessing yes" ;; 304 *) gl_cv_func_mbrtowc_null_arg1="guessing yes" ;;
304 esac 305 esac
305changequote([,])dnl 306changequote([,])dnl
306 if test $LOCALE_FR_UTF8 != none; then 307 if test "$LOCALE_EN_UTF8" != none; then
307 AC_RUN_IFELSE( 308 AC_RUN_IFELSE(
308 [AC_LANG_SOURCE([[ 309 [AC_LANG_SOURCE([[
309#include <locale.h> 310#include <locale.h>
@@ -314,7 +315,7 @@ int main ()
314{ 315{
315 int result = 0; 316 int result = 0;
316 317
317 if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL) 318 if (setlocale (LC_ALL, "$LOCALE_EN_UTF8") != NULL)
318 { 319 {
319 char input[] = "\303\237er"; 320 char input[] = "\303\237er";
320 mbstate_t state; 321 mbstate_t state;
@@ -351,7 +352,7 @@ dnl Result is gl_cv_func_mbrtowc_null_arg2.
351AC_DEFUN([gl_MBRTOWC_NULL_ARG2], 352AC_DEFUN([gl_MBRTOWC_NULL_ARG2],
352[ 353[
353 AC_REQUIRE([AC_PROG_CC]) 354 AC_REQUIRE([AC_PROG_CC])
354 AC_REQUIRE([gt_LOCALE_FR_UTF8]) 355 AC_REQUIRE([gt_LOCALE_EN_UTF8])
355 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles 356 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
356 AC_CACHE_CHECK([whether mbrtowc handles a NULL string argument], 357 AC_CACHE_CHECK([whether mbrtowc handles a NULL string argument],
357 [gl_cv_func_mbrtowc_null_arg2], 358 [gl_cv_func_mbrtowc_null_arg2],
@@ -366,7 +367,7 @@ changequote(,)dnl
366 *) gl_cv_func_mbrtowc_null_arg2="guessing yes" ;; 367 *) gl_cv_func_mbrtowc_null_arg2="guessing yes" ;;
367 esac 368 esac
368changequote([,])dnl 369changequote([,])dnl
369 if test $LOCALE_FR_UTF8 != none; then 370 if test "$LOCALE_EN_UTF8" != none; then
370 AC_RUN_IFELSE( 371 AC_RUN_IFELSE(
371 [AC_LANG_SOURCE([[ 372 [AC_LANG_SOURCE([[
372#include <locale.h> 373#include <locale.h>
@@ -374,7 +375,7 @@ changequote([,])dnl
374#include <wchar.h> 375#include <wchar.h>
375int main () 376int main ()
376{ 377{
377 if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL) 378 if (setlocale (LC_ALL, "$LOCALE_EN_UTF8") != NULL)
378 { 379 {
379 mbstate_t state; 380 mbstate_t state;
380 wchar_t wc; 381 wchar_t wc;
@@ -404,7 +405,7 @@ dnl Result is gl_cv_func_mbrtowc_retval.
404AC_DEFUN([gl_MBRTOWC_RETVAL], 405AC_DEFUN([gl_MBRTOWC_RETVAL],
405[ 406[
406 AC_REQUIRE([AC_PROG_CC]) 407 AC_REQUIRE([AC_PROG_CC])
407 AC_REQUIRE([gt_LOCALE_FR_UTF8]) 408 AC_REQUIRE([gt_LOCALE_EN_UTF8])
408 AC_REQUIRE([gt_LOCALE_JA]) 409 AC_REQUIRE([gt_LOCALE_JA])
409 AC_REQUIRE([AC_CANONICAL_HOST]) 410 AC_REQUIRE([AC_CANONICAL_HOST])
410 AC_CACHE_CHECK([whether mbrtowc has a correct return value], 411 AC_CACHE_CHECK([whether mbrtowc has a correct return value],
@@ -422,7 +423,7 @@ changequote(,)dnl
422 gl_cv_func_mbrtowc_retval="guessing yes" ;; 423 gl_cv_func_mbrtowc_retval="guessing yes" ;;
423 esac 424 esac
424changequote([,])dnl 425changequote([,])dnl
425 if test $LOCALE_FR_UTF8 != none || test $LOCALE_JA != none \ 426 if test "$LOCALE_EN_UTF8" != none || test $LOCALE_JA != none \
426 || { case "$host_os" in mingw* | windows*) true;; *) false;; esac; }; then 427 || { case "$host_os" in mingw* | windows*) true;; *) false;; esac; }; then
427 AC_RUN_IFELSE( 428 AC_RUN_IFELSE(
428 [AC_LANG_SOURCE([[ 429 [AC_LANG_SOURCE([[
@@ -434,8 +435,8 @@ int main ()
434 int result = 0; 435 int result = 0;
435 int found_some_locale = 0; 436 int found_some_locale = 0;
436 /* This fails on Solaris. */ 437 /* This fails on Solaris. */
437 if (strcmp ("$LOCALE_FR_UTF8", "none") != 0 438 if (strcmp ("$LOCALE_EN_UTF8", "none") != 0
438 && setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL) 439 && setlocale (LC_ALL, "$LOCALE_EN_UTF8") != NULL)
439 { 440 {
440 char input[] = "B\303\274\303\237er"; /* "Büßer" */ 441 char input[] = "B\303\274\303\237er"; /* "Büßer" */
441 mbstate_t state; 442 mbstate_t state;
@@ -649,8 +650,8 @@ int main ()
649 [:]) 650 [:])
650 ;; 651 ;;
651 *) 652 *)
652 AC_REQUIRE([gt_LOCALE_FR_UTF8]) 653 AC_REQUIRE([gt_LOCALE_EN_UTF8])
653 if test $LOCALE_FR_UTF8 != none; then 654 if test "$LOCALE_EN_UTF8" != none; then
654 AC_RUN_IFELSE( 655 AC_RUN_IFELSE(
655 [AC_LANG_SOURCE([[ 656 [AC_LANG_SOURCE([[
656#include <locale.h> 657#include <locale.h>
@@ -658,7 +659,7 @@ int main ()
658#include <wchar.h> 659#include <wchar.h>
659int main () 660int main ()
660{ 661{
661 if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL) 662 if (setlocale (LC_ALL, "$LOCALE_EN_UTF8") != NULL)
662 { 663 {
663 wchar_t wc = (wchar_t) 0xBADFACE; 664 wchar_t wc = (wchar_t) 0xBADFACE;
664 mbstate_t state; 665 mbstate_t state;
diff --git a/gl/m4/mbsinit.m4 b/gl/m4/mbsinit.m4
index 10c86ba9..69cfa574 100644
--- a/gl/m4/mbsinit.m4
+++ b/gl/m4/mbsinit.m4
@@ -1,9 +1,10 @@
1# mbsinit.m4 1# mbsinit.m4
2# serial 10 2# serial 10
3dnl Copyright (C) 2008, 2010-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2008, 2010-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_MBSINIT], 9AC_DEFUN([gl_FUNC_MBSINIT],
9[ 10[
diff --git a/gl/m4/mbstate_t.m4 b/gl/m4/mbstate_t.m4
index 66d65cd7..59df1e2e 100644
--- a/gl/m4/mbstate_t.m4
+++ b/gl/m4/mbstate_t.m4
@@ -1,9 +1,10 @@
1# mbstate_t.m4 1# mbstate_t.m4
2# serial 14 2# serial 14
3dnl Copyright (C) 2000-2002, 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2000-2002, 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# From Paul Eggert. 9# From Paul Eggert.
9 10
diff --git a/gl/m4/mbtowc.m4 b/gl/m4/mbtowc.m4
index 603b0c1a..3e3f6ce0 100644
--- a/gl/m4/mbtowc.m4
+++ b/gl/m4/mbtowc.m4
@@ -1,9 +1,10 @@
1# mbtowc.m4 1# mbtowc.m4
2# serial 5 2# serial 5
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2011-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_MBTOWC], 9AC_DEFUN([gl_FUNC_MBTOWC],
9[ 10[
diff --git a/gl/m4/memchr.m4 b/gl/m4/memchr.m4
index 346a2882..1c2ecf1d 100644
--- a/gl/m4/memchr.m4
+++ b/gl/m4/memchr.m4
@@ -1,9 +1,10 @@
1# memchr.m4 1# memchr.m4
2# serial 19 2# serial 20
3dnl Copyright (C) 2002-2004, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2002-2004, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN_ONCE([gl_FUNC_MEMCHR], 9AC_DEFUN_ONCE([gl_FUNC_MEMCHR],
9[ 10[
@@ -49,7 +50,7 @@ AC_DEFUN_ONCE([gl_FUNC_MEMCHR],
49 if (fd >= 0) 50 if (fd >= 0)
50# endif 51# endif
51 { 52 {
52 int pagesize = getpagesize (); 53 long int pagesize = sysconf (_SC_PAGESIZE);
53 char *two_pages = 54 char *two_pages =
54 (char *) mmap (NULL, 2 * pagesize, PROT_READ | PROT_WRITE, 55 (char *) mmap (NULL, 2 * pagesize, PROT_READ | PROT_WRITE,
55 flags, fd, 0); 56 flags, fd, 0);
diff --git a/gl/m4/minmax.m4 b/gl/m4/minmax.m4
index bc7d0c34..69c8a89f 100644
--- a/gl/m4/minmax.m4
+++ b/gl/m4/minmax.m4
@@ -1,9 +1,10 @@
1# minmax.m4 1# minmax.m4
2# serial 4 2# serial 4
3dnl Copyright (C) 2005, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2005, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_PREREQ([2.53]) 9AC_PREREQ([2.53])
9 10
diff --git a/gl/m4/mktime.m4 b/gl/m4/mktime.m4
index 85c52454..eca6c4d8 100644
--- a/gl/m4/mktime.m4
+++ b/gl/m4/mktime.m4
@@ -1,9 +1,11 @@
1# mktime.m4 1# mktime.m4
2# serial 39 2# serial 42
3dnl Copyright (C) 2002-2003, 2005-2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2002-2003, 2005-2007, 2009-2025 Free Software Foundation,
4dnl Inc.
4dnl This file is free software; the Free Software Foundation 5dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 6dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 7dnl with or without modifications, as long as this notice is preserved.
8dnl This file is offered as-is, without any warranty.
7 9
8dnl From Jim Meyering. 10dnl From Jim Meyering.
9 11
diff --git a/gl/m4/mmap-anon.m4 b/gl/m4/mmap-anon.m4
index 61ca0120..3f7a6656 100644
--- a/gl/m4/mmap-anon.m4
+++ b/gl/m4/mmap-anon.m4
@@ -1,9 +1,10 @@
1# mmap-anon.m4 1# mmap-anon.m4
2# serial 12 2# serial 12
3dnl Copyright (C) 2005, 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2005, 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Detect how mmap can be used to create anonymous (not file-backed) memory 9# Detect how mmap can be used to create anonymous (not file-backed) memory
9# mappings. 10# mappings.
diff --git a/gl/m4/mode_t.m4 b/gl/m4/mode_t.m4
index 0d5c2808..7dae201b 100644
--- a/gl/m4/mode_t.m4
+++ b/gl/m4/mode_t.m4
@@ -1,9 +1,10 @@
1# mode_t.m4 1# mode_t.m4
2# serial 2 2# serial 2
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# For using mode_t, it's sufficient to use AC_TYPE_MODE_T and 9# For using mode_t, it's sufficient to use AC_TYPE_MODE_T and
9# include <sys/types.h>. 10# include <sys/types.h>.
diff --git a/gl/m4/mountlist.m4 b/gl/m4/mountlist.m4
index ff414e66..e7eac2e9 100644
--- a/gl/m4/mountlist.m4
+++ b/gl/m4/mountlist.m4
@@ -1,9 +1,10 @@
1# mountlist.m4 1# mountlist.m4
2# serial 17 2# serial 18
3dnl Copyright (C) 2002-2006, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2002-2006, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Jim Meyering. 9dnl From Jim Meyering.
9 10
@@ -318,12 +319,17 @@ int getmntinfo (struct statfs **, int);
318 fi 319 fi
319 320
320 if test -z "$ac_list_mounted_fs"; then 321 if test -z "$ac_list_mounted_fs"; then
321 AC_MSG_ERROR([could not determine how to read list of mounted file systems]) 322 case "$host_os" in
322 # FIXME -- no need to abort building the whole package 323 mingw* | windows*) ac_list_mounted_fs=found ;;
323 # Can't build mountlist.c or anything that needs its functions 324 esac
325 fi
326
327 if test -z "$ac_list_mounted_fs"; then
328 AC_DEFINE([MOUNTED_NOT_PORTED], [1],
329 [Define if we don't know how to determine the list of mounted file systems.])
324 fi 330 fi
325 331
326 if test $ac_list_mounted_fs = found; then 332 if test "$ac_list_mounted_fs" = found; then
327 gl_cv_list_mounted_fs=yes 333 gl_cv_list_mounted_fs=yes
328 else 334 else
329 gl_cv_list_mounted_fs=no 335 gl_cv_list_mounted_fs=no
diff --git a/gl/m4/msvc-inval.m4 b/gl/m4/msvc-inval.m4
index 7919ff12..bfbb983b 100644
--- a/gl/m4/msvc-inval.m4
+++ b/gl/m4/msvc-inval.m4
@@ -1,9 +1,10 @@
1# msvc-inval.m4 1# msvc-inval.m4
2# serial 1 2# serial 1
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2011-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_MSVC_INVAL], 9AC_DEFUN([gl_MSVC_INVAL],
9[ 10[
diff --git a/gl/m4/msvc-nothrow.m4 b/gl/m4/msvc-nothrow.m4
index 007c7620..6a470971 100644
--- a/gl/m4/msvc-nothrow.m4
+++ b/gl/m4/msvc-nothrow.m4
@@ -1,9 +1,10 @@
1# msvc-nothrow.m4 1# msvc-nothrow.m4
2# serial 1 2# serial 1
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2011-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_MSVC_NOTHROW], 9AC_DEFUN([gl_MSVC_NOTHROW],
9[ 10[
diff --git a/gl/m4/multiarch.m4 b/gl/m4/multiarch.m4
index 3af29d39..817f01f1 100644
--- a/gl/m4/multiarch.m4
+++ b/gl/m4/multiarch.m4
@@ -1,9 +1,10 @@
1# multiarch.m4 1# multiarch.m4
2# serial 9 2# serial 9
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Determine whether the compiler is or may be producing universal binaries. 9# Determine whether the compiler is or may be producing universal binaries.
9# 10#
diff --git a/gl/m4/musl.m4 b/gl/m4/musl.m4
index 0d4de892..6ff778cb 100644
--- a/gl/m4/musl.m4
+++ b/gl/m4/musl.m4
@@ -1,9 +1,10 @@
1# musl.m4 1# musl.m4
2# serial 4 2# serial 4
3dnl Copyright (C) 2019-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2019-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Test for musl libc, despite the musl libc authors don't like it 9# Test for musl libc, despite the musl libc authors don't like it
9# <https://wiki.musl-libc.org/faq.html> 10# <https://wiki.musl-libc.org/faq.html>
diff --git a/gl/m4/netdb_h.m4 b/gl/m4/netdb_h.m4
index d8c00217..88512546 100644
--- a/gl/m4/netdb_h.m4
+++ b/gl/m4/netdb_h.m4
@@ -1,9 +1,10 @@
1# netdb_h.m4 1# netdb_h.m4
2# serial 15 2# serial 15
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN_ONCE([gl_NETDB_H], 9AC_DEFUN_ONCE([gl_NETDB_H],
9[ 10[
diff --git a/gl/m4/netinet_in_h.m4 b/gl/m4/netinet_in_h.m4
index 926f7f95..b56e354c 100644
--- a/gl/m4/netinet_in_h.m4
+++ b/gl/m4/netinet_in_h.m4
@@ -1,9 +1,10 @@
1# netinet_in_h.m4 1# netinet_in_h.m4
2# serial 6 2# serial 6
3dnl Copyright (C) 2006-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2006-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_HEADER_NETINET_IN], 9AC_DEFUN([gl_HEADER_NETINET_IN],
9[ 10[
diff --git a/gl/m4/nl_langinfo.m4 b/gl/m4/nl_langinfo.m4
index f38f11bb..9b1e0f32 100644
--- a/gl/m4/nl_langinfo.m4
+++ b/gl/m4/nl_langinfo.m4
@@ -1,9 +1,10 @@
1# nl_langinfo.m4 1# nl_langinfo.m4
2# serial 11 2# serial 12.1
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_NL_LANGINFO], 9AC_DEFUN([gl_FUNC_NL_LANGINFO],
9[ 10[
@@ -40,16 +41,18 @@ AC_DEFUN([gl_FUNC_NL_LANGINFO],
40 AC_DEFINE_UNQUOTED([FUNC_NL_LANGINFO_YESEXPR_WORKS], 41 AC_DEFINE_UNQUOTED([FUNC_NL_LANGINFO_YESEXPR_WORKS],
41 [$FUNC_NL_LANGINFO_YESEXPR_WORKS], 42 [$FUNC_NL_LANGINFO_YESEXPR_WORKS],
42 [Define to 1 if nl_langinfo (YESEXPR) returns a non-empty string.]) 43 [Define to 1 if nl_langinfo (YESEXPR) returns a non-empty string.])
43 # On Solaris 10 and Solaris 11.3, nl_langinfo is not multithread-safe. 44 # On macOS 26, Solaris 10, and Solaris 11.3, nl_langinfo is not
45 # multithread-safe.
44 case "$host_os" in 46 case "$host_os" in
45 solaris*) NL_LANGINFO_MTSAFE=0 ;; 47 darwin* | solaris*) NL_LANGINFO_MTSAFE=0 ;;
46 *) NL_LANGINFO_MTSAFE=1 ;; 48 *) NL_LANGINFO_MTSAFE=1 ;;
47 esac 49 esac
48 AC_DEFINE_UNQUOTED([NL_LANGINFO_MTSAFE], [$NL_LANGINFO_MTSAFE], 50 AC_DEFINE_UNQUOTED([NL_LANGINFO_MTSAFE], [$NL_LANGINFO_MTSAFE],
49 [Define to 1 if nl_langinfo is multithread-safe.]) 51 [Define to 1 if nl_langinfo is multithread-safe.])
50 if test $HAVE_LANGINFO_CODESET = 1 \ 52 if test $HAVE_LANGINFO_CODESET = 1 \
51 && test $HAVE_LANGINFO_T_FMT_AMPM = 1 \ 53 && test $HAVE_LANGINFO_T_FMT_AMPM = 1 \
52 && test $HAVE_LANGINFO_ALTMON = 1 \ 54 && test $HAVE_LANGINFO_ALTMON = 1 \
55 && test $HAVE_LANGINFO_ABALTMON = 1 \
53 && test $HAVE_LANGINFO_ERA = 1 \ 56 && test $HAVE_LANGINFO_ERA = 1 \
54 && test $FUNC_NL_LANGINFO_YESEXPR_WORKS = 1 \ 57 && test $FUNC_NL_LANGINFO_YESEXPR_WORKS = 1 \
55 && test $NL_LANGINFO_MTSAFE = 1; then 58 && test $NL_LANGINFO_MTSAFE = 1; then
diff --git a/gl/m4/nocrash.m4 b/gl/m4/nocrash.m4
index cbe8fe82..662fb049 100644
--- a/gl/m4/nocrash.m4
+++ b/gl/m4/nocrash.m4
@@ -1,9 +1,10 @@
1# nocrash.m4 1# nocrash.m4
2# serial 5 2# serial 5
3dnl Copyright (C) 2005, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2005, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Based on libsigsegv, from Bruno Haible and Paolo Bonzini. 9dnl Based on libsigsegv, from Bruno Haible and Paolo Bonzini.
9 10
diff --git a/gl/m4/off64_t.m4 b/gl/m4/off64_t.m4
new file mode 100644
index 00000000..963d53e9
--- /dev/null
+++ b/gl/m4/off64_t.m4
@@ -0,0 +1,32 @@
1# off64_t.m4
2# serial 1
3dnl Copyright (C) 2024-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9dnl Check whether <sys/types.h> defines the 'off64_t' type.
10dnl Set HAVE_OFF64_T.
11
12AC_DEFUN([gl_TYPE_OFF64_T],
13[
14 dnl Persuade glibc <sys/types.h>, <stdio.h>, <fcntl.h>, <unistd.h>, <aio.h>
15 dnl to define off64_t.
16 AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
17
18 AC_CACHE_CHECK([for off64_t], [gl_cv_off64_t],
19 [AC_COMPILE_IFELSE(
20 [AC_LANG_PROGRAM(
21 [[#include <sys/types.h>]],
22 [[int x = sizeof (off64_t *) + sizeof (off64_t);
23 return !x;]])],
24 [gl_cv_off64_t=yes], [gl_cv_off64_t=no])])
25
26 if test $gl_cv_off64_t != no; then
27 HAVE_OFF64_T=1
28 else
29 HAVE_OFF64_T=0
30 fi
31 AC_SUBST([HAVE_OFF64_T])
32])
diff --git a/gl/m4/off_t.m4 b/gl/m4/off_t.m4
index db6035db..f4f4bbf6 100644
--- a/gl/m4/off_t.m4
+++ b/gl/m4/off_t.m4
@@ -1,9 +1,10 @@
1# off_t.m4 1# off_t.m4
2# serial 1 2# serial 1
3dnl Copyright (C) 2012-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2012-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Check whether to override the 'off_t' type. 9dnl Check whether to override the 'off_t' type.
9dnl Set WINDOWS_64_BIT_OFF_T. 10dnl Set WINDOWS_64_BIT_OFF_T.
diff --git a/gl/m4/once.m4 b/gl/m4/once.m4
new file mode 100644
index 00000000..7876a8fe
--- /dev/null
+++ b/gl/m4/once.m4
@@ -0,0 +1,14 @@
1# once.m4
2# serial 1
3dnl Copyright (C) 2024-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9dnl From Bruno Haible.
10
11AC_DEFUN([gl_ONCE],
12[
13 AC_REQUIRE([gl_THREADLIB])
14])
diff --git a/gl/m4/open-cloexec.m4 b/gl/m4/open-cloexec.m4
index 6defdfb4..860541b0 100644
--- a/gl/m4/open-cloexec.m4
+++ b/gl/m4/open-cloexec.m4
@@ -1,9 +1,10 @@
1# open-cloexec.m4 1# open-cloexec.m4
2# serial 1 2# serial 1
3dnl Copyright 2017-2024 Free Software Foundation, Inc. 3dnl Copyright 2017-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Test whether O_CLOEXEC is defined. 9# Test whether O_CLOEXEC is defined.
9 10
diff --git a/gl/m4/open-slash.m4 b/gl/m4/open-slash.m4
index 03460e42..2cba48fe 100644
--- a/gl/m4/open-slash.m4
+++ b/gl/m4/open-slash.m4
@@ -1,9 +1,10 @@
1# open-slash.m4 1# open-slash.m4
2# serial 2 2# serial 2
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Tests whether open() and creat() recognize a trailing slash. 9dnl Tests whether open() and creat() recognize a trailing slash.
9dnl Sets gl_cv_func_open_slash. 10dnl Sets gl_cv_func_open_slash.
diff --git a/gl/m4/open.m4 b/gl/m4/open.m4
index 62a11a11..dd3a805f 100644
--- a/gl/m4/open.m4
+++ b/gl/m4/open.m4
@@ -1,14 +1,18 @@
1# open.m4 1# open.m4
2# serial 16 2# serial 17
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_OPEN], 9AC_DEFUN([gl_FUNC_OPEN],
9[ 10[
10 AC_REQUIRE([AC_CANONICAL_HOST]) 11 AC_REQUIRE([AC_CANONICAL_HOST])
11 AC_REQUIRE([gl_PREPROC_O_CLOEXEC]) 12 AC_REQUIRE([gl_PREPROC_O_CLOEXEC])
13 AC_REQUIRE([gl_FCNTL_O_FLAGS])
14 AS_CASE([$gl_cv_header_working_fcntl_h],
15 [*O_DIRECTORY* | *no], [REPLACE_OPEN=1])
12 case "$host_os" in 16 case "$host_os" in
13 mingw* | windows* | pw*) 17 mingw* | windows* | pw*)
14 REPLACE_OPEN=1 18 REPLACE_OPEN=1
diff --git a/gl/m4/pathmax.m4 b/gl/m4/pathmax.m4
index 4280837f..0c3925df 100644
--- a/gl/m4/pathmax.m4
+++ b/gl/m4/pathmax.m4
@@ -1,10 +1,11 @@
1# pathmax.m4 1# pathmax.m4
2# serial 11 2# serial 11
3dnl Copyright (C) 2002-2003, 2005-2006, 2009-2024 Free Software Foundation, 3dnl Copyright (C) 2002-2003, 2005-2006, 2009-2025 Free Software Foundation,
4dnl Inc. 4dnl Inc.
5dnl This file is free software; the Free Software Foundation 5dnl This file is free software; the Free Software Foundation
6dnl gives unlimited permission to copy and/or distribute it, 6dnl gives unlimited permission to copy and/or distribute it,
7dnl with or without modifications, as long as this notice is preserved. 7dnl with or without modifications, as long as this notice is preserved.
8dnl This file is offered as-is, without any warranty.
8 9
9AC_DEFUN([gl_PATHMAX], 10AC_DEFUN([gl_PATHMAX],
10[ 11[
diff --git a/gl/m4/pid_t.m4 b/gl/m4/pid_t.m4
index 8bedcc6b..a8bdabc2 100644
--- a/gl/m4/pid_t.m4
+++ b/gl/m4/pid_t.m4
@@ -1,9 +1,10 @@
1# pid_t.m4 1# pid_t.m4
2# serial 4 2# serial 4
3dnl Copyright (C) 2020-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2020-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# The following implementation works around a problem in autoconf <= 2.69. 9# The following implementation works around a problem in autoconf <= 2.69.
9m4_version_prereq([2.70], [], [ 10m4_version_prereq([2.70], [], [
diff --git a/gl/m4/printf.m4 b/gl/m4/printf.m4
index 0cb14d6f..4619a402 100644
--- a/gl/m4/printf.m4
+++ b/gl/m4/printf.m4
@@ -1,9 +1,10 @@
1# printf.m4 1# printf.m4
2# serial 91 2# serial 96
3dnl Copyright (C) 2003, 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2003, 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Test whether the *printf family of functions supports the 'j', 'z', 't', 9dnl Test whether the *printf family of functions supports the 'j', 'z', 't',
9dnl 'L' size specifiers. (ISO C99, POSIX:2001) 10dnl 'L' size specifiers. (ISO C99, POSIX:2001)
@@ -616,6 +617,7 @@ static double zero = 0.0;
616int main () 617int main ()
617{ 618{
618 int result = 0; 619 int result = 0;
620 /* This fails on FreeBSD 5.2.1, Solaris 11.4. */
619 if (sprintf (buf, "%a %d", 3.1416015625, 33, 44, 55) < 0 621 if (sprintf (buf, "%a %d", 3.1416015625, 33, 44, 55) < 0
620 || (strcmp (buf, "0x1.922p+1 33") != 0 622 || (strcmp (buf, "0x1.922p+1 33") != 0
621 && strcmp (buf, "0x3.244p+0 33") != 0 623 && strcmp (buf, "0x3.244p+0 33") != 0
@@ -627,27 +629,29 @@ int main ()
627 && strcmp (buf, "-0X3.244P+0 33") != 0 629 && strcmp (buf, "-0X3.244P+0 33") != 0
628 && strcmp (buf, "-0X6.488P-1 33") != 0 630 && strcmp (buf, "-0X6.488P-1 33") != 0
629 && strcmp (buf, "-0XC.91P-2 33") != 0)) 631 && strcmp (buf, "-0XC.91P-2 33") != 0))
630 result |= 2; 632 result |= 1;
631 /* This catches a FreeBSD 13.0 bug: it doesn't round. */ 633 /* This catches a Mac OS X 10.5, FreeBSD 6.4, NetBSD 10.0 bug:
634 it doesn't round. */
632 if (sprintf (buf, "%.2a %d", 1.51, 33, 44, 55) < 0 635 if (sprintf (buf, "%.2a %d", 1.51, 33, 44, 55) < 0
633 || (strcmp (buf, "0x1.83p+0 33") != 0 636 || (strcmp (buf, "0x1.83p+0 33") != 0
634 && strcmp (buf, "0x3.05p-1 33") != 0 637 && strcmp (buf, "0x3.05p-1 33") != 0
635 && strcmp (buf, "0x6.0ap-2 33") != 0 638 && strcmp (buf, "0x6.0ap-2 33") != 0
636 && strcmp (buf, "0xc.14p-3 33") != 0)) 639 && strcmp (buf, "0xc.14p-3 33") != 0))
637 result |= 4; 640 result |= 2;
638 /* This catches a Mac OS X 10.12.4 (Darwin 16.5) bug: it doesn't round. */ 641 /* This catches a macOS 14 (Darwin 23), FreeBSD 14.0, OpenBSD 7.5, AIX 7.3,
642 Solaris 11.4 bug: it doesn't round. */
639 if (sprintf (buf, "%.0a %d", 1.51, 33, 44, 55) < 0 643 if (sprintf (buf, "%.0a %d", 1.51, 33, 44, 55) < 0
640 || (strcmp (buf, "0x2p+0 33") != 0 644 || (strcmp (buf, "0x2p+0 33") != 0
641 && strcmp (buf, "0x3p-1 33") != 0 645 && strcmp (buf, "0x3p-1 33") != 0
642 && strcmp (buf, "0x6p-2 33") != 0 646 && strcmp (buf, "0x6p-2 33") != 0
643 && strcmp (buf, "0xcp-3 33") != 0)) 647 && strcmp (buf, "0xcp-3 33") != 0))
644 result |= 4; 648 result |= 4;
645 /* This catches a FreeBSD 6.1 bug. See 649 /* This catches a Mac OS X 10.5, FreeBSD 6.4 bug. See
646 <https://lists.gnu.org/r/bug-gnulib/2007-04/msg00107.html> */ 650 <https://lists.gnu.org/r/bug-gnulib/2007-04/msg00107.html> */
647 if (sprintf (buf, "%010a %d", 1.0 / zero, 33, 44, 55) < 0 651 if (sprintf (buf, "%010a %d", 1.0 / zero, 33, 44, 55) < 0
648 || buf[0] == '0') 652 || buf[0] == '0')
649 result |= 8; 653 result |= 8;
650 /* This catches a Mac OS X 10.3.9 (Darwin 7.9) bug. */ 654 /* This catches a Mac OS X 10.3.9 (Darwin 7.9), FreeBSD 6.4 bug. */
651 if (sprintf (buf, "%.1a", 1.999) < 0 655 if (sprintf (buf, "%.1a", 1.999) < 0
652 || (strcmp (buf, "0x1.0p+1") != 0 656 || (strcmp (buf, "0x1.0p+1") != 0
653 && strcmp (buf, "0x2.0p+0") != 0 657 && strcmp (buf, "0x2.0p+0") != 0
@@ -655,7 +659,8 @@ int main ()
655 && strcmp (buf, "0x8.0p-2") != 0)) 659 && strcmp (buf, "0x8.0p-2") != 0))
656 result |= 16; 660 result |= 16;
657 /* This catches the same Mac OS X 10.3.9 (Darwin 7.9) bug and also a 661 /* This catches the same Mac OS X 10.3.9 (Darwin 7.9) bug and also a
658 glibc 2.4 bug <https://sourceware.org/bugzilla/show_bug.cgi?id=2908>. */ 662 glibc 2.4 bug <https://sourceware.org/bugzilla/show_bug.cgi?id=2908>
663 and a FreeBSD 6.4, NetBSD 10.0 bug. */
659 if (sprintf (buf, "%.1La", 1.999L) < 0 664 if (sprintf (buf, "%.1La", 1.999L) < 0
660 || (strcmp (buf, "0x1.0p+1") != 0 665 || (strcmp (buf, "0x1.0p+1") != 0
661 && strcmp (buf, "0x2.0p+0") != 0 666 && strcmp (buf, "0x2.0p+0") != 0
@@ -893,9 +898,14 @@ AC_DEFUN([gl_PRINTF_DIRECTIVE_N],
893 [AC_LANG_SOURCE([[ 898 [AC_LANG_SOURCE([[
894#include <signal.h> 899#include <signal.h>
895#include <stdio.h> 900#include <stdio.h>
896#include <stdlib.h>
897#include <string.h> 901#include <string.h>
902#if defined _WIN32 && !defined __CYGWIN__
903# include <stdlib.h>
904#else
905# include <unistd.h>
906#endif
898#ifdef _MSC_VER 907#ifdef _MSC_VER
908#include <crtdbg.h>
899#include <inttypes.h> 909#include <inttypes.h>
900/* See page about "Parameter Validation" on msdn.microsoft.com. 910/* See page about "Parameter Validation" on msdn.microsoft.com.
901 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/parameter-validation> 911 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/parameter-validation>
@@ -922,6 +932,9 @@ int main ()
922 int count = -1; 932 int count = -1;
923#ifdef _MSC_VER 933#ifdef _MSC_VER
924 _set_invalid_parameter_handler (invalid_parameter_handler); 934 _set_invalid_parameter_handler (invalid_parameter_handler);
935 /* Also avoid an Abort/Retry/Ignore dialog in debug builds.
936 <https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/crtsetreportmode> */
937 _CrtSetReportMode (_CRT_ASSERT, 0);
925#endif 938#endif
926 signal (SIGABRT, abort_handler); 939 signal (SIGABRT, abort_handler);
927 /* Copy the format string. Some systems (glibc with _FORTIFY_SOURCE=2) 940 /* Copy the format string. Some systems (glibc with _FORTIFY_SOURCE=2)
@@ -1173,6 +1186,112 @@ changequote([,])dnl
1173 ]) 1186 ])
1174]) 1187])
1175 1188
1189dnl Test whether the *printf family of functions supports POSIX/XSI format
1190dnl strings with the ' flag for grouping of decimal digits on integers,
1191dnl together with a precision.
1192dnl Result is gl_cv_func_printf_flag_grouping_int_precision.
1193
1194AC_DEFUN([gl_PRINTF_FLAG_GROUPING_INT_PRECISION],
1195[
1196 AC_REQUIRE([AC_PROG_CC])
1197 AC_REQUIRE([AC_CANONICAL_HOST])
1198 AC_CACHE_CHECK([whether printf supports grouping on integers with a precision],
1199 [gl_cv_func_printf_flag_grouping_int_precision],
1200 [
1201 dnl Prepare a guess, used when cross-compiling or when specific locales
1202 dnl are not available.
1203 case "$host_os" in
1204 # Guess no on FreeBSD, NetBSD, Solaris, Cygwin, Haiku.
1205 freebsd* | dragonfly* | netbsd* | solaris* | cygwin* | haiku*)
1206 gl_cv_func_printf_flag_grouping_int_precision="guessing no";;
1207 *)
1208 gl_cv_func_printf_flag_grouping_int_precision="guessing yes";;
1209 esac
1210 AC_RUN_IFELSE(
1211 [AC_LANG_SOURCE([[
1212#include <locale.h>
1213#include <stdio.h>
1214#include <string.h>
1215static char buf[100];
1216int main ()
1217{
1218 if (setlocale (LC_ALL, "fr_FR.UTF-8") != NULL
1219 || setlocale (LC_ALL, "fr_FR") != NULL
1220 || setlocale (LC_ALL, "fr_FR.ISO-8859-1") != NULL
1221 || setlocale (LC_ALL, "fr_FR.ISO8859-1") != NULL)
1222 {
1223 if (sprintf (buf, "%'.10d", 1000) < 0)
1224 return 1;
1225 if (strlen (buf) == 10 && strcmp (buf, "0000001000") != 0)
1226 /* The sprintf implementation has produced fewer than 10 digits. */
1227 return 2;
1228 else
1229 return 0;
1230 }
1231 return 3;
1232}]])],
1233 [gl_cv_func_printf_flag_grouping_int_precision=yes],
1234 [if test $? = 2; then
1235 gl_cv_func_printf_flag_grouping_int_precision=no
1236 fi
1237 ],
1238 [:])
1239 ])
1240])
1241
1242dnl Test whether the *printf family of functions supports POSIX/XSI format
1243dnl strings with the ' flag for grouping of decimal digits, when the thousands
1244dnl separator is a multibyte character (such as U+00A0 or U+202F in a UTF-8
1245dnl locale).
1246dnl Result is gl_cv_func_printf_flag_grouping_multibyte.
1247
1248AC_DEFUN([gl_PRINTF_FLAG_GROUPING_MULTIBYTE],
1249[
1250 AC_REQUIRE([AC_PROG_CC])
1251 AC_REQUIRE([AC_CANONICAL_HOST])
1252 AC_CACHE_CHECK([whether printf supports grouping with a multibyte separator],
1253 [gl_cv_func_printf_flag_grouping_multibyte],
1254 [
1255 dnl Prepare a guess, used when cross-compiling or when specific locales
1256 dnl are not available.
1257 case "$host_os" in
1258 # Guess no on NetBSD and Solaris 11 OpenIndiana.
1259 netbsd* | solaris*)
1260 gl_cv_func_printf_flag_grouping_multibyte="guessing no";;
1261 *)
1262 gl_cv_func_printf_flag_grouping_multibyte="guessing yes";;
1263 esac
1264 AC_RUN_IFELSE(
1265 [AC_LANG_SOURCE([[
1266#include <locale.h>
1267#include <stdio.h>
1268#include <string.h>
1269static char buf[100];
1270int main ()
1271{
1272 if (setlocale (LC_ALL, "fr_FR.UTF-8") == NULL)
1273 return 0;
1274 if (sprintf (buf, "%'.0f", 1000.0) < 0)
1275 return 1;
1276 if (strlen (localeconv ()->thousands_sep) > 1)
1277 {
1278 if (strlen (buf) <= 4 + 1)
1279 return 2;
1280 else
1281 return 3;
1282 }
1283 return 0;
1284}]])],
1285 [:],
1286 [case $? in
1287 2) gl_cv_func_printf_flag_grouping_multibyte=no ;;
1288 3) gl_cv_func_printf_flag_grouping_multibyte=yes ;;
1289 esac
1290 ],
1291 [:])
1292 ])
1293])
1294
1176dnl Test whether the *printf family of functions supports the - flag correctly. 1295dnl Test whether the *printf family of functions supports the - flag correctly.
1177dnl (ISO C99.) See 1296dnl (ISO C99.) See
1178dnl <https://lists.gnu.org/r/bug-coreutils/2008-02/msg00035.html> 1297dnl <https://lists.gnu.org/r/bug-coreutils/2008-02/msg00035.html>
@@ -1709,6 +1828,11 @@ AC_DEFUN([gl_SNPRINTF_DIRECTIVE_N],
1709#include <signal.h> 1828#include <signal.h>
1710#include <stdio.h> 1829#include <stdio.h>
1711#include <string.h> 1830#include <string.h>
1831#if defined _WIN32 && !defined __CYGWIN__
1832# include <stdlib.h>
1833#else
1834# include <unistd.h>
1835#endif
1712#if HAVE_SNPRINTF 1836#if HAVE_SNPRINTF
1713# define my_snprintf snprintf 1837# define my_snprintf snprintf
1714#else 1838#else
@@ -2143,20 +2267,22 @@ dnl 11 = gl_PRINTF_DIRECTIVE_LS
2143dnl 12 = gl_PRINTF_DIRECTIVE_LC 2267dnl 12 = gl_PRINTF_DIRECTIVE_LC
2144dnl 13 = gl_PRINTF_POSITIONS 2268dnl 13 = gl_PRINTF_POSITIONS
2145dnl 14 = gl_PRINTF_FLAG_GROUPING 2269dnl 14 = gl_PRINTF_FLAG_GROUPING
2146dnl 15 = gl_PRINTF_FLAG_LEFTADJUST 2270dnl 15 = gl_PRINTF_FLAG_GROUPING_INT_PRECISION
2147dnl 16 = gl_PRINTF_FLAG_ZERO 2271dnl 16 = gl_PRINTF_FLAG_GROUPING_MULTIBYTE
2148dnl 17 = gl_PRINTF_FLAG_ALT_PRECISION_ZERO 2272dnl 17 = gl_PRINTF_FLAG_LEFTADJUST
2149dnl 18 = gl_PRINTF_PRECISION 2273dnl 18 = gl_PRINTF_FLAG_ZERO
2150dnl 19 = gl_PRINTF_ENOMEM 2274dnl 19 = gl_PRINTF_FLAG_ALT_PRECISION_ZERO
2151dnl 20 = gl_SNPRINTF_PRESENCE 2275dnl 20 = gl_PRINTF_PRECISION
2152dnl 21 = gl_SNPRINTF_TRUNCATION_C99 2276dnl 21 = gl_PRINTF_ENOMEM
2153dnl 22 = gl_SNPRINTF_RETVAL_C99 2277dnl 22 = gl_SNPRINTF_PRESENCE
2154dnl 23 = gl_SNPRINTF_DIRECTIVE_N 2278dnl 23 = gl_SNPRINTF_TRUNCATION_C99
2155dnl 24 = gl_SNPRINTF_SIZE1 2279dnl 24 = gl_SNPRINTF_RETVAL_C99
2156dnl 25 = gl_VSNPRINTF_ZEROSIZE_C99 2280dnl 25 = gl_SNPRINTF_DIRECTIVE_N
2157dnl 26 = gl_SWPRINTF_WORKS 2281dnl 26 = gl_SNPRINTF_SIZE1
2158dnl 27 = gl_SWPRINTF_DIRECTIVE_LA 2282dnl 27 = gl_VSNPRINTF_ZEROSIZE_C99
2159dnl 28 = gl_SWPRINTF_DIRECTIVE_LC 2283dnl 28 = gl_SWPRINTF_WORKS
2284dnl 29 = gl_SWPRINTF_DIRECTIVE_LA
2285dnl 30 = gl_SWPRINTF_DIRECTIVE_LC
2160dnl 2286dnl
2161dnl 1 = checking whether printf supports size specifiers as in C99... 2287dnl 1 = checking whether printf supports size specifiers as in C99...
2162dnl 2 = checking whether printf supports size specifiers as in C23... 2288dnl 2 = checking whether printf supports size specifiers as in C23...
@@ -2172,62 +2298,64 @@ dnl 11 = checking whether printf supports the 'ls' directive...
2172dnl 12 = checking whether printf supports the 'lc' directive correctly... 2298dnl 12 = checking whether printf supports the 'lc' directive correctly...
2173dnl 13 = checking whether printf supports POSIX/XSI format strings with positions... 2299dnl 13 = checking whether printf supports POSIX/XSI format strings with positions...
2174dnl 14 = checking whether printf supports the grouping flag... 2300dnl 14 = checking whether printf supports the grouping flag...
2175dnl 15 = checking whether printf supports the left-adjust flag correctly... 2301dnl 15 = checking whether printf supports grouping on integers with a precision...
2176dnl 16 = checking whether printf supports the zero flag correctly... 2302dnl 16 = checking whether printf supports grouping with a multibyte separator...
2177dnl 17 = checking whether printf supports the alternative flag with a zero precision... 2303dnl 17 = checking whether printf supports the left-adjust flag correctly...
2178dnl 18 = checking whether printf supports large precisions... 2304dnl 18 = checking whether printf supports the zero flag correctly...
2179dnl 19 = checking whether printf survives out-of-memory conditions... 2305dnl 19 = checking whether printf supports the alternative flag with a zero precision...
2180dnl 20 = checking for snprintf... 2306dnl 20 = checking whether printf supports large precisions...
2181dnl 21 = checking whether snprintf truncates the result as in C99... 2307dnl 21 = checking whether printf survives out-of-memory conditions...
2182dnl 22 = checking whether snprintf returns a byte count as in C99... 2308dnl 22 = checking for snprintf...
2183dnl 23 = checking whether snprintf fully supports the 'n' directive... 2309dnl 23 = checking whether snprintf truncates the result as in C99...
2184dnl 24 = checking whether snprintf respects a size of 1... 2310dnl 24 = checking whether snprintf returns a byte count as in C99...
2185dnl 25 = checking whether vsnprintf respects a zero size as in C99... 2311dnl 25 = checking whether snprintf fully supports the 'n' directive...
2186dnl 26 = checking whether swprintf works... 2312dnl 26 = checking whether snprintf respects a size of 1...
2187dnl 27 = checking whether swprintf supports the 'La' and 'LA' directives... 2313dnl 27 = checking whether vsnprintf respects a zero size as in C99...
2188dnl 28 = checking whether swprintf supports the 'lc' directive... 2314dnl 28 = checking whether swprintf works...
2315dnl 29 = checking whether swprintf supports the 'La' and 'LA' directives...
2316dnl 30 = checking whether swprintf supports the 'lc' directive...
2189dnl 2317dnl
2190dnl . = yes, # = no. 2318dnl . = yes, # = no.
2191dnl 2319dnl
2192dnl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 2320dnl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
2193dnl musl libc 1.2.3 . # . . . . # # . . . # . . . . ? . . . . . . . . # . # 2321dnl musl libc 1.2.3 . # . . . . # # . . . # . . . . . . . . . . . . . . . # . #
2194dnl glibc 2.35 . # . . . . . . . . . . . . . . . . . . . . . . . . . . 2322dnl glibc 2.35 . # . . . . . . . . . . . . # . . . . . . . . . . . . . . .
2195dnl glibc 2.5 . # . . . . # # . . . . . . . . . . . . . . . . . . # . 2323dnl glibc 2.5 . # . . . . # # . . . . . . # . . . . . . . . . . . . . # .
2196dnl glibc 2.3.6 . # . . . # # # . . . . . . . . . . . . . . . . . . # . 2324dnl glibc 2.3.6 . # . . . # # # . . . . . . . . . . . . . . . . . . . . # .
2197dnl FreeBSD 14.0 . . . . . # . . . . . . . . . . . . # . . . . . . # . # 2325dnl FreeBSD 14.0 . . . . . # . . . . . . . . # . . . . . # . . . . . . # . #
2198dnl FreeBSD 13.0 . # . . . # # # . . . . . . . . . . # . . . . . . # . # 2326dnl FreeBSD 13.0 . # . . . # # # . . . . . . # . . . . . # . . . . . . # . #
2199dnl FreeBSD 5.4, 6.1 . # . . . # # # . . . . . . . # ? . # . . . . . . # ? ? 2327dnl FreeBSD 5.4, 6.1 . # . . . # # # . . . . . . . . . # ? . # . . . . . . # ? ?
2200dnl Mac OS X 10.13.5 . # . . # # # # . # . . . . . . . . . . . . # . . # ? ? 2328dnl Mac OS X 10.13.5 . # . . # # # # . # . . . . ? ? . . . . . . . . # . . # ? ?
2201dnl Mac OS X 10.5.8 . # . . # # # # . . . . . . . # # . . . . . . . . # ? ? 2329dnl Mac OS X 10.5.8 . # . . # # # # . . . . . . ? ? . # # . . . . . . . . # ? ?
2202dnl Mac OS X 10.3.9 . # . . . # # # . . . . . . . # # . # . . . . . . # ? ? 2330dnl Mac OS X 10.3.9 . # . . . # # # . . . . . . ? ? . # # . # . . . . . . # ? ?
2203dnl OpenBSD 6.0, 6.7 . # . . . # # # . . . . . . . . . . # . . . . . . # . # 2331dnl OpenBSD 6.0, 6.7 . # . . . # # # . . . . . . . . . . . . # . . . . . . # . #
2204dnl OpenBSD 3.9, 4.0 . # . # # # # # # . # . . # . # ? . # . . . . . . # ? ? 2332dnl OpenBSD 3.9, 4.0 . # . # # # # # # . # . . # ? ? . # ? . # . . . . . . # ? ?
2205dnl Cygwin 1.7.0 (2009) . # . . # . # # . . ? ? . . . . ? . ? . . . . . . ? ? ? 2333dnl Cygwin 1.7.0 (2009) . # . . # . # # . . ? ? . . ? ? . . ? . ? . . . . . . ? ? ?
2206dnl Cygwin 1.5.25 (2008) . # . . # # # # . . # ? . . . . ? . # . . . . . . ? ? ? 2334dnl Cygwin 1.5.25 (2008) . # . . # # # # . . # ? . . ? ? . . ? . # . . . . . . ? ? ?
2207dnl Cygwin 1.5.19 (2006) # # . . # # # # # . # ? . # . # ? # # . . . . . . ? ? ? 2335dnl Cygwin 1.5.19 (2006) # # . . # # # # # . # ? . # ? ? . # ? # # . . . . . . ? ? ?
2208dnl Solaris 11.4 . # . # # # # # . . # . . . . # . . . . . . . . . . # . 2336dnl Solaris 11.4 . # . # # # # # . . # . . . # # . # . . . . . . . . . . # .
2209dnl Solaris 11.3 . # . . . # # # . . # . . . . . . . . . . . . . . . # . 2337dnl Solaris 11.3 . # . . . # # # . . # . . . ? ? . . . . . . . . . . . . # .
2210dnl Solaris 11.0 . # . # # # # # . . # . . . . # . . . . . . . . . ? ? ? 2338dnl Solaris 11.0 . # . # # # # # . . # . . . ? ? . # . . . . . . . . . ? ? ?
2211dnl Solaris 10 . # . # # # # # . . # . . . . # . # . . . . . . . . # . 2339dnl Solaris 10 . # . # # # # # . . # . . . # # . # . # . . . . . . . . # .
2212dnl Solaris 2.6 ... 9 # # . # # # # # # . # . . . . # ? # . . . # . . . ? ? ? 2340dnl Solaris 2.6 ... 9 # # . # # # # # # . # . . . ? ? . # ? # . . . # . . . ? ? ?
2213dnl Solaris 2.5.1 # # . # # # # # # . # . . . . # ? . . # # # # # # ? ? ? 2341dnl Solaris 2.5.1 # # . # # # # # # . # . . . ? ? . # ? . . # # # # # # ? ? ?
2214dnl AIX 7.1 . # . # # # # # . . . . . . . # . # . . . . . . . # . . 2342dnl AIX 7.1 . # . # # # # # . . . . . . . . . # . # . . . . . . . # . .
2215dnl AIX 5.2 . # . # # # # # . . . . . . . # ? . . . . . . . . # ? ? 2343dnl AIX 5.2 . # . # # # # # . . . . . . ? ? . # ? . . . . . . . . # ? ?
2216dnl AIX 4.3.2, 5.1 # # . # # # # # # . . . . . . # ? . . . . # . . . # ? ? 2344dnl AIX 4.3.2, 5.1 # # . # # # # # # . . . . . ? ? . # ? . . . . # . . . # ? ?
2217dnl HP-UX 11.31 . # . . . # # # . . . ? . . . # ? . . . . # # . . ? ? ? 2345dnl HP-UX 11.31 . # . . . # # # . . . ? . . ? ? . # ? . . . . # # . . ? ? ?
2218dnl HP-UX 11.{00,11,23} # # . . . # # # # . . ? . . . # ? . . . . # # . # ? ? ? 2346dnl HP-UX 11.{00,11,23} # # . . . # # # # . . ? . . ? ? . # ? . . . . # # . # ? ? ?
2219dnl HP-UX 10.20 # # . # . # # # # . ? ? . . # # ? . . . . # # ? # ? ? ? 2347dnl HP-UX 10.20 # # . # . # # # # . ? ? . . ? ? # # ? . . . . # # ? # ? ? ?
2220dnl IRIX 6.5 # # . # # # # # # . # . . . . # ? . . . . # . . . # ? ? 2348dnl IRIX 6.5 # # . # # # # # # . # . . . ? ? . # ? . . . . # . . . # ? ?
2221dnl OSF/1 5.1 # # . # # # # # # . . ? . . . # ? . . . . # . . # ? ? ? 2349dnl OSF/1 5.1 # # . # # # # # # . . ? . . ? ? . # ? . . . . # . . # ? ? ?
2222dnl OSF/1 4.0d # # . # # # # # # . . ? . . . # ? . . # # # # # # ? ? ? 2350dnl OSF/1 4.0d # # . # # # # # # . . ? . . ? ? . # ? . . # # # # # # ? ? ?
2223dnl NetBSD 9.0 . # . . . # # # . . . . . . . . . . . . . . . . . # . # 2351dnl NetBSD 9.0 . # . . . # # # . . . . . . # # . . . . . . . . . . . # . #
2224dnl NetBSD 5.0 . # . . # # # # . . . . . . . # ? . # . . . . . . # ? ? 2352dnl NetBSD 5.0 . # . . # # # # . . . . . . ? ? . # ? . # . . . . . . # ? ?
2225dnl NetBSD 4.0 . # ? ? ? ? # # ? . ? . . ? ? ? ? ? ? . . . ? ? ? # ? ? 2353dnl NetBSD 4.0 . # ? ? ? ? # # ? . ? . . ? ? ? ? ? ? ? ? . . . ? ? ? # ? ?
2226dnl NetBSD 3.0 . # . . . # # # # . ? . # # ? # ? . # . . . . . . # ? ? 2354dnl NetBSD 3.0 . # . . . # # # # . ? . # # ? ? ? # ? . # . . . . . . # ? ?
2227dnl Haiku . # . . # # # # # . # ? . . . . ? . ? . . ? . . . . # . 2355dnl Haiku . # . . # # # # # . # ? . . # . . . ? . ? . . ? . . . . # .
2228dnl BeOS # # # . # # # # # . ? ? # . ? . ? # ? . . ? . . . ? ? ? 2356dnl BeOS # # # . # # # # # . ? ? # . ? ? ? . ? # ? . . ? . . . ? ? ?
2229dnl Android 4.3 . # . # # # # # # # # ? . # . # ? . # . . . # . . ? ? ? 2357dnl Android 4.3 . # . # # # # # # # # ? . # ? ? . # ? . # . . . # . . ? ? ?
2230dnl old mingw / msvcrt # # # # # # # # # . . ? # # . # ? # ? . # # # . . # ? ? 2358dnl old mingw / msvcrt # # # # # # # # # . . ? # # ? ? . # ? # ? . # # # . . # ? ?
2231dnl MSVC 9 # # # # # # # # # # . ? # # . # ? # ? # # # # . . # ? ? 2359dnl MSVC 9 # # # # # # # # # # . ? # # ? ? . # ? # ? # # # # . . # ? ?
2232dnl mingw 2009-2011 . # # . # . # # . . . ? # # . . ? . ? . . . . . . # ? ? 2360dnl mingw 2009-2011 . # # . # . # # . . . ? # # ? ? . . ? . ? . . . . . . # ? ?
2233dnl mingw-w64 2011 # # # # # # # # # . . ? # # . # ? # ? . # # # . . # ? ? 2361dnl mingw-w64 2011 # # # # # # # # # . . ? # # ? ? . # ? # ? . # # # . . # ? ?
diff --git a/gl/m4/pthread-once.m4 b/gl/m4/pthread-once.m4
new file mode 100644
index 00000000..85549254
--- /dev/null
+++ b/gl/m4/pthread-once.m4
@@ -0,0 +1,83 @@
1# pthread-once.m4
2# serial 6
3dnl Copyright (C) 2019-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9AC_DEFUN([gl_PTHREAD_ONCE],
10[
11 AC_REQUIRE([gl_PTHREAD_H])
12 AC_REQUIRE([AC_CANONICAL_HOST])
13 AC_REQUIRE([gl_PTHREADLIB])
14
15 if { case "$host_os" in mingw* | windows*) true;; *) false;; esac; } \
16 && test $gl_threads_api = windows; then
17 dnl Choose function names that don't conflict with the mingw-w64 winpthreads
18 dnl library.
19 REPLACE_PTHREAD_ONCE=1
20 PTHREAD_ONCE_LIB=
21 else
22 if test $HAVE_PTHREAD_H = 0; then
23 HAVE_PTHREAD_ONCE=0
24 PTHREAD_ONCE_LIB=
25 else
26 dnl Work around Cygwin 3.5.3 bug.
27 AC_CACHE_CHECK([whether pthread_once works],
28 [gl_cv_func_pthread_once_works],
29 [case "$host_os" in
30 cygwin*) gl_cv_func_pthread_once_works="guessing no" ;;
31 *) gl_cv_func_pthread_once_works="yes" ;;
32 esac
33 ])
34 case "$gl_cv_func_pthread_once_works" in
35 *yes) ;;
36 *) REPLACE_PTHREAD_ONCE=1 ;;
37 esac
38 dnl Determine whether linking requires $(LIBPMULTITHREAD) or only
39 dnl $(LIBPTHREAD).
40 if test -z "$LIBPTHREAD" && test -n "$LIBPMULTITHREAD"; then
41 AC_CACHE_CHECK([whether pthread_once can be used without linking with libpthread],
42 [gl_cv_func_pthread_once_no_lib],
43 [AC_RUN_IFELSE(
44 [AC_LANG_PROGRAM(
45 [[#include <pthread.h>
46 static pthread_once_t a_once = PTHREAD_ONCE_INIT;
47 static int a;
48 static void a_init (void) { a = 8647; }
49 ]],
50 [[if (pthread_once (&a_once, a_init)) return 1;
51 if (a != 8647) return 2;
52 return 0;
53 ]])],
54 [gl_cv_func_pthread_once_no_lib=yes],
55 [gl_cv_func_pthread_once_no_lib=no],
56 [case "$host_os" in
57 # Guess no on glibc.
58 *-gnu* | gnu*)
59 gl_cv_func_pthread_once_no_lib="guessing no" ;;
60 # Guess no on FreeBSD.
61 freebsd* | dragonfly* | midnightbsd*)
62 gl_cv_func_pthread_once_no_lib="guessing no" ;;
63 # Guess yes otherwise.
64 *)
65 gl_cv_func_pthread_once_no_lib="guessing yes" ;;
66 esac
67 ])
68 ])
69 case "$gl_cv_func_pthread_once_no_lib" in
70 *yes) PTHREAD_ONCE_LIB="$LIBPTHREAD" ;;
71 *) PTHREAD_ONCE_LIB="$LIBPMULTITHREAD" ;;
72 esac
73 dnl Expected result:
74 dnl PTHREAD_ONCE_LIB is $(LIBPMULTITHREAD) on glibc < 2.34, FreeBSD.
75 dnl PTHREAD_ONCE_LIB is $(LIBPTHREAD) in particular on
76 dnl musl libc, macOS, NetBSD, Solaris, Cygwin, Haiku, Android.
77 else
78 PTHREAD_ONCE_LIB="$LIBPTHREAD"
79 fi
80 fi
81 fi
82 AC_SUBST([PTHREAD_ONCE_LIB])
83])
diff --git a/gl/m4/pthread-spin.m4 b/gl/m4/pthread-spin.m4
new file mode 100644
index 00000000..aae2fb3b
--- /dev/null
+++ b/gl/m4/pthread-spin.m4
@@ -0,0 +1,72 @@
1# pthread-spin.m4
2# serial 8
3dnl Copyright (C) 2019-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9AC_DEFUN_ONCE([gl_PTHREAD_SPIN],
10[
11 AC_REQUIRE([gl_PTHREAD_H_PART1])
12 AC_REQUIRE([AC_CANONICAL_HOST])
13
14 if { case "$host_os" in mingw* | windows*) true;; *) false;; esac; } \
15 && test $gl_threads_api = windows; then
16 dnl Choose function names that don't conflict with the mingw-w64 winpthreads
17 dnl library.
18 REPLACE_PTHREAD_SPIN_INIT=1
19 REPLACE_PTHREAD_SPIN_LOCK=1
20 REPLACE_PTHREAD_SPIN_TRYLOCK=1
21 REPLACE_PTHREAD_SPIN_UNLOCK=1
22 REPLACE_PTHREAD_SPIN_DESTROY=1
23 else
24 if test $HAVE_PTHREAD_H = 0 || test $HAVE_PTHREAD_SPINLOCK_T = 0; then
25 HAVE_PTHREAD_SPIN_INIT=0
26 HAVE_PTHREAD_SPIN_LOCK=0
27 HAVE_PTHREAD_SPIN_TRYLOCK=0
28 HAVE_PTHREAD_SPIN_UNLOCK=0
29 HAVE_PTHREAD_SPIN_DESTROY=0
30 else
31 dnl Test whether the gnulib module 'threadlib' is in use.
32 dnl Some packages like Emacs use --avoid=threadlib.
33 dnl Write the symbol in such a way that it does not cause 'aclocal' to pick
34 dnl the threadlib.m4 file that is installed in $PREFIX/share/aclocal/.
35 m4_ifdef([gl_][THREADLIB], [
36 AC_REQUIRE([gl_][THREADLIB])
37 dnl Test whether the functions actually exist.
38 dnl FreeBSD 5.2.1 declares them but does not define them.
39 AC_CACHE_CHECK([for pthread_spin_init],
40 [gl_cv_func_pthread_spin_init_in_LIBMULTITHREAD],
41 [gl_saved_LIBS="$LIBS"
42 LIBS="$LIBS $LIBMULTITHREAD"
43 AC_LINK_IFELSE(
44 [AC_LANG_PROGRAM(
45 [[#include <pthread.h>
46 ]],
47 [[pthread_spinlock_t lock;
48 return pthread_spin_init (&lock, 0);
49 ]])
50 ],
51 [gl_cv_func_pthread_spin_init_in_LIBMULTITHREAD=yes],
52 [gl_cv_func_pthread_spin_init_in_LIBMULTITHREAD=no])
53 LIBS="$gl_saved_LIBS"
54 ])
55 if test $gl_cv_func_pthread_spin_init_in_LIBMULTITHREAD != yes; then
56 HAVE_PTHREAD_SPIN_INIT=0
57 REPLACE_PTHREAD_SPIN_INIT=1
58 HAVE_PTHREAD_SPIN_LOCK=0
59 REPLACE_PTHREAD_SPIN_LOCK=1
60 HAVE_PTHREAD_SPIN_TRYLOCK=0
61 REPLACE_PTHREAD_SPIN_TRYLOCK=1
62 HAVE_PTHREAD_SPIN_UNLOCK=0
63 REPLACE_PTHREAD_SPIN_UNLOCK=1
64 HAVE_PTHREAD_SPIN_DESTROY=0
65 REPLACE_PTHREAD_SPIN_DESTROY=1
66 fi
67 ], [
68 :
69 ])
70 fi
71 fi
72])
diff --git a/gl/m4/pthread_h.m4 b/gl/m4/pthread_h.m4
new file mode 100644
index 00000000..bb921386
--- /dev/null
+++ b/gl/m4/pthread_h.m4
@@ -0,0 +1,293 @@
1# pthread_h.m4
2# serial 11
3dnl Copyright (C) 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9AC_DEFUN_ONCE([gl_PTHREAD_H_PART1],
10[
11 dnl Ensure to expand the default settings once only, before all statements
12 dnl that occur in other macros.
13 AC_REQUIRE([gl_PTHREAD_H_DEFAULTS])
14
15 AC_REQUIRE([AC_CANONICAL_HOST])
16 AC_REQUIRE([gl_PTHREADLIB])
17
18 gl_CHECK_NEXT_HEADERS([pthread.h])
19 if test $ac_cv_header_pthread_h = yes; then
20 HAVE_PTHREAD_H=1
21 dnl On mingw, if --enable-threads=windows or gl_AVOID_WINPTHREAD is used,
22 dnl ignore the <pthread.h> from the mingw-w64 winpthreads library.
23 m4_ifdef([gl_][THREADLIB], [
24 AC_REQUIRE([gl_][THREADLIB])
25 if { case "$host_os" in mingw* | windows*) true;; *) false;; esac; } \
26 && test $gl_threads_api = windows; then
27 HAVE_PTHREAD_H=0
28 fi
29 ])
30 else
31 HAVE_PTHREAD_H=0
32 fi
33 AC_SUBST([HAVE_PTHREAD_H])
34
35 AC_CHECK_TYPES([pthread_t, pthread_spinlock_t], [], [],
36 [AC_INCLUDES_DEFAULT[
37 #if HAVE_PTHREAD_H
38 #include <pthread.h>
39 #endif]])
40 if test $ac_cv_type_pthread_t != yes; then
41 HAVE_PTHREAD_T=0
42 fi
43 if test $ac_cv_type_pthread_spinlock_t != yes; then
44 HAVE_PTHREAD_SPINLOCK_T=0
45 fi
46])
47
48AC_DEFUN([gl_PTHREAD_H],
49[
50 AC_REQUIRE([gl_PTHREAD_H_PART1])
51
52 dnl Set HAVE_PTHREAD_SPIN_INIT, REPLACE_PTHREAD_SPIN_INIT.
53 gl_PTHREAD_SPIN
54
55 dnl Constants may be defined as C preprocessor macros or as enum items.
56
57 AC_CACHE_CHECK([for PTHREAD_CREATE_DETACHED],
58 [gl_cv_const_PTHREAD_CREATE_DETACHED],
59 [AC_COMPILE_IFELSE(
60 [AC_LANG_PROGRAM(
61 [[#include <pthread.h>
62 int x = PTHREAD_CREATE_DETACHED;
63 ]],
64 [[]])],
65 [gl_cv_const_PTHREAD_CREATE_DETACHED=yes],
66 [gl_cv_const_PTHREAD_CREATE_DETACHED=no])
67 ])
68 if test $gl_cv_const_PTHREAD_CREATE_DETACHED != yes; then
69 HAVE_PTHREAD_CREATE_DETACHED=0
70 fi
71
72 AC_CACHE_CHECK([for PTHREAD_MUTEX_RECURSIVE],
73 [gl_cv_const_PTHREAD_MUTEX_RECURSIVE],
74 [AC_COMPILE_IFELSE(
75 [AC_LANG_PROGRAM(
76 [[#include <pthread.h>
77 int x = PTHREAD_MUTEX_RECURSIVE;
78 ]],
79 [[]])],
80 [gl_cv_const_PTHREAD_MUTEX_RECURSIVE=yes],
81 [gl_cv_const_PTHREAD_MUTEX_RECURSIVE=no])
82 ])
83 if test $gl_cv_const_PTHREAD_MUTEX_RECURSIVE != yes; then
84 HAVE_PTHREAD_MUTEX_RECURSIVE=0
85 fi
86
87 AC_CACHE_CHECK([for PTHREAD_MUTEX_ROBUST],
88 [gl_cv_const_PTHREAD_MUTEX_ROBUST],
89 [AC_COMPILE_IFELSE(
90 [AC_LANG_PROGRAM(
91 [[#include <pthread.h>
92 int x = PTHREAD_MUTEX_ROBUST;
93 ]],
94 [[]])],
95 [gl_cv_const_PTHREAD_MUTEX_ROBUST=yes],
96 [gl_cv_const_PTHREAD_MUTEX_ROBUST=no])
97 ])
98 if test $gl_cv_const_PTHREAD_MUTEX_ROBUST != yes; then
99 HAVE_PTHREAD_MUTEX_ROBUST=0
100 fi
101
102 AC_CACHE_CHECK([for PTHREAD_PROCESS_SHARED],
103 [gl_cv_const_PTHREAD_PROCESS_SHARED],
104 [AC_COMPILE_IFELSE(
105 [AC_LANG_PROGRAM(
106 [[#include <pthread.h>
107 int x = PTHREAD_PROCESS_SHARED;
108 ]],
109 [[]])],
110 [gl_cv_const_PTHREAD_PROCESS_SHARED=yes],
111 [gl_cv_const_PTHREAD_PROCESS_SHARED=no])
112 ])
113 if test $gl_cv_const_PTHREAD_PROCESS_SHARED != yes; then
114 HAVE_PTHREAD_PROCESS_SHARED=0
115 fi
116
117 dnl Check for declarations of anything we want to poison if the
118 dnl corresponding gnulib module is not in use, if it is not common
119 dnl enough to be declared everywhere.
120 gl_WARN_ON_USE_PREPARE([[#include <pthread.h>
121 ]], [
122 pthread_create pthread_attr_init pthread_attr_getdetachstate
123 pthread_attr_setdetachstate pthread_attr_destroy pthread_self pthread_equal
124 pthread_detach pthread_join pthread_exit
125 pthread_once
126 pthread_mutex_init pthread_mutexattr_init pthread_mutexattr_gettype
127 pthread_mutexattr_settype pthread_mutexattr_getrobust
128 pthread_mutexattr_setrobust pthread_mutexattr_destroy pthread_mutex_lock
129 pthread_mutex_trylock pthread_mutex_timedlock pthread_mutex_unlock
130 pthread_mutex_destroy
131 pthread_rwlock_init pthread_rwlockattr_init pthread_rwlockattr_destroy
132 pthread_rwlock_rdlock pthread_rwlock_wrlock pthread_rwlock_tryrdlock
133 pthread_rwlock_trywrlock pthread_rwlock_timedrdlock
134 pthread_rwlock_timedwrlock pthread_rwlock_unlock pthread_rwlock_destroy
135 pthread_cond_init pthread_condattr_init pthread_condattr_destroy
136 pthread_cond_wait pthread_cond_timedwait pthread_cond_signal
137 pthread_cond_broadcast pthread_cond_destroy
138 pthread_key_create pthread_setspecific pthread_getspecific
139 pthread_key_delete
140 pthread_spin_init pthread_spin_lock pthread_spin_trylock pthread_spin_unlock
141 pthread_spin_destroy])
142
143 AC_REQUIRE([AC_C_RESTRICT])
144
145 dnl For backward compatibility with gnulib versions <= 2019-07.
146 LIB_PTHREAD="$LIBPMULTITHREAD"
147 AC_SUBST([LIB_PTHREAD])
148])
149
150# gl_PTHREAD_MODULE_INDICATOR([modulename])
151# sets the shell variable that indicates the presence of the given module
152# to a C preprocessor expression that will evaluate to 1.
153# This macro invocation must not occur in macros that are AC_REQUIREd.
154AC_DEFUN([gl_PTHREAD_MODULE_INDICATOR],
155[
156 dnl Ensure to expand the default settings once only.
157 gl_PTHREAD_H_REQUIRE_DEFAULTS
158 gl_MODULE_INDICATOR_SET_VARIABLE([$1])
159 dnl Define it also as a C macro, for the benefit of the unit tests.
160 gl_MODULE_INDICATOR_FOR_TESTS([$1])
161])
162
163# Initializes the default values for AC_SUBSTed shell variables.
164# This macro must not be AC_REQUIREd. It must only be invoked, and only
165# outside of macros or in macros that are not AC_REQUIREd.
166AC_DEFUN([gl_PTHREAD_H_REQUIRE_DEFAULTS],
167[
168 m4_defun(GL_MODULE_INDICATOR_PREFIX[_PTHREAD_H_MODULE_INDICATOR_DEFAULTS], [
169 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PTHREAD_THREAD])
170 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PTHREAD_ONCE])
171 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PTHREAD_MUTEX])
172 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PTHREAD_RWLOCK])
173 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PTHREAD_COND])
174 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PTHREAD_TSS])
175 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PTHREAD_SPIN])
176 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PTHREAD_MUTEX_TIMEDLOCK])
177 ])
178 m4_require(GL_MODULE_INDICATOR_PREFIX[_PTHREAD_H_MODULE_INDICATOR_DEFAULTS])
179 AC_REQUIRE([gl_PTHREAD_H_DEFAULTS])
180])
181
182AC_DEFUN([gl_PTHREAD_H_DEFAULTS],
183[
184 dnl Assume proper GNU behavior unless another module says otherwise.
185 HAVE_PTHREAD_T=1; AC_SUBST([HAVE_PTHREAD_T])
186 HAVE_PTHREAD_SPINLOCK_T=1; AC_SUBST([HAVE_PTHREAD_SPINLOCK_T])
187 HAVE_PTHREAD_CREATE_DETACHED=1; AC_SUBST([HAVE_PTHREAD_CREATE_DETACHED])
188 HAVE_PTHREAD_MUTEX_RECURSIVE=1; AC_SUBST([HAVE_PTHREAD_MUTEX_RECURSIVE])
189 HAVE_PTHREAD_MUTEX_ROBUST=1; AC_SUBST([HAVE_PTHREAD_MUTEX_ROBUST])
190 HAVE_PTHREAD_PROCESS_SHARED=1; AC_SUBST([HAVE_PTHREAD_PROCESS_SHARED])
191 HAVE_PTHREAD_CREATE=1; AC_SUBST([HAVE_PTHREAD_CREATE])
192 HAVE_PTHREAD_ATTR_INIT=1; AC_SUBST([HAVE_PTHREAD_ATTR_INIT])
193 HAVE_PTHREAD_ATTR_GETDETACHSTATE=1; AC_SUBST([HAVE_PTHREAD_ATTR_GETDETACHSTATE])
194 HAVE_PTHREAD_ATTR_SETDETACHSTATE=1; AC_SUBST([HAVE_PTHREAD_ATTR_SETDETACHSTATE])
195 HAVE_PTHREAD_ATTR_DESTROY=1; AC_SUBST([HAVE_PTHREAD_ATTR_DESTROY])
196 HAVE_PTHREAD_SELF=1; AC_SUBST([HAVE_PTHREAD_SELF])
197 HAVE_PTHREAD_EQUAL=1; AC_SUBST([HAVE_PTHREAD_EQUAL])
198 HAVE_PTHREAD_DETACH=1; AC_SUBST([HAVE_PTHREAD_DETACH])
199 HAVE_PTHREAD_JOIN=1; AC_SUBST([HAVE_PTHREAD_JOIN])
200 HAVE_PTHREAD_EXIT=1; AC_SUBST([HAVE_PTHREAD_EXIT])
201 HAVE_PTHREAD_ONCE=1; AC_SUBST([HAVE_PTHREAD_ONCE])
202 HAVE_PTHREAD_MUTEX_INIT=1; AC_SUBST([HAVE_PTHREAD_MUTEX_INIT])
203 HAVE_PTHREAD_MUTEXATTR_INIT=1; AC_SUBST([HAVE_PTHREAD_MUTEXATTR_INIT])
204 HAVE_PTHREAD_MUTEXATTR_GETTYPE=1; AC_SUBST([HAVE_PTHREAD_MUTEXATTR_GETTYPE])
205 HAVE_PTHREAD_MUTEXATTR_SETTYPE=1; AC_SUBST([HAVE_PTHREAD_MUTEXATTR_SETTYPE])
206 HAVE_PTHREAD_MUTEXATTR_GETROBUST=1; AC_SUBST([HAVE_PTHREAD_MUTEXATTR_GETROBUST])
207 HAVE_PTHREAD_MUTEXATTR_SETROBUST=1; AC_SUBST([HAVE_PTHREAD_MUTEXATTR_SETROBUST])
208 HAVE_PTHREAD_MUTEXATTR_DESTROY=1; AC_SUBST([HAVE_PTHREAD_MUTEXATTR_DESTROY])
209 HAVE_PTHREAD_MUTEX_LOCK=1; AC_SUBST([HAVE_PTHREAD_MUTEX_LOCK])
210 HAVE_PTHREAD_MUTEX_TRYLOCK=1; AC_SUBST([HAVE_PTHREAD_MUTEX_TRYLOCK])
211 HAVE_PTHREAD_MUTEX_TIMEDLOCK=1; AC_SUBST([HAVE_PTHREAD_MUTEX_TIMEDLOCK])
212 HAVE_PTHREAD_MUTEX_UNLOCK=1; AC_SUBST([HAVE_PTHREAD_MUTEX_UNLOCK])
213 HAVE_PTHREAD_MUTEX_DESTROY=1; AC_SUBST([HAVE_PTHREAD_MUTEX_DESTROY])
214 HAVE_PTHREAD_RWLOCK_INIT=1; AC_SUBST([HAVE_PTHREAD_RWLOCK_INIT])
215 HAVE_PTHREAD_RWLOCKATTR_INIT=1; AC_SUBST([HAVE_PTHREAD_RWLOCKATTR_INIT])
216 HAVE_PTHREAD_RWLOCKATTR_DESTROY=1; AC_SUBST([HAVE_PTHREAD_RWLOCKATTR_DESTROY])
217 HAVE_PTHREAD_RWLOCK_RDLOCK=1; AC_SUBST([HAVE_PTHREAD_RWLOCK_RDLOCK])
218 HAVE_PTHREAD_RWLOCK_WRLOCK=1; AC_SUBST([HAVE_PTHREAD_RWLOCK_WRLOCK])
219 HAVE_PTHREAD_RWLOCK_TRYRDLOCK=1; AC_SUBST([HAVE_PTHREAD_RWLOCK_TRYRDLOCK])
220 HAVE_PTHREAD_RWLOCK_TRYWRLOCK=1; AC_SUBST([HAVE_PTHREAD_RWLOCK_TRYWRLOCK])
221 HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK=1; AC_SUBST([HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK])
222 HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK=1; AC_SUBST([HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK])
223 HAVE_PTHREAD_RWLOCK_UNLOCK=1; AC_SUBST([HAVE_PTHREAD_RWLOCK_UNLOCK])
224 HAVE_PTHREAD_RWLOCK_DESTROY=1; AC_SUBST([HAVE_PTHREAD_RWLOCK_DESTROY])
225 HAVE_PTHREAD_COND_INIT=1; AC_SUBST([HAVE_PTHREAD_COND_INIT])
226 HAVE_PTHREAD_CONDATTR_INIT=1; AC_SUBST([HAVE_PTHREAD_CONDATTR_INIT])
227 HAVE_PTHREAD_CONDATTR_DESTROY=1; AC_SUBST([HAVE_PTHREAD_CONDATTR_DESTROY])
228 HAVE_PTHREAD_COND_WAIT=1; AC_SUBST([HAVE_PTHREAD_COND_WAIT])
229 HAVE_PTHREAD_COND_TIMEDWAIT=1; AC_SUBST([HAVE_PTHREAD_COND_TIMEDWAIT])
230 HAVE_PTHREAD_COND_SIGNAL=1; AC_SUBST([HAVE_PTHREAD_COND_SIGNAL])
231 HAVE_PTHREAD_COND_BROADCAST=1; AC_SUBST([HAVE_PTHREAD_COND_BROADCAST])
232 HAVE_PTHREAD_COND_DESTROY=1; AC_SUBST([HAVE_PTHREAD_COND_DESTROY])
233 HAVE_PTHREAD_KEY_CREATE=1; AC_SUBST([HAVE_PTHREAD_KEY_CREATE])
234 HAVE_PTHREAD_SETSPECIFIC=1; AC_SUBST([HAVE_PTHREAD_SETSPECIFIC])
235 HAVE_PTHREAD_GETSPECIFIC=1; AC_SUBST([HAVE_PTHREAD_GETSPECIFIC])
236 HAVE_PTHREAD_KEY_DELETE=1; AC_SUBST([HAVE_PTHREAD_KEY_DELETE])
237 HAVE_PTHREAD_SPIN_INIT=1; AC_SUBST([HAVE_PTHREAD_SPIN_INIT])
238 HAVE_PTHREAD_SPIN_LOCK=1; AC_SUBST([HAVE_PTHREAD_SPIN_LOCK])
239 HAVE_PTHREAD_SPIN_TRYLOCK=1; AC_SUBST([HAVE_PTHREAD_SPIN_TRYLOCK])
240 HAVE_PTHREAD_SPIN_UNLOCK=1; AC_SUBST([HAVE_PTHREAD_SPIN_UNLOCK])
241 HAVE_PTHREAD_SPIN_DESTROY=1; AC_SUBST([HAVE_PTHREAD_SPIN_DESTROY])
242 REPLACE_PTHREAD_CREATE=0; AC_SUBST([REPLACE_PTHREAD_CREATE])
243 REPLACE_PTHREAD_ATTR_INIT=0; AC_SUBST([REPLACE_PTHREAD_ATTR_INIT])
244 REPLACE_PTHREAD_ATTR_GETDETACHSTATE=0; AC_SUBST([REPLACE_PTHREAD_ATTR_GETDETACHSTATE])
245 REPLACE_PTHREAD_ATTR_SETDETACHSTATE=0; AC_SUBST([REPLACE_PTHREAD_ATTR_SETDETACHSTATE])
246 REPLACE_PTHREAD_ATTR_DESTROY=0; AC_SUBST([REPLACE_PTHREAD_ATTR_DESTROY])
247 REPLACE_PTHREAD_SELF=0; AC_SUBST([REPLACE_PTHREAD_SELF])
248 REPLACE_PTHREAD_EQUAL=0; AC_SUBST([REPLACE_PTHREAD_EQUAL])
249 REPLACE_PTHREAD_DETACH=0; AC_SUBST([REPLACE_PTHREAD_DETACH])
250 REPLACE_PTHREAD_JOIN=0; AC_SUBST([REPLACE_PTHREAD_JOIN])
251 REPLACE_PTHREAD_EXIT=0; AC_SUBST([REPLACE_PTHREAD_EXIT])
252 REPLACE_PTHREAD_ONCE=0; AC_SUBST([REPLACE_PTHREAD_ONCE])
253 REPLACE_PTHREAD_MUTEX_INIT=0; AC_SUBST([REPLACE_PTHREAD_MUTEX_INIT])
254 REPLACE_PTHREAD_MUTEXATTR_INIT=0; AC_SUBST([REPLACE_PTHREAD_MUTEXATTR_INIT])
255 REPLACE_PTHREAD_MUTEXATTR_GETTYPE=0; AC_SUBST([REPLACE_PTHREAD_MUTEXATTR_GETTYPE])
256 REPLACE_PTHREAD_MUTEXATTR_SETTYPE=0; AC_SUBST([REPLACE_PTHREAD_MUTEXATTR_SETTYPE])
257 REPLACE_PTHREAD_MUTEXATTR_GETROBUST=0; AC_SUBST([REPLACE_PTHREAD_MUTEXATTR_GETROBUST])
258 REPLACE_PTHREAD_MUTEXATTR_SETROBUST=0; AC_SUBST([REPLACE_PTHREAD_MUTEXATTR_SETROBUST])
259 REPLACE_PTHREAD_MUTEXATTR_DESTROY=0; AC_SUBST([REPLACE_PTHREAD_MUTEXATTR_DESTROY])
260 REPLACE_PTHREAD_MUTEX_LOCK=0; AC_SUBST([REPLACE_PTHREAD_MUTEX_LOCK])
261 REPLACE_PTHREAD_MUTEX_TRYLOCK=0; AC_SUBST([REPLACE_PTHREAD_MUTEX_TRYLOCK])
262 REPLACE_PTHREAD_MUTEX_TIMEDLOCK=0; AC_SUBST([REPLACE_PTHREAD_MUTEX_TIMEDLOCK])
263 REPLACE_PTHREAD_MUTEX_UNLOCK=0; AC_SUBST([REPLACE_PTHREAD_MUTEX_UNLOCK])
264 REPLACE_PTHREAD_MUTEX_DESTROY=0; AC_SUBST([REPLACE_PTHREAD_MUTEX_DESTROY])
265 REPLACE_PTHREAD_RWLOCK_INIT=0; AC_SUBST([REPLACE_PTHREAD_RWLOCK_INIT])
266 REPLACE_PTHREAD_RWLOCKATTR_INIT=0; AC_SUBST([REPLACE_PTHREAD_RWLOCKATTR_INIT])
267 REPLACE_PTHREAD_RWLOCKATTR_DESTROY=0; AC_SUBST([REPLACE_PTHREAD_RWLOCKATTR_DESTROY])
268 REPLACE_PTHREAD_RWLOCK_RDLOCK=0; AC_SUBST([REPLACE_PTHREAD_RWLOCK_RDLOCK])
269 REPLACE_PTHREAD_RWLOCK_WRLOCK=0; AC_SUBST([REPLACE_PTHREAD_RWLOCK_WRLOCK])
270 REPLACE_PTHREAD_RWLOCK_TRYRDLOCK=0; AC_SUBST([REPLACE_PTHREAD_RWLOCK_TRYRDLOCK])
271 REPLACE_PTHREAD_RWLOCK_TRYWRLOCK=0; AC_SUBST([REPLACE_PTHREAD_RWLOCK_TRYWRLOCK])
272 REPLACE_PTHREAD_RWLOCK_TIMEDRDLOCK=0; AC_SUBST([REPLACE_PTHREAD_RWLOCK_TIMEDRDLOCK])
273 REPLACE_PTHREAD_RWLOCK_TIMEDWRLOCK=0; AC_SUBST([REPLACE_PTHREAD_RWLOCK_TIMEDWRLOCK])
274 REPLACE_PTHREAD_RWLOCK_UNLOCK=0; AC_SUBST([REPLACE_PTHREAD_RWLOCK_UNLOCK])
275 REPLACE_PTHREAD_RWLOCK_DESTROY=0; AC_SUBST([REPLACE_PTHREAD_RWLOCK_DESTROY])
276 REPLACE_PTHREAD_COND_INIT=0; AC_SUBST([REPLACE_PTHREAD_COND_INIT])
277 REPLACE_PTHREAD_CONDATTR_INIT=0; AC_SUBST([REPLACE_PTHREAD_CONDATTR_INIT])
278 REPLACE_PTHREAD_CONDATTR_DESTROY=0; AC_SUBST([REPLACE_PTHREAD_CONDATTR_DESTROY])
279 REPLACE_PTHREAD_COND_WAIT=0; AC_SUBST([REPLACE_PTHREAD_COND_WAIT])
280 REPLACE_PTHREAD_COND_TIMEDWAIT=0; AC_SUBST([REPLACE_PTHREAD_COND_TIMEDWAIT])
281 REPLACE_PTHREAD_COND_SIGNAL=0; AC_SUBST([REPLACE_PTHREAD_COND_SIGNAL])
282 REPLACE_PTHREAD_COND_BROADCAST=0; AC_SUBST([REPLACE_PTHREAD_COND_BROADCAST])
283 REPLACE_PTHREAD_COND_DESTROY=0; AC_SUBST([REPLACE_PTHREAD_COND_DESTROY])
284 REPLACE_PTHREAD_KEY_CREATE=0; AC_SUBST([REPLACE_PTHREAD_KEY_CREATE])
285 REPLACE_PTHREAD_SETSPECIFIC=0; AC_SUBST([REPLACE_PTHREAD_SETSPECIFIC])
286 REPLACE_PTHREAD_GETSPECIFIC=0; AC_SUBST([REPLACE_PTHREAD_GETSPECIFIC])
287 REPLACE_PTHREAD_KEY_DELETE=0; AC_SUBST([REPLACE_PTHREAD_KEY_DELETE])
288 REPLACE_PTHREAD_SPIN_INIT=0; AC_SUBST([REPLACE_PTHREAD_SPIN_INIT])
289 REPLACE_PTHREAD_SPIN_LOCK=0; AC_SUBST([REPLACE_PTHREAD_SPIN_LOCK])
290 REPLACE_PTHREAD_SPIN_TRYLOCK=0; AC_SUBST([REPLACE_PTHREAD_SPIN_TRYLOCK])
291 REPLACE_PTHREAD_SPIN_UNLOCK=0; AC_SUBST([REPLACE_PTHREAD_SPIN_UNLOCK])
292 REPLACE_PTHREAD_SPIN_DESTROY=0; AC_SUBST([REPLACE_PTHREAD_SPIN_DESTROY])
293])
diff --git a/gl/m4/pthread_rwlock_rdlock.m4 b/gl/m4/pthread_rwlock_rdlock.m4
index b8b5b117..aec9f076 100644
--- a/gl/m4/pthread_rwlock_rdlock.m4
+++ b/gl/m4/pthread_rwlock_rdlock.m4
@@ -1,9 +1,10 @@
1# pthread_rwlock_rdlock.m4 1# pthread_rwlock_rdlock.m4
2# serial 8 2# serial 8
3dnl Copyright (C) 2017-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2017-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Bruno Haible. 9dnl From Bruno Haible.
9dnl Inspired by 10dnl Inspired by
diff --git a/gl/m4/realloc.m4 b/gl/m4/realloc.m4
index eb90d588..67c1476b 100644
--- a/gl/m4/realloc.m4
+++ b/gl/m4/realloc.m4
@@ -1,54 +1,22 @@
1# realloc.m4 1# realloc.m4
2# serial 29 2# serial 39.1
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# This is adapted with modifications from upstream Autoconf here: 9# An an experimental option, the user can request a sanitized realloc()
9# https://git.savannah.gnu.org/cgit/autoconf.git/tree/lib/autoconf/functions.m4?id=v2.70#n1455 10# implementation, i.e. one that aborts upon undefined behaviour,
10AC_DEFUN([_AC_FUNC_REALLOC_IF], 11# by setting
12# gl_cv_func_realloc_sanitize=yes
13# at configure time.
14AC_DEFUN([gl_FUNC_REALLOC_SANITIZED],
11[ 15[
12 AC_REQUIRE([AC_CANONICAL_HOST])dnl for cross-compiles 16 AC_CACHE_CHECK([whether realloc should abort upon undefined behaviour],
13 AC_CACHE_CHECK([whether realloc (0, 0) returns nonnull], 17 [gl_cv_func_realloc_sanitize],
14 [ac_cv_func_realloc_0_nonnull], 18 [test -n "$gl_cv_func_realloc_sanitize" || gl_cv_func_realloc_sanitize=no])
15 [AC_RUN_IFELSE( 19])
16 [AC_LANG_PROGRAM(
17 [[#include <stdlib.h>
18 ]],
19 [[void *p = realloc (0, 0);
20 void * volatile vp = p;
21 int result = !vp;
22 free (p);
23 return result;]])
24 ],
25 [ac_cv_func_realloc_0_nonnull=yes],
26 [ac_cv_func_realloc_0_nonnull=no],
27 [case "$host_os" in
28 # Guess yes on platforms where we know the result.
29 *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \
30 | gnu* | *-musl* | midipix* | midnightbsd* \
31 | hpux* | solaris* | cygwin* | mingw* | windows* | msys* )
32 ac_cv_func_realloc_0_nonnull="guessing yes" ;;
33 # If we don't know, obey --enable-cross-guesses.
34 *) ac_cv_func_realloc_0_nonnull="$gl_cross_guess_normal" ;;
35 esac
36 ])
37 ])
38 AS_CASE([$ac_cv_func_realloc_0_nonnull], [*yes], [$1], [$2])
39])# AC_FUNC_REALLOC
40
41# gl_FUNC_REALLOC_GNU
42# -------------------
43# Replace realloc if it is not compatible with GNU libc.
44AC_DEFUN([gl_FUNC_REALLOC_GNU],
45[
46 AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
47 AC_REQUIRE([gl_FUNC_REALLOC_POSIX])
48 if test $REPLACE_REALLOC_FOR_REALLOC_GNU = 0; then
49 _AC_FUNC_REALLOC_IF([], [REPLACE_REALLOC_FOR_REALLOC_GNU=1])
50 fi
51])# gl_FUNC_REALLOC_GNU
52 20
53# gl_FUNC_REALLOC_POSIX 21# gl_FUNC_REALLOC_POSIX
54# --------------------- 22# ---------------------
@@ -59,7 +27,100 @@ AC_DEFUN([gl_FUNC_REALLOC_POSIX],
59[ 27[
60 AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) 28 AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
61 AC_REQUIRE([gl_FUNC_MALLOC_POSIX]) 29 AC_REQUIRE([gl_FUNC_MALLOC_POSIX])
62 if test $REPLACE_MALLOC_FOR_MALLOC_POSIX = 1; then 30 AC_REQUIRE([AC_CANONICAL_HOST])
31 AC_CACHE_CHECK([whether realloc sets errno on failure],
32 [gl_cv_func_realloc_posix],
33 [
34 dnl FreeBSD 15.0 realloc() does not set errno when asked for more than
35 dnl 0x7000000000000000 bytes.
36 case "$host_os" in
37 darwin* | freebsd* | dragonfly* | midnightbsd* | netbsd* | openbsd*)
38 AC_RUN_IFELSE(
39 [AC_LANG_SOURCE(
40 [[#include <errno.h>
41 #include <stdlib.h>
42 int main (int argc, char **argv)
43 {
44 void *p;
45 errno = 1729;
46 p = realloc (malloc (1), (size_t)(-1) / 100 * 49);
47 return (!p && errno == 1729);
48 }
49 ]])
50 ],
51 [gl_cv_func_realloc_posix=yes],
52 [gl_cv_func_realloc_posix=no],
53 [case "$host_os" in
54 freebsd*) gl_cv_func_realloc_posix="guessing no" ;;
55 *) gl_cv_func_realloc_posix="guessing yes" ;;
56 esac
57 ])
58 ;;
59 *)
60 gl_cv_func_realloc_posix="$gl_cv_func_malloc_posix"
61 ;;
62 esac
63 ])
64 case "$gl_cv_func_realloc_posix" in
65 *yes)
66 AC_DEFINE([HAVE_REALLOC_POSIX], [1],
67 [Define if realloc sets errno on allocation failure.])
68 ;;
69 *)
70 REPLACE_REALLOC_FOR_REALLOC_POSIX=1
71 ;;
72 esac
73 AC_REQUIRE([gl_FUNC_REALLOC_SANITIZED])
74 if test "$gl_cv_func_realloc_sanitize" != no; then
63 REPLACE_REALLOC_FOR_REALLOC_POSIX=1 75 REPLACE_REALLOC_FOR_REALLOC_POSIX=1
76 AC_DEFINE([NEED_SANITIZED_REALLOC], [1],
77 [Define to 1 if realloc should abort upon undefined behaviour.])
64 fi 78 fi
65]) 79])
80
81# gl_FUNC_REALLOC_0_NONNULL
82# -------------------------
83# Replace realloc if realloc (..., 0) returns null.
84# Modules that use this macro directly or indirectly should depend
85# on extensions-aix, so that _LINUX_SOURCE_COMPAT gets defined
86# before this macro gets invoked. This helps if !(__VEC__ || __AIXVEC),
87# and doesn't hurt otherwise.
88AC_DEFUN([gl_FUNC_REALLOC_0_NONNULL],
89[
90 AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
91 AC_REQUIRE([AC_CANONICAL_HOST])dnl for cross-compiles
92 AC_REQUIRE([gl_FUNC_REALLOC_POSIX])
93 AC_CACHE_CHECK([whether realloc (..., 0) returns nonnull],
94 [gl_cv_func_realloc_0_nonnull],
95 [AC_RUN_IFELSE(
96 [AC_LANG_PROGRAM(
97 [[#include <stdlib.h>
98 /* Use prealloc to test; "volatile" prevents the compiler
99 from optimizing the realloc call away. */
100 void *(*volatile prealloc) (void *, size_t) = realloc;]],
101 [[void *p = prealloc (0, 0);
102 int result = !p;
103 p = prealloc (p, 0);
104 result |= !p;
105 free (p);
106 return result;]])],
107 [gl_cv_func_realloc_0_nonnull=yes],
108 [gl_cv_func_realloc_0_nonnull=no],
109 [AS_CASE([$host_os],
110 [# Guess yes on platforms where we know the result.
111 freebsd* | netbsd* | openbsd* | darwin* | bitrig* \
112 | *-musl* | midipix* | midnightbsd* \
113 | hpux* | solaris* | cygwin*],
114 [gl_cv_func_realloc_0_nonnull="guessing yes"],
115 [# Guess as follows if we don't know.
116 gl_cv_func_realloc_0_nonnull=$gl_cross_guess_normal])])])
117 AS_CASE([$gl_cv_func_realloc_0_nonnull],
118 [*yes],
119 [AC_DEFINE([HAVE_REALLOC_0_NONNULL], [1],
120 [Define to 1 if realloc (..., 0) returns nonnull.])],
121 [AS_CASE([$gl_cv_func_realloc_sanitize,$gl_cv_malloc_ptrdiff,$gl_cv_func_malloc_posix,$host],
122 [yes,*,*,* | *,no,*,* | *,*,*no,* | *,*,*,aarch64c-*-freebsd*],
123 [REPLACE_REALLOC_FOR_REALLOC_POSIX=1],
124 [# Optimize for common case of glibc 2.1.1+ and compatibles.
125 REPLACE_REALLOC_FOR_REALLOC_POSIX=2])])
126])
diff --git a/gl/m4/reallocarray.m4 b/gl/m4/reallocarray.m4
index 958095e1..3970d9e1 100644
--- a/gl/m4/reallocarray.m4
+++ b/gl/m4/reallocarray.m4
@@ -1,9 +1,10 @@
1# reallocarray.m4 1# reallocarray.m4
2# serial 5 2# serial 7
3dnl Copyright (C) 2017-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2017-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_REALLOCARRAY], 9AC_DEFUN([gl_FUNC_REALLOCARRAY],
9[ 10[
@@ -12,14 +13,21 @@ AC_DEFUN([gl_FUNC_REALLOCARRAY],
12 13
13 AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) 14 AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
14 AC_REQUIRE([gl_CHECK_MALLOC_PTRDIFF]) 15 AC_REQUIRE([gl_CHECK_MALLOC_PTRDIFF])
16 AC_REQUIRE([gl_FUNC_REALLOC_0_NONNULL])
15 gl_CHECK_FUNCS_ANDROID([reallocarray], [[#include <stdlib.h>]]) 17 gl_CHECK_FUNCS_ANDROID([reallocarray], [[#include <stdlib.h>]])
16 if test "$ac_cv_func_reallocarray" = no; then 18 if test "$ac_cv_func_reallocarray" = no; then
17 HAVE_REALLOCARRAY=0 19 HAVE_REALLOCARRAY=0
18 case "$gl_cv_onwards_func_reallocarray" in 20 case "$gl_cv_onwards_func_reallocarray" in
19 future*) REPLACE_REALLOCARRAY=1 ;; 21 future*) REPLACE_REALLOCARRAY=1 ;;
20 esac 22 esac
21 elif test "$gl_cv_malloc_ptrdiff" = no; then 23 else
22 REPLACE_REALLOCARRAY=1 24 if test "$gl_cv_malloc_ptrdiff" = no; then
25 REPLACE_REALLOCARRAY=1
26 fi
27 case "$gl_cv_func_realloc_0_nonnull" in
28 *yes) ;;
29 *) REPLACE_REALLOCARRAY=1 ;;
30 esac
23 fi 31 fi
24]) 32])
25 33
diff --git a/gl/m4/regex.m4 b/gl/m4/regex.m4
index f0101fe6..49a8059f 100644
--- a/gl/m4/regex.m4
+++ b/gl/m4/regex.m4
@@ -1,9 +1,10 @@
1# regex.m4 1# regex.m4
2# serial 75 2# serial 81
3dnl Copyright (C) 1996-2001, 2003-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 1996-2001, 2003-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Initially derived from code in GNU grep. 9dnl Initially derived from code in GNU grep.
9dnl Mostly written by Jim Meyering. 10dnl Mostly written by Jim Meyering.
@@ -39,19 +40,24 @@ AC_DEFUN([gl_REGEX],
39 #include <limits.h> 40 #include <limits.h>
40 #include <string.h> 41 #include <string.h>
41 42
42 #if defined M_CHECK_ACTION || HAVE_DECL_ALARM 43 #if HAVE_MALLOC_H
43 # include <signal.h> 44 # include <malloc.h> /* defines M_CHECK_ACTION on glibc */
44 # include <unistd.h>
45 #endif 45 #endif
46 46
47 #if HAVE_MALLOC_H 47 #if defined __HAIKU__ || defined M_CHECK_ACTION || HAVE_DECL_ALARM
48 # include <malloc.h> 48 # include <signal.h>
49 # include <unistd.h>
49 #endif 50 #endif
50 51
51 #ifdef M_CHECK_ACTION 52 #if defined __HAIKU__ || defined M_CHECK_ACTION
52 /* Exit with distinguishable exit code. */ 53 /* Exit with distinguishable exit code. */
53 static void sigabrt_no_core (int sig) { raise (SIGTERM); } 54 static void sigabrt_no_core (int sig) { raise (SIGTERM); }
54 #endif 55 #endif
56
57 /* There is no need to check whether RE_SYNTAX_EMACS is
58 (RE_CHAR_CLASSES | RE_INTERVALS), corresponding to
59 Emacs 21 (2001) and later, because Gnulib's lib/regex.h
60 is always used and has this value. */
55 ]], 61 ]],
56 [[int result = 0; 62 [[int result = 0;
57 static struct re_pattern_buffer regex; 63 static struct re_pattern_buffer regex;
@@ -67,6 +73,9 @@ AC_DEFUN([gl_REGEX],
67 signal (SIGALRM, SIG_DFL); 73 signal (SIGALRM, SIG_DFL);
68 alarm (2); 74 alarm (2);
69#endif 75#endif
76#ifdef __HAIKU__
77 signal (SIGABRT, sigabrt_no_core);
78#endif
70#ifdef M_CHECK_ACTION 79#ifdef M_CHECK_ACTION
71 signal (SIGABRT, sigabrt_no_core); 80 signal (SIGABRT, sigabrt_no_core);
72 mallopt (M_CHECK_ACTION, 2); 81 mallopt (M_CHECK_ACTION, 2);
@@ -388,7 +397,6 @@ AC_DEFUN([gl_PREREQ_REGEX],
388 AC_REQUIRE([AC_C_INLINE]) 397 AC_REQUIRE([AC_C_INLINE])
389 AC_REQUIRE([AC_C_RESTRICT]) 398 AC_REQUIRE([AC_C_RESTRICT])
390 AC_REQUIRE([AC_TYPE_MBSTATE_T]) 399 AC_REQUIRE([AC_TYPE_MBSTATE_T])
391 AC_REQUIRE([gl_EEMALLOC])
392 AC_CHECK_HEADERS([libintl.h]) 400 AC_CHECK_HEADERS([libintl.h])
393 AC_CHECK_FUNCS_ONCE([isblank iswctype]) 401 AC_CHECK_FUNCS_ONCE([isblank iswctype])
394 AC_CHECK_DECLS([isblank], [], [], [[#include <ctype.h>]]) 402 AC_CHECK_DECLS([isblank], [], [], [[#include <ctype.h>]])
diff --git a/gl/m4/sched_h.m4 b/gl/m4/sched_h.m4
new file mode 100644
index 00000000..1ffd465f
--- /dev/null
+++ b/gl/m4/sched_h.m4
@@ -0,0 +1,102 @@
1# sched_h.m4
2# serial 16
3dnl Copyright (C) 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9dnl Written by Bruno Haible.
10
11AC_DEFUN_ONCE([gl_SCHED_H],
12[
13 dnl Ensure to expand the default settings once only, before all statements
14 dnl that occur in other macros.
15 AC_REQUIRE([gl_SCHED_H_DEFAULTS])
16
17 AC_REQUIRE([AC_CANONICAL_HOST])
18
19 AC_REQUIRE([gl_CHECK_HEADER_SYS_CDEFS_H])
20
21 AC_CHECK_HEADERS([sched.h], [], [],
22 [[#if HAVE_SYS_CDEFS_H
23 #include <sys/cdefs.h>
24 #endif
25 ]])
26 gl_NEXT_HEADERS([sched.h])
27
28 if test "$ac_cv_header_sched_h" = yes; then
29 HAVE_SCHED_H=1
30 else
31 HAVE_SCHED_H=0
32 fi
33 AC_SUBST([HAVE_SCHED_H])
34
35 if test "$HAVE_SCHED_H" = 1; then
36 AC_CHECK_TYPE([struct sched_param],
37 [HAVE_STRUCT_SCHED_PARAM=1], [HAVE_STRUCT_SCHED_PARAM=0],
38 [[#if HAVE_SYS_CDEFS_H
39 #include <sys/cdefs.h>
40 #endif
41 #include <sched.h>
42 ]])
43 else
44 HAVE_STRUCT_SCHED_PARAM=0
45 case "$host_os" in
46 os2*)
47 dnl On OS/2 kLIBC, struct sched_param is in spawn.h.
48 AC_CHECK_TYPE([struct sched_param],
49 [HAVE_STRUCT_SCHED_PARAM=1], [],
50 [#include <spawn.h>])
51 ;;
52 vms)
53 dnl On OpenVMS 7.2 or newer, struct sched_param is in pthread.h.
54 AC_CHECK_TYPE([struct sched_param],
55 [HAVE_STRUCT_SCHED_PARAM=1], [],
56 [#include <pthread.h>])
57 ;;
58 esac
59 fi
60 AC_SUBST([HAVE_STRUCT_SCHED_PARAM])
61
62 dnl Ensure the type pid_t gets defined.
63 AC_REQUIRE([AC_TYPE_PID_T])
64
65 dnl Check for declarations of anything we want to poison if the
66 dnl corresponding gnulib module is not in use, if it is not common
67 dnl enough to be declared everywhere.
68 gl_WARN_ON_USE_PREPARE([[#include <sched.h>
69 ]], [sched_yield])
70])
71
72# gl_SCHED_MODULE_INDICATOR([modulename])
73# sets the shell variable that indicates the presence of the given module
74# to a C preprocessor expression that will evaluate to 1.
75# This macro invocation must not occur in macros that are AC_REQUIREd.
76AC_DEFUN([gl_SCHED_MODULE_INDICATOR],
77[
78 dnl Ensure to expand the default settings once only.
79 gl_SCHED_H_REQUIRE_DEFAULTS
80 gl_MODULE_INDICATOR_SET_VARIABLE([$1])
81 dnl Define it also as a C macro, for the benefit of the unit tests.
82 gl_MODULE_INDICATOR_FOR_TESTS([$1])
83])
84
85# Initializes the default values for AC_SUBSTed shell variables.
86# This macro must not be AC_REQUIREd. It must only be invoked, and only
87# outside of macros or in macros that are not AC_REQUIREd.
88AC_DEFUN([gl_SCHED_H_REQUIRE_DEFAULTS],
89[
90 m4_defun(GL_MODULE_INDICATOR_PREFIX[_SCHED_H_MODULE_INDICATOR_DEFAULTS], [
91 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SCHED_YIELD])
92 ])
93 m4_require(GL_MODULE_INDICATOR_PREFIX[_SCHED_H_MODULE_INDICATOR_DEFAULTS])
94 AC_REQUIRE([gl_SCHED_H_DEFAULTS])
95])
96
97AC_DEFUN([gl_SCHED_H_DEFAULTS],
98[
99 dnl Assume proper GNU behavior unless another module says otherwise.
100 HAVE_SCHED_YIELD=1; AC_SUBST([HAVE_SCHED_YIELD])
101 REPLACE_SCHED_YIELD=0; AC_SUBST([REPLACE_SCHED_YIELD])
102])
diff --git a/gl/m4/servent.m4 b/gl/m4/servent.m4
index 422003b4..ba6ebd1d 100644
--- a/gl/m4/servent.m4
+++ b/gl/m4/servent.m4
@@ -1,9 +1,10 @@
1# servent.m4 1# servent.m4
2# serial 5 2# serial 5
3dnl Copyright (C) 2008, 2010-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2008, 2010-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_SERVENT], 9AC_DEFUN([gl_SERVENT],
9[ 10[
diff --git a/gl/m4/setenv.m4 b/gl/m4/setenv.m4
index e7f00f39..727e35af 100644
--- a/gl/m4/setenv.m4
+++ b/gl/m4/setenv.m4
@@ -1,9 +1,10 @@
1# setenv.m4 1# setenv.m4
2# serial 33 2# serial 35
3dnl Copyright (C) 2001-2004, 2006-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2001-2004, 2006-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_SETENV], 9AC_DEFUN([gl_FUNC_SETENV],
9[ 10[
@@ -155,6 +156,7 @@ AC_DEFUN([gl_PREREQ_SETENV],
155 AC_REQUIRE([gl_ENVIRON]) 156 AC_REQUIRE([gl_ENVIRON])
156 AC_CHECK_HEADERS_ONCE([unistd.h]) 157 AC_CHECK_HEADERS_ONCE([unistd.h])
157 AC_CHECK_HEADERS([search.h]) 158 AC_CHECK_HEADERS([search.h])
159 AC_CHECK_DECLS_ONCE([_putenv])
158 gl_CHECK_FUNCS_ANDROID([tsearch], [[#include <search.h>]]) 160 gl_CHECK_FUNCS_ANDROID([tsearch], [[#include <search.h>]])
159]) 161])
160 162
@@ -163,4 +165,5 @@ AC_DEFUN([gl_PREREQ_UNSETENV],
163[ 165[
164 AC_REQUIRE([gl_ENVIRON]) 166 AC_REQUIRE([gl_ENVIRON])
165 AC_CHECK_HEADERS_ONCE([unistd.h]) 167 AC_CHECK_HEADERS_ONCE([unistd.h])
168 AC_CHECK_DECLS_ONCE([_putenv])
166]) 169])
diff --git a/gl/m4/setlocale_null.m4 b/gl/m4/setlocale_null.m4
index e5b7d28b..3c8b693e 100644
--- a/gl/m4/setlocale_null.m4
+++ b/gl/m4/setlocale_null.m4
@@ -1,11 +1,12 @@
1# setlocale_null.m4 1# setlocale_null.m4
2# serial 9 2# serial 10
3dnl Copyright (C) 2019-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2019-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_SETLOCALE_NULL], 9AC_DEFUN_ONCE([gl_FUNC_SETLOCALE_NULL],
9[ 10[
10 AC_REQUIRE([AC_CANONICAL_HOST]) 11 AC_REQUIRE([AC_CANONICAL_HOST])
11 AC_REQUIRE([gl_PTHREADLIB]) 12 AC_REQUIRE([gl_PTHREADLIB])
diff --git a/gl/m4/sha256.m4 b/gl/m4/sha256.m4
index ad5596a4..30e8deeb 100644
--- a/gl/m4/sha256.m4
+++ b/gl/m4/sha256.m4
@@ -1,9 +1,10 @@
1# sha256.m4 1# sha256.m4
2# serial 8 2# serial 8
3dnl Copyright (C) 2005, 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2005, 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_SHA256], 9AC_DEFUN([gl_SHA256],
9[ 10[
diff --git a/gl/m4/size_max.m4 b/gl/m4/size_max.m4
index df91cf06..b0460d45 100644
--- a/gl/m4/size_max.m4
+++ b/gl/m4/size_max.m4
@@ -1,9 +1,10 @@
1# size_max.m4 1# size_max.m4
2# serial 12 2# serial 12
3dnl Copyright (C) 2003, 2005-2006, 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2003, 2005-2006, 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Bruno Haible. 9dnl From Bruno Haible.
9 10
diff --git a/gl/m4/snprintf.m4 b/gl/m4/snprintf.m4
index 6dbe146f..2c50cee9 100644
--- a/gl/m4/snprintf.m4
+++ b/gl/m4/snprintf.m4
@@ -1,9 +1,10 @@
1# snprintf.m4 1# snprintf.m4
2# serial 7 2# serial 7
3dnl Copyright (C) 2002-2004, 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2002-2004, 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Libintl 0.17 will replace snprintf only if it does not support %1$s, 9dnl Libintl 0.17 will replace snprintf only if it does not support %1$s,
9dnl but defers to any gnulib snprintf replacements. Therefore, gnulib 10dnl but defers to any gnulib snprintf replacements. Therefore, gnulib
diff --git a/gl/m4/socketlib.m4 b/gl/m4/socketlib.m4
index 09f01161..e3509f81 100644
--- a/gl/m4/socketlib.m4
+++ b/gl/m4/socketlib.m4
@@ -1,9 +1,10 @@
1# socketlib.m4 1# socketlib.m4
2# serial 4 2# serial 4
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl gl_SOCKETLIB 9dnl gl_SOCKETLIB
9dnl Determines the library to use for socket functions. 10dnl Determines the library to use for socket functions.
diff --git a/gl/m4/sockets.m4 b/gl/m4/sockets.m4
index a3dfe92f..54f4dc79 100644
--- a/gl/m4/sockets.m4
+++ b/gl/m4/sockets.m4
@@ -1,9 +1,10 @@
1# sockets.m4 1# sockets.m4
2# serial 7 2# serial 7
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_SOCKETS], 9AC_DEFUN([gl_SOCKETS],
9[ 10[
diff --git a/gl/m4/socklen.m4 b/gl/m4/socklen.m4
index 9ece0abb..a8ac25b1 100644
--- a/gl/m4/socklen.m4
+++ b/gl/m4/socklen.m4
@@ -1,9 +1,10 @@
1# socklen.m4 1# socklen.m4
2# serial 11 2# serial 11
3dnl Copyright (C) 2005-2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2005-2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Albert Chin, Windows fixes from Simon Josefsson. 9dnl From Albert Chin, Windows fixes from Simon Josefsson.
9 10
diff --git a/gl/m4/sockpfaf.m4 b/gl/m4/sockpfaf.m4
index c68b3abb..08ce843d 100644
--- a/gl/m4/sockpfaf.m4
+++ b/gl/m4/sockpfaf.m4
@@ -1,9 +1,10 @@
1# sockpfaf.m4 1# sockpfaf.m4
2# serial 10 2# serial 11
3dnl Copyright (C) 2004, 2006, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2004, 2006, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Test for some common socket protocol families (PF_INET, PF_INET6, ...) 9dnl Test for some common socket protocol families (PF_INET, PF_INET6, ...)
9dnl and some common address families (AF_INET, AF_INET6, ...). 10dnl and some common address families (AF_INET, AF_INET6, ...).
@@ -64,6 +65,13 @@ AC_DEFUN([gl_SOCKET_FAMILY_UNIX],
64 AC_REQUIRE([gl_SYS_SOCKET_H]) 65 AC_REQUIRE([gl_SYS_SOCKET_H])
65 AC_CHECK_HEADERS_ONCE([sys/un.h]) 66 AC_CHECK_HEADERS_ONCE([sys/un.h])
66 67
68 dnl Windows versions released after 2017 may have support for AF_UNIX.
69 dnl Including it requires types from <winsock2.h> to be defined.
70 dnl <https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/>.
71 if test "$ac_cv_header_winsock2_h" = yes; then
72 AC_CHECK_HEADERS([afunix.h], [], [], [#include <winsock2.h>])
73 fi
74
67 AC_CACHE_CHECK([for UNIX domain sockets], 75 AC_CACHE_CHECK([for UNIX domain sockets],
68 [gl_cv_socket_unix], 76 [gl_cv_socket_unix],
69 [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h> 77 [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
@@ -75,6 +83,9 @@ AC_DEFUN([gl_SOCKET_FAMILY_UNIX],
75#endif 83#endif
76#ifdef HAVE_WINSOCK2_H 84#ifdef HAVE_WINSOCK2_H
77#include <winsock2.h> 85#include <winsock2.h>
86#endif
87#ifdef HAVE_AFUNIX_H
88#include <afunix.h>
78#endif]], 89#endif]],
79[[int x = AF_UNIX; struct sockaddr_un y; 90[[int x = AF_UNIX; struct sockaddr_un y;
80 if (&x && &y) return 0;]])], 91 if (&x && &y) return 0;]])],
diff --git a/gl/m4/ssize_t.m4 b/gl/m4/ssize_t.m4
index c15f948a..a2ffd6fc 100644
--- a/gl/m4/ssize_t.m4
+++ b/gl/m4/ssize_t.m4
@@ -1,9 +1,10 @@
1# ssize_t.m4 1# ssize_t.m4
2# serial 6 2# serial 6
3dnl Copyright (C) 2001-2003, 2006, 2010-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2001-2003, 2006, 2010-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Bruno Haible. 9dnl From Bruno Haible.
9dnl Define ssize_t if it does not already exist. 10dnl Define ssize_t if it does not already exist.
diff --git a/gl/m4/stat-time.m4 b/gl/m4/stat-time.m4
index e8ee7d51..4aa24e7f 100644
--- a/gl/m4/stat-time.m4
+++ b/gl/m4/stat-time.m4
@@ -1,9 +1,11 @@
1# stat-time.m4 1# stat-time.m4
2# serial 1 2# serial 1
3dnl Copyright (C) 1998-1999, 2001, 2003, 2005-2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 1998-1999, 2001, 2003, 2005-2007, 2009-2025 Free Software
4dnl Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 5dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 6dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 7dnl with or without modifications, as long as this notice is preserved.
8dnl This file is offered as-is, without any warranty.
7 9
8# Checks for stat-related time functions. 10# Checks for stat-related time functions.
9 11
diff --git a/gl/m4/stat.m4 b/gl/m4/stat.m4
index fabd360c..66876305 100644
--- a/gl/m4/stat.m4
+++ b/gl/m4/stat.m4
@@ -1,9 +1,10 @@
1# stat.m4 1# stat.m4
2# serial 21 2# serial 21
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_STAT], 9AC_DEFUN([gl_FUNC_STAT],
9[ 10[
diff --git a/gl/m4/std-gnu11.m4 b/gl/m4/std-gnu11.m4
index 37324c15..762764e0 100644
--- a/gl/m4/std-gnu11.m4
+++ b/gl/m4/std-gnu11.m4
@@ -1,22 +1,27 @@
1# std-gnu11.m4 1# std-gnu11.m4
2# serial 1 2# serial 3
3 3
4# Prefer GNU C11 and C++11 to earlier versions. -*- coding: utf-8 -*- 4# Prefer GNU C11 and C++11 to earlier versions. -*- coding: utf-8 -*-
5 5
6# The std-gnu23 module, which defines _AC_C_C23_OPTIONS, supersedes us.
7m4_ifndef([_AC_C_C23_OPTIONS], [
8
6# This implementation is taken from GNU Autoconf lib/autoconf/c.m4 9# This implementation is taken from GNU Autoconf lib/autoconf/c.m4
7# commit 017d5ddd82854911f0119691d91ea8a1438824d6 10# commit 017d5ddd82854911f0119691d91ea8a1438824d6
8# dated Sun Apr 3 13:57:17 2016 -0700 11# dated Sun Apr 3 13:57:17 2016 -0700
12# with minor changes to commentary.
9# This implementation will be obsolete once we can assume Autoconf 2.70 13# This implementation will be obsolete once we can assume Autoconf 2.70
10# or later is installed everywhere a Gnulib program might be developed. 14# or later is installed everywhere a Gnulib program might be developed.
11 15
12m4_version_prereq([2.70], [], [ 16m4_version_prereq([2.70], [], [
13 17
14 18
15# Copyright (C) 2001-2024 Free Software Foundation, Inc. 19# Copyright (C) 2001-2025 Free Software Foundation, Inc.
16 20
17# This program is free software; you can redistribute it and/or modify 21# This file is part of Autoconf. This program is free
18# it under the terms of the GNU General Public License as published by 22# software; you can redistribute it and/or modify it under the
19# the Free Software Foundation, either version 3 of the License, or 23# terms of the GNU General Public License as published by the
24# Free Software Foundation, either version 3 of the License, or
20# (at your option) any later version. 25# (at your option) any later version.
21# 26#
22# This program is distributed in the hope that it will be useful, 27# This program is distributed in the hope that it will be useful,
@@ -24,8 +29,15 @@ m4_version_prereq([2.70], [], [
24# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25# GNU General Public License for more details. 30# GNU General Public License for more details.
26# 31#
32# Under Section 7 of GPL version 3, you are granted additional
33# permissions described in the Autoconf Configure Script Exception,
34# version 3.0, as published by the Free Software Foundation.
35#
27# You should have received a copy of the GNU General Public License 36# You should have received a copy of the GNU General Public License
28# along with this program. If not, see <https://www.gnu.org/licenses/>. 37# and a copy of the Autoconf Configure Script Exception along with
38# this program; see the files COPYINGv3 and COPYING.EXCEPTION
39# respectively. If not, see <https://www.gnu.org/licenses/> and
40# <https://git.savannah.gnu.org/gitweb/?p=autoconf.git;a=blob_plain;f=COPYING.EXCEPTION>.
29 41
30# Written by David MacKenzie, with help from 42# Written by David MacKenzie, with help from
31# Akim Demaille, Paul Eggert, 43# Akim Demaille, Paul Eggert,
@@ -38,7 +50,7 @@ m4_version_prereq([2.70], [], [
38# COMPILER ... is a space separated list of C compilers to search for. 50# COMPILER ... is a space separated list of C compilers to search for.
39# This just gives the user an opportunity to specify an alternative 51# This just gives the user an opportunity to specify an alternative
40# search list for the C compiler. 52# search list for the C compiler.
41AC_DEFUN_ONCE([AC_PROG_CC], 53AC_DEFUN([AC_PROG_CC],
42[AC_LANG_PUSH(C)dnl 54[AC_LANG_PUSH(C)dnl
43AC_ARG_VAR([CC], [C compiler command])dnl 55AC_ARG_VAR([CC], [C compiler command])dnl
44AC_ARG_VAR([CFLAGS], [C compiler flags])dnl 56AC_ARG_VAR([CFLAGS], [C compiler flags])dnl
@@ -830,3 +842,4 @@ dnl with extended modes being tried first.
830 842
831 843
832])# m4_version_prereq 844])# m4_version_prereq
845])# !_AC_C_C23_OPTIONS
diff --git a/gl/m4/stdalign.m4 b/gl/m4/stdalign.m4
index 2b4762f3..885feafd 100644
--- a/gl/m4/stdalign.m4
+++ b/gl/m4/stdalign.m4
@@ -1,9 +1,10 @@
1# stdalign.m4 1# stdalign.m4
2# serial 1 2# serial 3
3dnl Copyright 2011-2024 Free Software Foundation, Inc. 3dnl Copyright 2011-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Check for alignas and alignof that conform to C23. 9# Check for alignas and alignof that conform to C23.
9 10
@@ -81,10 +82,10 @@ AC_DEFUN([gl_ALIGNASOF],
81 82
82 References: 83 References:
83 ISO C23 (latest free draft 84 ISO C23 (latest free draft
84 <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.pdf>) 85 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf>)
85 sections 6.5.3.4, 6.7.5, 7.15. 86 sections 6.5.3.4, 6.7.5, 7.15.
86 C++11 (latest free draft 87 C++11 (latest free draft
87 <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf>) 88 <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf>)
88 section 18.10. */ 89 section 18.10. */
89 90
90/* alignof (TYPE), also known as _Alignof (TYPE), yields the alignment 91/* alignof (TYPE), also known as _Alignof (TYPE), yields the alignment
@@ -103,11 +104,13 @@ AC_DEFUN([gl_ALIGNASOF],
103 104
104/* GCC releases before GCC 4.9 had a bug in _Alignof. See GCC bug 52023 105/* GCC releases before GCC 4.9 had a bug in _Alignof. See GCC bug 52023
105 <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023>. 106 <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023>.
106 clang versions < 8.0.0 have the same bug. */ 107 clang versions < 8.0.0 have the same bug.
108 IBM XL C V16.1.0 cc (non-clang) has the same bug. */
107# if (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 \ 109# if (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 \
108 || (defined __GNUC__ && __GNUC__ < 4 + (__GNUC_MINOR__ < 9) \ 110 || (defined __GNUC__ && __GNUC__ < 4 + (__GNUC_MINOR__ < 9) \
109 && !defined __clang__) \ 111 && !defined __clang__) \
110 || (defined __clang__ && __clang_major__ < 8)) 112 || (defined __clang__ && __clang_major__ < 8) \
113 || defined __xlC__)
111# undef/**/_Alignof 114# undef/**/_Alignof
112# ifdef __cplusplus 115# ifdef __cplusplus
113# if (201103 <= __cplusplus || defined _MSC_VER) 116# if (201103 <= __cplusplus || defined _MSC_VER)
@@ -178,7 +181,8 @@ AC_DEFUN([gl_ALIGNASOF],
178# if ((defined _Alignas \ 181# if ((defined _Alignas \
179 && !(defined __cplusplus \ 182 && !(defined __cplusplus \
180 && (201103 <= __cplusplus || defined _MSC_VER))) \ 183 && (201103 <= __cplusplus || defined _MSC_VER))) \
181 || (defined __STDC_VERSION__ && 201112 <= __STDC_VERSION__)) 184 || (defined __STDC_VERSION__ && 201112 <= __STDC_VERSION__ \
185 && !defined __xlC__))
182# define alignas _Alignas 186# define alignas _Alignas
183# endif 187# endif
184# endif 188# endif
diff --git a/gl/m4/stdckdint_h.m4 b/gl/m4/stdckdint_h.m4
new file mode 100644
index 00000000..d269faa5
--- /dev/null
+++ b/gl/m4/stdckdint_h.m4
@@ -0,0 +1,136 @@
1# stdckdint_h.m4
2# serial 1
3dnl Copyright 2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9dnl Written by Collin Funk.
10
11AC_DEFUN_ONCE([gl_STDCKDINT_H],
12[
13 gl_CHECK_NEXT_HEADERS([stdckdint.h])
14 if test $ac_cv_header_stdckdint_h = yes; then
15 HAVE_STDCKDINT_H=1
16 else
17 HAVE_STDCKDINT_H=0
18 fi
19 AC_SUBST([HAVE_STDCKDINT_H])
20
21 if test $HAVE_STDCKDINT_H = 1; then
22 AC_CACHE_CHECK([whether stdckdint.h can be included in C],
23 [gl_cv_header_c_stdckdint_h],
24 [AC_COMPILE_IFELSE(
25 [AC_LANG_PROGRAM(
26 [[#include <stdckdint.h>
27 ]])],
28 [gl_cv_header_c_stdckdint_h=yes],
29 [gl_cv_header_c_stdckdint_h=no])])
30 if test $gl_cv_header_c_stdckdint_h = yes; then
31 HAVE_C_STDCKDINT_H=1
32 AC_CACHE_CHECK([checking for an ISO C23 compliant stdckdint.h in C],
33 [gl_cv_header_c_stdckdint_h_works],
34 [AC_COMPILE_IFELSE(
35 [AC_LANG_PROGRAM(
36 [[#include <stdckdint.h>
37 ]],
38 [[int r;
39 int a = 1;
40 int b = 1;
41 return !!(ckd_add (&r, a, b) || ckd_sub (&r, a, b)
42 || ckd_mul (&r, a, b));
43 ]])],
44 [gl_cv_header_c_stdckdint_h_works=yes],
45 [gl_cv_header_c_stdckdint_h_works=no])])
46 if test $gl_cv_header_c_stdckdint_h_works = yes; then
47 HAVE_WORKING_C_STDCKDINT_H=1
48 else
49 HAVE_WORKING_C_STDCKDINT_H=0
50 fi
51 else
52 HAVE_C_STDCKDINT_H=0
53 HAVE_WORKING_C_STDCKDINT_H=0
54 fi
55 if test "$CXX" != no; then
56 AC_CACHE_CHECK([whether stdckdint.h can be included in C++],
57 [gl_cv_header_cxx_stdckdint_h],
58 [dnl We can't use AC_LANG_PUSH([C++]) and AC_LANG_POP([C++]) here, due to
59 dnl an autoconf bug <https://savannah.gnu.org/support/?110294>.
60 cat > conftest.cpp <<\EOF
61#include <stdckdint.h>
62EOF
63 gl_command="$CXX $CXXFLAGS $CPPFLAGS -c conftest.cpp"
64 if AC_TRY_EVAL([gl_command]); then
65 gl_cv_header_cxx_stdckdint_h=yes
66 else
67 gl_cv_header_cxx_stdckdint_h=no
68 fi
69 rm -fr conftest*
70 ])
71 if test $gl_cv_header_cxx_stdckdint_h = yes; then
72 HAVE_CXX_STDCKDINT_H=1
73 AC_CACHE_CHECK([checking for an ISO C++26 compliant stdckdint.h in C++],
74 [gl_cv_header_cxx_stdckdint_h_works],
75 [dnl We can't use AC_LANG_PUSH([C++]) and AC_LANG_POP([C++]) here, due to
76 dnl an autoconf bug <https://savannah.gnu.org/support/?110294>.
77 cat > conftest.cpp <<\EOF
78#include <stdckdint.h>
79int
80main (void)
81{
82 int r;
83 int a = 1;
84 int b = 1;
85 return !!(ckd_add (&r, a, b) || ckd_sub (&r, a, b) || ckd_mul (&r, a, b));
86}
87EOF
88 gl_command="$CXX $CXXFLAGS $CPPFLAGS -c conftest.cpp"
89 if AC_TRY_EVAL([gl_command]); then
90 gl_cv_header_cxx_stdckdint_h_works=yes
91 else
92 gl_cv_header_cxx_stdckdint_h_works=no
93 fi
94 rm -fr conftest*
95 ])
96 if test $gl_cv_header_cxx_stdckdint_h_works = yes; then
97 HAVE_WORKING_CXX_STDCKDINT_H=1
98 else
99 HAVE_WORKING_CXX_STDCKDINT_H=0
100 fi
101 else
102 HAVE_CXX_STDCKDINT_H=0
103 HAVE_WORKING_CXX_STDCKDINT_H=0
104 fi
105 fi
106 else
107 HAVE_C_STDCKDINT_H=0
108 HAVE_WORKING_C_STDCKDINT_H=0
109 HAVE_CXX_STDCKDINT_H=0
110 HAVE_WORKING_CXX_STDCKDINT_H=0
111 fi
112 AC_SUBST([HAVE_C_STDCKDINT_H])
113 AC_SUBST([HAVE_WORKING_C_STDCKDINT_H])
114 AC_SUBST([HAVE_CXX_STDCKDINT_H])
115 AC_SUBST([HAVE_WORKING_CXX_STDCKDINT_H])
116
117 if test "$CXX" != no; then
118 dnl We might need the header for C or C++.
119 if test $HAVE_C_STDCKDINT_H = 1 \
120 && test $HAVE_WORKING_C_STDCKDINT_H = 1 \
121 && test $HAVE_CXX_STDCKDINT_H = 1 \
122 && test $HAVE_WORKING_CXX_STDCKDINT_H = 1; then
123 GL_GENERATE_STDCKDINT_H=false
124 else
125 GL_GENERATE_STDCKDINT_H=true
126 fi
127 else
128 dnl We don't care about C++ here.
129 if test $HAVE_C_STDCKDINT_H = 1 \
130 && test $HAVE_WORKING_C_STDCKDINT_H = 1; then
131 GL_GENERATE_STDCKDINT_H=false
132 else
133 GL_GENERATE_STDCKDINT_H=true
134 fi
135 fi
136])
diff --git a/gl/m4/stddef_h.m4 b/gl/m4/stddef_h.m4
index 84d3bae8..127ec05b 100644
--- a/gl/m4/stddef_h.m4
+++ b/gl/m4/stddef_h.m4
@@ -1,16 +1,16 @@
1# stddef_h.m4 1# stddef_h.m4
2# serial 14 2# serial 23
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl A placeholder for <stddef.h>, for platforms that have issues. 9dnl A placeholder for <stddef.h>, for platforms that have issues.
9 10
10AC_DEFUN_ONCE([gl_STDDEF_H], 11AC_DEFUN_ONCE([gl_STDDEF_H],
11[ 12[
12 AC_REQUIRE([gl_STDDEF_H_DEFAULTS]) 13 AC_REQUIRE([gl_STDDEF_H_DEFAULTS])
13 AC_REQUIRE([gt_TYPE_WCHAR_T])
14 14
15 dnl Persuade OpenBSD <stddef.h> to declare max_align_t. 15 dnl Persuade OpenBSD <stddef.h> to declare max_align_t.
16 AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) 16 AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
@@ -52,11 +52,6 @@ AC_DEFUN_ONCE([gl_STDDEF_H],
52 GL_GENERATE_STDDEF_H=true 52 GL_GENERATE_STDDEF_H=true
53 fi 53 fi
54 54
55 if test $gt_cv_c_wchar_t = no; then
56 HAVE_WCHAR_T=0
57 GL_GENERATE_STDDEF_H=true
58 fi
59
60 AC_CACHE_CHECK([whether NULL can be used in arbitrary expressions], 55 AC_CACHE_CHECK([whether NULL can be used in arbitrary expressions],
61 [gl_cv_decl_null_works], 56 [gl_cv_decl_null_works],
62 [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <stddef.h> 57 [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <stddef.h>
@@ -69,21 +64,60 @@ AC_DEFUN_ONCE([gl_STDDEF_H],
69 GL_GENERATE_STDDEF_H=true 64 GL_GENERATE_STDDEF_H=true
70 fi 65 fi
71 66
72 AC_CACHE_CHECK([for unreachable], 67 AC_CACHE_CHECK([for unreachable in C],
73 [gl_cv_func_unreachable], 68 [gl_cv_c_func_unreachable],
74 [AC_LINK_IFELSE( 69 [AC_LINK_IFELSE(
75 [AC_LANG_PROGRAM( 70 [AC_LANG_PROGRAM(
76 [[#include <stddef.h> 71 [[#include <stddef.h>
77 ]], 72 ]],
78 [[unreachable (); 73 [[unreachable ();
79 ]])], 74 ]])],
80 [gl_cv_func_unreachable=yes], 75 [gl_cv_c_func_unreachable=yes],
81 [gl_cv_func_unreachable=no]) 76 [gl_cv_c_func_unreachable=no])
82 ]) 77 ])
83 if test $gl_cv_func_unreachable = no; then 78 if test $gl_cv_c_func_unreachable = no; then
79 GL_GENERATE_STDDEF_H=true
80 HAVE_C_UNREACHABLE=0
81 else
82 HAVE_C_UNREACHABLE=1
83 fi
84 AC_SUBST([HAVE_C_UNREACHABLE])
85 dnl Provide gl_unreachable() unconditionally.
86 GL_GENERATE_STDDEF_H=true
87
88 dnl https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114869
89 AC_CACHE_CHECK([whether nullptr_t needs <stddef.h>],
90 [gl_cv_nullptr_t_needs_stddef],
91 [AC_COMPILE_IFELSE([AC_LANG_DEFINES_PROVIDED[nullptr_t x;]],
92 [gl_cv_nullptr_t_needs_stddef=no],
93 [gl_cv_nullptr_t_needs_stddef=yes])])
94 if test "$gl_cv_nullptr_t_needs_stddef" = no; then
95 NULLPTR_T_NEEDS_STDDEF=0
84 GL_GENERATE_STDDEF_H=true 96 GL_GENERATE_STDDEF_H=true
85 fi 97 fi
86 98
99 dnl https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114870
100 dnl affects GCC 13.3 and 14.2.
101 AC_CACHE_CHECK([whether <stddef.h> is idempotent],
102 [gl_cv_stddef_idempotent],
103 [AC_COMPILE_IFELSE([AC_LANG_SOURCE(
104 [[
105 #if \
106 ((__GNUC__ == 13 && __GNUC_MINOR__ <= 3) \
107 || (__GNUC__ == 14 && __GNUC_MINOR__ <= 2))
108 #error "bug 114870 is present"
109 #endif
110 ]])],
111 [gl_cv_stddef_idempotent="guessing yes"],
112 [gl_cv_stddef_idempotent="guessing no"])
113 ])
114 case "$gl_cv_stddef_idempotent" in
115 *yes) ;;
116 *) STDDEF_NOT_IDEMPOTENT=1
117 GL_GENERATE_STDDEF_H=true
118 ;;
119 esac
120
87 if $GL_GENERATE_STDDEF_H; then 121 if $GL_GENERATE_STDDEF_H; then
88 gl_NEXT_HEADERS([stddef.h]) 122 gl_NEXT_HEADERS([stddef.h])
89 fi 123 fi
@@ -114,7 +148,8 @@ AC_DEFUN([gl_STDDEF_H_REQUIRE_DEFAULTS],
114AC_DEFUN([gl_STDDEF_H_DEFAULTS], 148AC_DEFUN([gl_STDDEF_H_DEFAULTS],
115[ 149[
116 dnl Assume proper GNU behavior unless another module says otherwise. 150 dnl Assume proper GNU behavior unless another module says otherwise.
151 NULLPTR_T_NEEDS_STDDEF=1; AC_SUBST([NULLPTR_T_NEEDS_STDDEF])
152 STDDEF_NOT_IDEMPOTENT=0; AC_SUBST([STDDEF_NOT_IDEMPOTENT])
117 REPLACE_NULL=0; AC_SUBST([REPLACE_NULL]) 153 REPLACE_NULL=0; AC_SUBST([REPLACE_NULL])
118 HAVE_MAX_ALIGN_T=1; AC_SUBST([HAVE_MAX_ALIGN_T]) 154 HAVE_MAX_ALIGN_T=1; AC_SUBST([HAVE_MAX_ALIGN_T])
119 HAVE_WCHAR_T=1; AC_SUBST([HAVE_WCHAR_T])
120]) 155])
diff --git a/gl/m4/stdint.m4 b/gl/m4/stdint.m4
index 2dea8469..2d69088b 100644
--- a/gl/m4/stdint.m4
+++ b/gl/m4/stdint.m4
@@ -1,9 +1,10 @@
1# stdint.m4 1# stdint.m4
2# serial 63 2# serial 64
3dnl Copyright (C) 2001-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2001-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Paul Eggert and Bruno Haible. 9dnl From Paul Eggert and Bruno Haible.
9dnl Test whether <stdint.h> is supported or must be substituted. 10dnl Test whether <stdint.h> is supported or must be substituted.
@@ -157,7 +158,7 @@ uintmax_t j = UINTMAX_MAX;
157 || defined __clang__) 158 || defined __clang__)
158int k = _Generic (SIZE_MAX, size_t: 0); 159int k = _Generic (SIZE_MAX, size_t: 0);
159#elif (2 <= __GNUC__ || 4 <= __clang_major__ || defined __IBM__TYPEOF__ \ 160#elif (2 <= __GNUC__ || 4 <= __clang_major__ || defined __IBM__TYPEOF__ \
160 || (0x5110 <= __SUNPRO_C && !__STDC__)) 161 || (0x5110 <= __SUNPRO_C && !__STDC__) || 1939 <= _MSC_VER)
161extern size_t k; 162extern size_t k;
162extern __typeof__ (SIZE_MAX) k; 163extern __typeof__ (SIZE_MAX) k;
163#endif 164#endif
diff --git a/gl/m4/stdint_h.m4 b/gl/m4/stdint_h.m4
index 29f42160..d4f1acdd 100644
--- a/gl/m4/stdint_h.m4
+++ b/gl/m4/stdint_h.m4
@@ -1,9 +1,10 @@
1# stdint_h.m4 1# stdint_h.m4
2# serial 9 2# serial 9
3dnl Copyright (C) 1997-2004, 2006, 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 1997-2004, 2006, 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Paul Eggert. 9dnl From Paul Eggert.
9 10
diff --git a/gl/m4/stdio_h.m4 b/gl/m4/stdio_h.m4
index 8eb5816a..71d86180 100644
--- a/gl/m4/stdio_h.m4
+++ b/gl/m4/stdio_h.m4
@@ -1,9 +1,10 @@
1# stdio_h.m4 1# stdio_h.m4
2# serial 63 2# serial 75
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_STDIO_H_EARLY], 9AC_DEFUN([gl_STDIO_H_EARLY],
9[ 10[
@@ -133,6 +134,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS],
133[ 134[
134 m4_defun(GL_MODULE_INDICATOR_PREFIX[_STDIO_H_MODULE_INDICATOR_DEFAULTS], [ 135 m4_defun(GL_MODULE_INDICATOR_PREFIX[_STDIO_H_MODULE_INDICATOR_DEFAULTS], [
135 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DPRINTF]) 136 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DPRINTF])
137 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DZPRINTF])
136 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FCLOSE]) 138 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FCLOSE])
137 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FDOPEN]) 139 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FDOPEN])
138 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FFLUSH]) 140 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FFLUSH])
@@ -153,12 +155,14 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS],
153 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FTELL]) 155 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FTELL])
154 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FTELLO]) 156 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FTELLO])
155 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FWRITE]) 157 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FWRITE])
158 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FZPRINTF])
156 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETC]) 159 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETC])
157 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETCHAR]) 160 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETCHAR])
158 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETDELIM]) 161 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETDELIM])
159 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLINE]) 162 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLINE])
160 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OBSTACK_PRINTF]) 163 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OBSTACK_PRINTF])
161 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OBSTACK_PRINTF_POSIX]) 164 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OBSTACK_PRINTF_POSIX])
165 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OBSTACK_ZPRINTF])
162 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PCLOSE]) 166 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PCLOSE])
163 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PERROR]) 167 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PERROR])
164 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_POPEN]) 168 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_POPEN])
@@ -172,20 +176,29 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS],
172 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RENAMEAT]) 176 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RENAMEAT])
173 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SCANF]) 177 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SCANF])
174 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SNPRINTF]) 178 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SNPRINTF])
179 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SNZPRINTF])
175 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SPRINTF_POSIX]) 180 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SPRINTF_POSIX])
176 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDIO_H_NONBLOCKING]) 181 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDIO_H_NONBLOCKING])
177 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDIO_H_SIGPIPE]) 182 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDIO_H_SIGPIPE])
183 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SZPRINTF])
178 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TMPFILE]) 184 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TMPFILE])
179 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VASPRINTF]) 185 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VASPRINTF])
186 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VASZPRINTF])
180 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFSCANF]) 187 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFSCANF])
181 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSCANF]) 188 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSCANF])
182 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VDPRINTF]) 189 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VDPRINTF])
190 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VDZPRINTF])
183 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFPRINTF]) 191 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFPRINTF])
184 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFPRINTF_POSIX]) 192 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFPRINTF_POSIX])
193 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFZPRINTF])
185 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VPRINTF]) 194 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VPRINTF])
186 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VPRINTF_POSIX]) 195 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VPRINTF_POSIX])
187 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSNPRINTF]) 196 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSNPRINTF])
197 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSNZPRINTF])
188 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSPRINTF_POSIX]) 198 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSPRINTF_POSIX])
199 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSZPRINTF])
200 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZPRINTF])
201 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ZPRINTF])
189 dnl Support Microsoft deprecated alias function names by default. 202 dnl Support Microsoft deprecated alias function names by default.
190 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCLOSEALL], [1]) 203 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCLOSEALL], [1])
191 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FDOPEN], [1]) 204 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FDOPEN], [1])
diff --git a/gl/m4/stdlib_h.m4 b/gl/m4/stdlib_h.m4
index a4662f29..2d25da37 100644
--- a/gl/m4/stdlib_h.m4
+++ b/gl/m4/stdlib_h.m4
@@ -1,9 +1,10 @@
1# stdlib_h.m4 1# stdlib_h.m4
2# serial 77 2# serial 84
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN_ONCE([gl_STDLIB_H], 9AC_DEFUN_ONCE([gl_STDLIB_H],
9[ 10[
@@ -37,44 +38,51 @@ AC_DEFUN_ONCE([gl_STDLIB_H],
37 dnl On Solaris 10, in UTF-8 locales, its value is 3 but needs to be 4. 38 dnl On Solaris 10, in UTF-8 locales, its value is 3 but needs to be 4.
38 dnl Fortunately, we can do this because on this platform MB_LEN_MAX is 5. 39 dnl Fortunately, we can do this because on this platform MB_LEN_MAX is 5.
39 AC_REQUIRE([AC_CANONICAL_HOST]) 40 AC_REQUIRE([AC_CANONICAL_HOST])
40 AC_REQUIRE([gt_LOCALE_FR_UTF8]) 41 AC_REQUIRE([gt_LOCALE_EN_UTF8])
41 AC_CACHE_CHECK([whether MB_CUR_MAX is correct], 42 AC_CACHE_CHECK([whether MB_CUR_MAX is correct],
42 [gl_cv_macro_MB_CUR_MAX_good], 43 [gl_cv_macro_MB_CUR_MAX_good],
43 [ 44 [AC_LINK_IFELSE(
44 dnl Initial guess, used when cross-compiling or when no suitable locale 45 [AC_LANG_PROGRAM([[#include <stdlib.h>
45 dnl is present. 46 ]],
46changequote(,)dnl 47 [[return !!MB_CUR_MAX;]])
47 case "$host_os" in 48 ],
48 # Guess no on Solaris. 49 [dnl Initial guess, used when cross-compiling or when no suitable locale
49 solaris*) gl_cv_macro_MB_CUR_MAX_good="guessing no" ;; 50 dnl is present.
50 # Guess yes otherwise. 51 # Guess no on Solaris and Haiku, yes otherwise.
51 *) gl_cv_macro_MB_CUR_MAX_good="guessing yes" ;; 52 AS_CASE([$host_os],
52 esac 53 [solaris* | haiku*],
53changequote([,])dnl 54 [gl_cv_macro_MB_CUR_MAX_good="guessing no"],
54 if test $LOCALE_FR_UTF8 != none; then 55 [gl_cv_macro_MB_CUR_MAX_good="guessing yes"])
55 AC_RUN_IFELSE( 56 if test "$LOCALE_EN_UTF8" != none; then
56 [AC_LANG_SOURCE([[ 57 AC_RUN_IFELSE(
58 [AC_LANG_SOURCE([[
57#include <locale.h> 59#include <locale.h>
58#include <stdlib.h> 60#include <stdlib.h>
59int main () 61int main ()
60{ 62{
61 int result = 0; 63 int result = 0;
62 if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL) 64 if (setlocale (LC_ALL, "$LOCALE_EN_UTF8") != NULL)
63 { 65 {
64 if (MB_CUR_MAX < 4) 66 if (MB_CUR_MAX < 4)
65 result |= 1; 67 result |= 1;
66 } 68 }
67 return result; 69 return result;
68}]])], 70}]])],
69 [gl_cv_macro_MB_CUR_MAX_good=yes], 71 [gl_cv_macro_MB_CUR_MAX_good=yes],
70 [gl_cv_macro_MB_CUR_MAX_good=no], 72 [gl_cv_macro_MB_CUR_MAX_good=no],
71 [:]) 73 [:])
72 fi 74 fi
75 ],
76 [gl_cv_macro_MB_CUR_MAX_good="link failed - so no"])
73 ]) 77 ])
74 case "$gl_cv_macro_MB_CUR_MAX_good" in 78 AS_CASE([$gl_cv_macro_MB_CUR_MAX_good],
75 *yes) ;; 79 [*yes],
76 *) REPLACE_MB_CUR_MAX=1 ;; 80 [],
77 esac 81 ["link failed - so no"],
82 [# 4 suffices as a workaround in Android NDK 16,
83 # the only known platform with the bug.
84 REPLACE_MB_CUR_MAX=4],
85 [REPLACE_MB_CUR_MAX="(-1)"])
78 86
79 AC_CHECK_DECLS_ONCE([ecvt]) 87 AC_CHECK_DECLS_ONCE([ecvt])
80 if test $ac_cv_have_decl_ecvt = no; then 88 if test $ac_cv_have_decl_ecvt = no; then
@@ -110,6 +118,7 @@ AC_DEFUN([gl_STDLIB_H_REQUIRE_DEFAULTS],
110[ 118[
111 m4_defun(GL_MODULE_INDICATOR_PREFIX[_STDLIB_H_MODULE_INDICATOR_DEFAULTS], [ 119 m4_defun(GL_MODULE_INDICATOR_PREFIX[_STDLIB_H_MODULE_INDICATOR_DEFAULTS], [
112 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB__EXIT]) 120 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB__EXIT])
121 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ABORT_DEBUG])
113 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ALIGNED_ALLOC]) 122 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ALIGNED_ALLOC])
114 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ATOLL]) 123 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ATOLL])
115 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CALLOC_GNU]) 124 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CALLOC_GNU])
@@ -139,12 +148,12 @@ AC_DEFUN([gl_STDLIB_H_REQUIRE_DEFAULTS],
139 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RANDOM]) 148 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RANDOM])
140 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RANDOM_R]) 149 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RANDOM_R])
141 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REALLOCARRAY]) 150 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REALLOCARRAY])
142 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REALLOC_GNU])
143 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REALLOC_POSIX]) 151 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REALLOC_POSIX])
144 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REALPATH]) 152 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REALPATH])
145 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RPMATCH]) 153 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RPMATCH])
146 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SECURE_GETENV]) 154 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SECURE_GETENV])
147 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETENV]) 155 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETENV])
156 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STACK_TRACE])
148 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOD]) 157 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOD])
149 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOF]) 158 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOF])
150 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOL]) 159 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOL])
@@ -218,6 +227,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
218 HAVE_UNLOCKPT=1; AC_SUBST([HAVE_UNLOCKPT]) 227 HAVE_UNLOCKPT=1; AC_SUBST([HAVE_UNLOCKPT])
219 HAVE_DECL_UNSETENV=1; AC_SUBST([HAVE_DECL_UNSETENV]) 228 HAVE_DECL_UNSETENV=1; AC_SUBST([HAVE_DECL_UNSETENV])
220 REPLACE__EXIT=0; AC_SUBST([REPLACE__EXIT]) 229 REPLACE__EXIT=0; AC_SUBST([REPLACE__EXIT])
230 REPLACE_ABORT=0; AC_SUBST([REPLACE_ABORT])
221 REPLACE_ALIGNED_ALLOC=0; AC_SUBST([REPLACE_ALIGNED_ALLOC]) 231 REPLACE_ALIGNED_ALLOC=0; AC_SUBST([REPLACE_ALIGNED_ALLOC])
222 REPLACE_CALLOC_FOR_CALLOC_GNU=0; AC_SUBST([REPLACE_CALLOC_FOR_CALLOC_GNU]) 232 REPLACE_CALLOC_FOR_CALLOC_GNU=0; AC_SUBST([REPLACE_CALLOC_FOR_CALLOC_GNU])
223 REPLACE_CALLOC_FOR_CALLOC_POSIX=0; AC_SUBST([REPLACE_CALLOC_FOR_CALLOC_POSIX]) 233 REPLACE_CALLOC_FOR_CALLOC_POSIX=0; AC_SUBST([REPLACE_CALLOC_FOR_CALLOC_POSIX])
@@ -244,7 +254,6 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
244 REPLACE_RAND=0; AC_SUBST([REPLACE_RAND]) 254 REPLACE_RAND=0; AC_SUBST([REPLACE_RAND])
245 REPLACE_RANDOM=0; AC_SUBST([REPLACE_RANDOM]) 255 REPLACE_RANDOM=0; AC_SUBST([REPLACE_RANDOM])
246 REPLACE_RANDOM_R=0; AC_SUBST([REPLACE_RANDOM_R]) 256 REPLACE_RANDOM_R=0; AC_SUBST([REPLACE_RANDOM_R])
247 REPLACE_REALLOC_FOR_REALLOC_GNU=0; AC_SUBST([REPLACE_REALLOC_FOR_REALLOC_GNU])
248 REPLACE_REALLOC_FOR_REALLOC_POSIX=0; AC_SUBST([REPLACE_REALLOC_FOR_REALLOC_POSIX]) 257 REPLACE_REALLOC_FOR_REALLOC_POSIX=0; AC_SUBST([REPLACE_REALLOC_FOR_REALLOC_POSIX])
249 REPLACE_REALLOCARRAY=0; AC_SUBST([REPLACE_REALLOCARRAY]) 258 REPLACE_REALLOCARRAY=0; AC_SUBST([REPLACE_REALLOCARRAY])
250 REPLACE_REALPATH=0; AC_SUBST([REPLACE_REALPATH]) 259 REPLACE_REALPATH=0; AC_SUBST([REPLACE_REALPATH])
@@ -259,4 +268,5 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
259 REPLACE_STRTOULL=0; AC_SUBST([REPLACE_STRTOULL]) 268 REPLACE_STRTOULL=0; AC_SUBST([REPLACE_STRTOULL])
260 REPLACE_UNSETENV=0; AC_SUBST([REPLACE_UNSETENV]) 269 REPLACE_UNSETENV=0; AC_SUBST([REPLACE_UNSETENV])
261 REPLACE_WCTOMB=0; AC_SUBST([REPLACE_WCTOMB]) 270 REPLACE_WCTOMB=0; AC_SUBST([REPLACE_WCTOMB])
271 CAN_PRINT_STACK_TRACE=0; AC_SUBST([CAN_PRINT_STACK_TRACE])
262]) 272])
diff --git a/gl/m4/strcasecmp.m4 b/gl/m4/strcasecmp.m4
new file mode 100644
index 00000000..eb4345d9
--- /dev/null
+++ b/gl/m4/strcasecmp.m4
@@ -0,0 +1,67 @@
1# strcasecmp.m4
2# serial 3
3dnl Copyright (C) 2002-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9AC_DEFUN([gl_FUNC_STRCASECMP],
10[
11 AC_REQUIRE([gl_STRINGS_H_DEFAULTS])
12 AC_CHECK_FUNCS([strcasecmp])
13 if test $ac_cv_func_strcasecmp = yes; then
14 gl_STRCASECMP_WORKS
15 case "$gl_cv_func_strcasecmp_works" in
16 *yes) ;;
17 *) REPLACE_STRCASECMP=1 ;;
18 esac
19 else
20 HAVE_STRCASECMP=0
21 fi
22])
23
24AC_DEFUN([gl_STRCASECMP_WORKS],
25[
26 AC_REQUIRE([AC_CANONICAL_HOST])
27 AC_CACHE_CHECK([whether strcasecmp works],
28 [gl_cv_func_strcasecmp_works],
29 [dnl Prepare a guess, used when cross-compiling or when specific locales
30 dnl are not available.
31 case "$host_os" in
32 solaris* | cygwin*)
33 gl_cv_func_strcasecmp_works="guessing no" ;;
34 *)
35 gl_cv_func_strcasecmp_works="guessing yes" ;;
36 esac
37 AC_RUN_IFELSE(
38 [AC_LANG_SOURCE([[
39#include <stdio.h>
40#include <ctype.h>
41#include <locale.h>
42#include <strings.h>
43int main ()
44{
45 if (setlocale (LC_ALL, "fr_FR.ISO-8859-1") != NULL
46 || setlocale (LC_ALL, "fr_FR.ISO8859-1") != NULL)
47 {
48 int c1 = (unsigned char) '\311';
49 int c2 = (unsigned char) '\351';
50 if (tolower (c1) == c2 && toupper (c2) == c1)
51 return strcasecmp ("Fej\311r", "Fej\351r") != 0;
52 }
53 return 2;
54}]])],
55 [gl_cv_func_strcasecmp_works=yes],
56 [if test $? = 1; then
57 gl_cv_func_strcasecmp_works=no
58 fi
59 ],
60 [:])
61 ])
62])
63
64# Prerequisites of lib/strcasecmp.c.
65AC_DEFUN([gl_PREREQ_STRCASECMP], [
66 :
67])
diff --git a/gl/m4/strcasestr.m4 b/gl/m4/strcasestr.m4
index d2548716..eb2862f1 100644
--- a/gl/m4/strcasestr.m4
+++ b/gl/m4/strcasestr.m4
@@ -1,9 +1,10 @@
1# strcasestr.m4 1# strcasestr.m4
2# serial 28 2# serial 29
3dnl Copyright (C) 2005, 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2005, 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Check that strcasestr is present and works. 9dnl Check that strcasestr is present and works.
9AC_DEFUN([gl_FUNC_STRCASESTR_SIMPLE], 10AC_DEFUN([gl_FUNC_STRCASESTR_SIMPLE],
@@ -98,7 +99,7 @@ static void quit (int sig) { _exit (sig + 128); }
98 char *haystack = (char *) malloc (2 * m + 2); 99 char *haystack = (char *) malloc (2 * m + 2);
99 char *needle = (char *) malloc (m + 2); 100 char *needle = (char *) malloc (m + 2);
100 /* Failure to compile this test due to missing alarm is okay, 101 /* Failure to compile this test due to missing alarm is okay,
101 since all such platforms (mingw) also lack strcasestr. */ 102 since all such platforms (mingw, MSVC) also lack strcasestr. */
102 signal (SIGALRM, quit); 103 signal (SIGALRM, quit);
103 alarm (5); 104 alarm (5);
104 /* Check for quadratic performance. */ 105 /* Check for quadratic performance. */
diff --git a/gl/m4/strerror.m4 b/gl/m4/strerror.m4
index 0272c6f4..c8b3b207 100644
--- a/gl/m4/strerror.m4
+++ b/gl/m4/strerror.m4
@@ -1,9 +1,10 @@
1# strerror.m4 1# strerror.m4
2# serial 25 2# serial 25
3dnl Copyright (C) 2002, 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2002, 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_STRERROR], 9AC_DEFUN([gl_FUNC_STRERROR],
9[ 10[
diff --git a/gl/m4/string_h.m4 b/gl/m4/string_h.m4
index f31264ae..fc73603a 100644
--- a/gl/m4/string_h.m4
+++ b/gl/m4/string_h.m4
@@ -1,9 +1,10 @@
1# string_h.m4 1# string_h.m4
2# serial 39 2# serial 44.1
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Configure a GNU-like replacement for <string.h>. 9# Configure a GNU-like replacement for <string.h>.
9 10
@@ -23,8 +24,9 @@ AC_DEFUN_ONCE([gl_STRING_H],
23 ]], 24 ]],
24 [explicit_bzero ffsl ffsll memmem mempcpy memrchr memset_explicit 25 [explicit_bzero ffsl ffsll memmem mempcpy memrchr memset_explicit
25 rawmemchr stpcpy stpncpy strchrnul 26 rawmemchr stpcpy stpncpy strchrnul
26 strdup strncat strndup strnlen strpbrk strsep strcasestr strtok_r 27 strdup strncat strncpy strndup strnlen strpbrk strsep strcasestr strtok_r
27 strerror_r strerrorname_np sigabbrev_np sigdescr_np strsignal strverscmp]) 28 strerror_l strerror_r strerrorname_np
29 sigabbrev_np sigdescr_np strsignal strverscmp])
28 30
29 AC_REQUIRE([AC_C_RESTRICT]) 31 AC_REQUIRE([AC_C_RESTRICT])
30]) 32])
@@ -62,6 +64,7 @@ AC_DEFUN([gl_STRING_H_REQUIRE_DEFAULTS],
62 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRCHRNUL]) 64 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRCHRNUL])
63 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRDUP]) 65 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRDUP])
64 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRNCAT]) 66 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRNCAT])
67 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRNCPY])
65 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRNDUP]) 68 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRNDUP])
66 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRNLEN]) 69 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRNLEN])
67 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRPBRK]) 70 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRPBRK])
@@ -69,6 +72,8 @@ AC_DEFUN([gl_STRING_H_REQUIRE_DEFAULTS],
69 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRSTR]) 72 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRSTR])
70 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRCASESTR]) 73 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRCASESTR])
71 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOK_R]) 74 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOK_R])
75 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STR_STARTSWITH])
76 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STR_ENDSWITH])
72 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSLEN]) 77 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSLEN])
73 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSNLEN]) 78 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSNLEN])
74 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSCHR]) 79 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSCHR])
@@ -83,8 +88,11 @@ AC_DEFUN([gl_STRING_H_REQUIRE_DEFAULTS],
83 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSSPN]) 88 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSSPN])
84 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSSEP]) 89 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSSEP])
85 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSTOK_R]) 90 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSTOK_R])
91 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBS_STARTSWITH])
92 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBS_ENDSWITH])
86 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRERROR]) 93 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRERROR])
87 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRERROR_R]) 94 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRERROR_R])
95 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRERROR_L])
88 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRERRORNAME_NP]) 96 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRERRORNAME_NP])
89 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGABBREV_NP]) 97 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGABBREV_NP])
90 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGDESCR_NP]) 98 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGDESCR_NP])
@@ -123,6 +131,7 @@ AC_DEFUN([gl_STRING_H_DEFAULTS],
123 HAVE_STRCASESTR=1; AC_SUBST([HAVE_STRCASESTR]) 131 HAVE_STRCASESTR=1; AC_SUBST([HAVE_STRCASESTR])
124 HAVE_DECL_STRTOK_R=1; AC_SUBST([HAVE_DECL_STRTOK_R]) 132 HAVE_DECL_STRTOK_R=1; AC_SUBST([HAVE_DECL_STRTOK_R])
125 HAVE_DECL_STRERROR_R=1; AC_SUBST([HAVE_DECL_STRERROR_R]) 133 HAVE_DECL_STRERROR_R=1; AC_SUBST([HAVE_DECL_STRERROR_R])
134 HAVE_STRERROR_L=1; AC_SUBST([HAVE_STRERROR_L])
126 HAVE_STRERRORNAME_NP=1; AC_SUBST([HAVE_STRERRORNAME_NP]) 135 HAVE_STRERRORNAME_NP=1; AC_SUBST([HAVE_STRERRORNAME_NP])
127 HAVE_SIGABBREV_NP=1; AC_SUBST([HAVE_SIGABBREV_NP]) 136 HAVE_SIGABBREV_NP=1; AC_SUBST([HAVE_SIGABBREV_NP])
128 HAVE_SIGDESCR_NP=1; AC_SUBST([HAVE_SIGDESCR_NP]) 137 HAVE_SIGDESCR_NP=1; AC_SUBST([HAVE_SIGDESCR_NP])
@@ -138,6 +147,7 @@ AC_DEFUN([gl_STRING_H_DEFAULTS],
138 REPLACE_STRCHRNUL=0; AC_SUBST([REPLACE_STRCHRNUL]) 147 REPLACE_STRCHRNUL=0; AC_SUBST([REPLACE_STRCHRNUL])
139 REPLACE_STRDUP=0; AC_SUBST([REPLACE_STRDUP]) 148 REPLACE_STRDUP=0; AC_SUBST([REPLACE_STRDUP])
140 REPLACE_STRNCAT=0; AC_SUBST([REPLACE_STRNCAT]) 149 REPLACE_STRNCAT=0; AC_SUBST([REPLACE_STRNCAT])
150 REPLACE_STRNCPY=0; AC_SUBST([REPLACE_STRNCPY])
141 REPLACE_STRNDUP=0; AC_SUBST([REPLACE_STRNDUP]) 151 REPLACE_STRNDUP=0; AC_SUBST([REPLACE_STRNDUP])
142 REPLACE_STRNLEN=0; AC_SUBST([REPLACE_STRNLEN]) 152 REPLACE_STRNLEN=0; AC_SUBST([REPLACE_STRNLEN])
143 REPLACE_STRSTR=0; AC_SUBST([REPLACE_STRSTR]) 153 REPLACE_STRSTR=0; AC_SUBST([REPLACE_STRSTR])
@@ -145,6 +155,7 @@ AC_DEFUN([gl_STRING_H_DEFAULTS],
145 REPLACE_STRTOK_R=0; AC_SUBST([REPLACE_STRTOK_R]) 155 REPLACE_STRTOK_R=0; AC_SUBST([REPLACE_STRTOK_R])
146 REPLACE_STRERROR=0; AC_SUBST([REPLACE_STRERROR]) 156 REPLACE_STRERROR=0; AC_SUBST([REPLACE_STRERROR])
147 REPLACE_STRERROR_R=0; AC_SUBST([REPLACE_STRERROR_R]) 157 REPLACE_STRERROR_R=0; AC_SUBST([REPLACE_STRERROR_R])
158 REPLACE_STRERROR_L=0; AC_SUBST([REPLACE_STRERROR_L])
148 REPLACE_STRERRORNAME_NP=0; AC_SUBST([REPLACE_STRERRORNAME_NP]) 159 REPLACE_STRERRORNAME_NP=0; AC_SUBST([REPLACE_STRERRORNAME_NP])
149 REPLACE_STRSIGNAL=0; AC_SUBST([REPLACE_STRSIGNAL]) 160 REPLACE_STRSIGNAL=0; AC_SUBST([REPLACE_STRSIGNAL])
150 REPLACE_STRVERSCMP=0; AC_SUBST([REPLACE_STRVERSCMP]) 161 REPLACE_STRVERSCMP=0; AC_SUBST([REPLACE_STRVERSCMP])
diff --git a/gl/m4/strings_h.m4 b/gl/m4/strings_h.m4
index aaafb559..18f30d4a 100644
--- a/gl/m4/strings_h.m4
+++ b/gl/m4/strings_h.m4
@@ -1,9 +1,10 @@
1# strings_h.m4 1# strings_h.m4
2# serial 9 2# serial 14
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Configure a replacement for <strings.h>. 9# Configure a replacement for <strings.h>.
9 10
@@ -28,7 +29,7 @@ AC_DEFUN_ONCE([gl_STRINGS_H],
28 <strings.h>. */ 29 <strings.h>. */
29 #include <sys/types.h> 30 #include <sys/types.h>
30 #include <strings.h> 31 #include <strings.h>
31 ]], [ffs strcasecmp strncasecmp]) 32 ]], [ffs strcasecmp strcasecmp_l strncasecmp strncasecmp_l])
32]) 33])
33 34
34# gl_STRINGS_MODULE_INDICATOR([modulename]) 35# gl_STRINGS_MODULE_INDICATOR([modulename])
@@ -49,6 +50,10 @@ AC_DEFUN([gl_STRINGS_H_REQUIRE_DEFAULTS],
49[ 50[
50 m4_defun(GL_MODULE_INDICATOR_PREFIX[_STRINGS_H_MODULE_INDICATOR_DEFAULTS], [ 51 m4_defun(GL_MODULE_INDICATOR_PREFIX[_STRINGS_H_MODULE_INDICATOR_DEFAULTS], [
51 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FFS]) 52 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FFS])
53 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRCASECMP])
54 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRCASECMP_L])
55 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRNCASECMP])
56 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRNCASECMP_L])
52 ]) 57 ])
53 m4_require(GL_MODULE_INDICATOR_PREFIX[_STRINGS_H_MODULE_INDICATOR_DEFAULTS]) 58 m4_require(GL_MODULE_INDICATOR_PREFIX[_STRINGS_H_MODULE_INDICATOR_DEFAULTS])
54 AC_REQUIRE([gl_STRINGS_H_DEFAULTS]) 59 AC_REQUIRE([gl_STRINGS_H_DEFAULTS])
@@ -59,5 +64,12 @@ AC_DEFUN([gl_STRINGS_H_DEFAULTS],
59 dnl Assume proper GNU behavior unless another module says otherwise. 64 dnl Assume proper GNU behavior unless another module says otherwise.
60 HAVE_FFS=1; AC_SUBST([HAVE_FFS]) 65 HAVE_FFS=1; AC_SUBST([HAVE_FFS])
61 HAVE_STRCASECMP=1; AC_SUBST([HAVE_STRCASECMP]) 66 HAVE_STRCASECMP=1; AC_SUBST([HAVE_STRCASECMP])
67 HAVE_STRCASECMP_L=1; AC_SUBST([HAVE_STRCASECMP_L])
68 HAVE_STRNCASECMP=1; AC_SUBST([HAVE_STRNCASECMP])
69 HAVE_STRNCASECMP_L=1; AC_SUBST([HAVE_STRNCASECMP_L])
62 HAVE_DECL_STRNCASECMP=1; AC_SUBST([HAVE_DECL_STRNCASECMP]) 70 HAVE_DECL_STRNCASECMP=1; AC_SUBST([HAVE_DECL_STRNCASECMP])
71 REPLACE_STRCASECMP=0; AC_SUBST([REPLACE_STRCASECMP])
72 REPLACE_STRCASECMP_L=0; AC_SUBST([REPLACE_STRCASECMP_L])
73 REPLACE_STRNCASECMP=0; AC_SUBST([REPLACE_STRNCASECMP])
74 REPLACE_STRNCASECMP_L=0; AC_SUBST([REPLACE_STRNCASECMP_L])
63]) 75])
diff --git a/gl/m4/strcase.m4 b/gl/m4/strncasecmp.m4
index 63021733..c7c8b240 100644
--- a/gl/m4/strcase.m4
+++ b/gl/m4/strncasecmp.m4
@@ -1,31 +1,22 @@
1# strcase.m4 1# strncasecmp.m4
2# serial 12 2# serial 2
3dnl Copyright (C) 2002, 2005-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2002-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7 7dnl This file is offered as-is, without any warranty.
8AC_DEFUN([gl_STRCASE],
9[
10 gl_FUNC_STRCASECMP
11 gl_FUNC_STRNCASECMP
12])
13
14AC_DEFUN([gl_FUNC_STRCASECMP],
15[
16 AC_REQUIRE([gl_STRINGS_H_DEFAULTS])
17 AC_CHECK_FUNCS([strcasecmp])
18 if test $ac_cv_func_strcasecmp = no; then
19 HAVE_STRCASECMP=0
20 fi
21])
22 8
23AC_DEFUN([gl_FUNC_STRNCASECMP], 9AC_DEFUN([gl_FUNC_STRNCASECMP],
24[ 10[
25 AC_REQUIRE([gl_STRINGS_H_DEFAULTS]) 11 AC_REQUIRE([gl_STRINGS_H_DEFAULTS])
26 AC_CHECK_FUNCS([strncasecmp]) 12 AC_CHECK_FUNCS([strncasecmp])
27 if test $ac_cv_func_strncasecmp = yes; then 13 if test $ac_cv_func_strncasecmp = yes; then
28 HAVE_STRNCASECMP=1 14 dnl Assume that strncasecmp and strcasecmp share the same bugs.
15 gl_STRCASECMP_WORKS
16 case "$gl_cv_func_strcasecmp_works" in
17 *yes) ;;
18 *) REPLACE_STRNCASECMP=1 ;;
19 esac
29 else 20 else
30 HAVE_STRNCASECMP=0 21 HAVE_STRNCASECMP=0
31 fi 22 fi
@@ -35,11 +26,6 @@ AC_DEFUN([gl_FUNC_STRNCASECMP],
35 fi 26 fi
36]) 27])
37 28
38# Prerequisites of lib/strcasecmp.c.
39AC_DEFUN([gl_PREREQ_STRCASECMP], [
40 :
41])
42
43# Prerequisites of lib/strncasecmp.c. 29# Prerequisites of lib/strncasecmp.c.
44AC_DEFUN([gl_PREREQ_STRNCASECMP], [ 30AC_DEFUN([gl_PREREQ_STRNCASECMP], [
45 : 31 :
diff --git a/gl/m4/strncpy.m4 b/gl/m4/strncpy.m4
new file mode 100644
index 00000000..57876171
--- /dev/null
+++ b/gl/m4/strncpy.m4
@@ -0,0 +1,94 @@
1# strncpy.m4
2# serial 1
3dnl Copyright (C) 2002-2004, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9AC_DEFUN_ONCE([gl_FUNC_STRNCPY],
10[
11 AC_REQUIRE([gl_STRING_H_DEFAULTS])
12 AC_REQUIRE([AC_PROG_CC])
13 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
14
15 dnl Check for prerequisites for memory fence checks.
16 gl_FUNC_MMAP_ANON
17 AC_CHECK_HEADERS_ONCE([sys/mman.h])
18 AC_CHECK_FUNCS_ONCE([mprotect])
19
20 dnl Detect bug in FreeBSD 15.0 on x86_64:
21 dnl strncpy should not dereference more than n bytes, but always dereferences
22 dnl n+1 bytes if the first n bytes don't contain a NUL byte.
23 dnl Assume that strncpy works on platforms that lack mprotect.
24 AC_CACHE_CHECK([whether strncpy works], [gl_cv_func_strncpy_works],
25 [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
26#include <string.h>
27#if HAVE_SYS_MMAN_H
28# include <fcntl.h>
29# include <unistd.h>
30# include <sys/types.h>
31# include <sys/mman.h>
32#endif
33]GL_MDA_DEFINES],
34[[
35 char *fence = NULL;
36#if HAVE_SYS_MMAN_H && HAVE_MPROTECT
37 {
38 long int pagesize = sysconf (_SC_PAGESIZE);
39 char *two_pages =
40 (char *) mmap (NULL, 2 * pagesize, PROT_READ | PROT_WRITE,
41 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
42 if (two_pages != (char *)(-1)
43 && mprotect (two_pages + pagesize, pagesize, PROT_NONE) == 0)
44 fence = two_pages + pagesize;
45 }
46#endif
47 if (fence)
48 {
49 char dest[8];
50
51 dest[0] = 'a';
52 dest[1] = 'b';
53 dest[2] = 'c';
54 dest[3] = 'd';
55 dest[4] = 'e';
56 dest[5] = 'f';
57 dest[6] = 'g';
58
59 *(fence - 3) = '7';
60 *(fence - 2) = '2';
61 *(fence - 1) = '9';
62
63 if (strncpy (dest + 1, fence - 3, 3) != dest + 1)
64 return 1;
65 if (dest[0] != 'a')
66 return 2;
67 if (dest[1] != '7' || dest[2] != '2' || dest[3] != '9')
68 return 3;
69 if (dest[4] != 'e')
70 return 4;
71 }
72 return 0;
73]])], [gl_cv_func_strncpy_works=yes], [gl_cv_func_strncpy_works=no],
74 [
75 case "$host_os" in
76 # Guess no on FreeBSD.
77 freebsd* | dragonfly*) gl_cv_func_strncpy_works="guessing no" ;;
78 # Guess yes on native Windows.
79 mingw* | windows*) gl_cv_func_strncpy_works="guessing yes" ;;
80 # Guess yes otherwise.
81 *) gl_cv_func_strncpy_works="guessing yes" ;;
82 esac
83 ])
84 ])
85 case "$gl_cv_func_strncpy_works" in
86 *yes) ;;
87 *) REPLACE_STRNCPY=1 ;;
88 esac
89])
90
91# Prerequisites of lib/strncpy.c.
92AC_DEFUN([gl_PREREQ_STRNCPY], [
93 :
94])
diff --git a/gl/m4/strsep.m4 b/gl/m4/strsep.m4
index cfde87a5..b018ff88 100644
--- a/gl/m4/strsep.m4
+++ b/gl/m4/strsep.m4
@@ -1,9 +1,10 @@
1# strsep.m4 1# strsep.m4
2# serial 11 2# serial 11
3dnl Copyright (C) 2002-2004, 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2002-2004, 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_STRSEP], 9AC_DEFUN([gl_FUNC_STRSEP],
9[ 10[
diff --git a/gl/m4/strstr.m4 b/gl/m4/strstr.m4
index 957ed2e3..1b5ef6c1 100644
--- a/gl/m4/strstr.m4
+++ b/gl/m4/strstr.m4
@@ -1,9 +1,10 @@
1# strstr.m4 1# strstr.m4
2# serial 24 2# serial 25
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Check that strstr works. 9dnl Check that strstr works.
9AC_DEFUN([gl_FUNC_STRSTR_SIMPLE], 10AC_DEFUN([gl_FUNC_STRSTR_SIMPLE],
@@ -95,7 +96,7 @@ static void quit (int sig) { _exit (sig + 128); }
95 char *haystack = (char *) malloc (2 * m + 2); 96 char *haystack = (char *) malloc (2 * m + 2);
96 char *needle = (char *) malloc (m + 2); 97 char *needle = (char *) malloc (m + 2);
97 /* Failure to compile this test due to missing alarm is okay, 98 /* Failure to compile this test due to missing alarm is okay,
98 since all such platforms (mingw) also have quadratic strstr. */ 99 since all such platforms (mingw, MSVC) also have quadratic strstr. */
99 signal (SIGALRM, quit); 100 signal (SIGALRM, quit);
100 alarm (5); 101 alarm (5);
101 /* Check for quadratic performance. */ 102 /* Check for quadratic performance. */
diff --git a/gl/m4/sys_cdefs_h.m4 b/gl/m4/sys_cdefs_h.m4
new file mode 100644
index 00000000..d72796ca
--- /dev/null
+++ b/gl/m4/sys_cdefs_h.m4
@@ -0,0 +1,26 @@
1# sys_cdefs_h.m4 - Is <sys/cdefs.h> compatible enough with glibc?
2# serial 2
3dnl Copyright 2024-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9dnl Written by Paul Eggert.
10
11AC_DEFUN_ONCE([gl_CHECK_HEADER_SYS_CDEFS_H],
12 [AC_CACHE_CHECK([for glibc-compatible sys/cdefs.h],
13 [gl_cv_header_sys_cdefs_h],
14 [AC_COMPILE_IFELSE(
15 [AC_LANG_DEFINES_PROVIDED
16 [#include <sys/cdefs.h>
17 enum { foo = __GNUC_PREREQ (14, 1) } bar;
18 ]],
19 [gl_cv_header_sys_cdefs_h=yes],
20 [gl_cv_header_sys_cdefs_h=no])])
21 if test "$gl_cv_header_sys_cdefs_h" = yes; then
22 HAVE_SYS_CDEFS_H=1
23 else
24 HAVE_SYS_CDEFS_H=0
25 fi
26 AC_SUBST([HAVE_SYS_CDEFS_H])])
diff --git a/gl/m4/sys_socket_h.m4 b/gl/m4/sys_socket_h.m4
index 3bf3cb47..fb69209b 100644
--- a/gl/m4/sys_socket_h.m4
+++ b/gl/m4/sys_socket_h.m4
@@ -1,9 +1,10 @@
1# sys_socket_h.m4 1# sys_socket_h.m4
2# serial 29 2# serial 31
3dnl Copyright (C) 2005-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2005-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Simon Josefsson. 9dnl From Simon Josefsson.
9 10
@@ -52,24 +53,10 @@ AC_DEFUN_ONCE([gl_SYS_SOCKET_H],
52 fi 53 fi
53 # We need to check for ws2tcpip.h now. 54 # We need to check for ws2tcpip.h now.
54 gl_PREREQ_SYS_H_SOCKET 55 gl_PREREQ_SYS_H_SOCKET
55 AC_CHECK_TYPES([struct sockaddr_storage, sa_family_t],,,[ 56 gl_PREREQ_SYS_SA_FAMILY
56 /* sys/types.h is not needed according to POSIX, but the
57 sys/socket.h in i386-unknown-freebsd4.10 and
58 powerpc-apple-darwin5.5 required it. */
59#include <sys/types.h>
60#ifdef HAVE_SYS_SOCKET_H
61#include <sys/socket.h>
62#endif
63#ifdef HAVE_WS2TCPIP_H
64#include <ws2tcpip.h>
65#endif
66])
67 if test $ac_cv_type_struct_sockaddr_storage = no; then 57 if test $ac_cv_type_struct_sockaddr_storage = no; then
68 HAVE_STRUCT_SOCKADDR_STORAGE=0 58 HAVE_STRUCT_SOCKADDR_STORAGE=0
69 fi 59 fi
70 if test $ac_cv_type_sa_family_t = no; then
71 HAVE_SA_FAMILY_T=0
72 fi
73 if test $ac_cv_type_struct_sockaddr_storage != no; then 60 if test $ac_cv_type_struct_sockaddr_storage != no; then
74 AC_CHECK_MEMBERS([struct sockaddr_storage.ss_family], 61 AC_CHECK_MEMBERS([struct sockaddr_storage.ss_family],
75 [], 62 [],
@@ -158,6 +145,32 @@ AC_DEFUN([gl_PREREQ_SYS_H_WS2TCPIP],
158 AC_SUBST([HAVE_WS2TCPIP_H]) 145 AC_SUBST([HAVE_WS2TCPIP_H])
159]) 146])
160 147
148# Common prerequisites of the <sys/socket.h> replacement and of the <sys/un.h>
149# replacement.
150# Sets and substitutes HAVE_SA_FAMILY_T.
151AC_DEFUN([gl_PREREQ_SYS_SA_FAMILY],
152[
153 AC_REQUIRE([gl_CHECK_SOCKET_HEADERS])
154 AC_CHECK_TYPES([struct sockaddr_storage, sa_family_t],,,[
155 /* sys/types.h is not needed according to POSIX, but the
156 sys/socket.h in i386-unknown-freebsd4.10 and
157 powerpc-apple-darwin5.5 required it. */
158#include <sys/types.h>
159#ifdef HAVE_SYS_SOCKET_H
160#include <sys/socket.h>
161#endif
162#ifdef HAVE_WS2TCPIP_H
163#include <ws2tcpip.h>
164#endif
165])
166 if test $ac_cv_type_sa_family_t = yes; then
167 HAVE_SA_FAMILY_T=1
168 else
169 HAVE_SA_FAMILY_T=0
170 fi
171 AC_SUBST([HAVE_SA_FAMILY_T])
172])
173
161# gl_SYS_SOCKET_MODULE_INDICATOR([modulename]) 174# gl_SYS_SOCKET_MODULE_INDICATOR([modulename])
162# sets the shell variable that indicates the presence of the given module 175# sets the shell variable that indicates the presence of the given module
163# to a C preprocessor expression that will evaluate to 1. 176# to a C preprocessor expression that will evaluate to 1.
@@ -202,6 +215,5 @@ AC_DEFUN([gl_SYS_SOCKET_H_DEFAULTS],
202 HAVE_STRUCT_SOCKADDR_STORAGE=1; AC_SUBST([HAVE_STRUCT_SOCKADDR_STORAGE]) 215 HAVE_STRUCT_SOCKADDR_STORAGE=1; AC_SUBST([HAVE_STRUCT_SOCKADDR_STORAGE])
203 HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY=1; 216 HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY=1;
204 AC_SUBST([HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY]) 217 AC_SUBST([HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY])
205 HAVE_SA_FAMILY_T=1; AC_SUBST([HAVE_SA_FAMILY_T])
206 HAVE_ACCEPT4=1; AC_SUBST([HAVE_ACCEPT4]) 218 HAVE_ACCEPT4=1; AC_SUBST([HAVE_ACCEPT4])
207]) 219])
diff --git a/gl/m4/sys_stat_h.m4 b/gl/m4/sys_stat_h.m4
index 3cc50ce6..fdcc8954 100644
--- a/gl/m4/sys_stat_h.m4
+++ b/gl/m4/sys_stat_h.m4
@@ -1,9 +1,10 @@
1# sys_stat_h.m4 1# sys_stat_h.m4
2# serial 42 -*- Autoconf -*- 2# serial 42 -*- Autoconf -*-
3dnl Copyright (C) 2006-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2006-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Eric Blake. 9dnl From Eric Blake.
9dnl Provide a GNU-like <sys/stat.h>. 10dnl Provide a GNU-like <sys/stat.h>.
diff --git a/gl/m4/sys_types_h.m4 b/gl/m4/sys_types_h.m4
index 00d2437b..e99fdcc6 100644
--- a/gl/m4/sys_types_h.m4
+++ b/gl/m4/sys_types_h.m4
@@ -1,9 +1,10 @@
1# sys_types_h.m4 1# sys_types_h.m4
2# serial 13 2# serial 15
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2011-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN_ONCE([gl_SYS_TYPES_H], 9AC_DEFUN_ONCE([gl_SYS_TYPES_H],
9[ 10[
@@ -23,6 +24,9 @@ AC_DEFUN_ONCE([gl_SYS_TYPES_H],
23 dnl Whether to override the 'off_t' type. 24 dnl Whether to override the 'off_t' type.
24 AC_REQUIRE([gl_TYPE_OFF_T]) 25 AC_REQUIRE([gl_TYPE_OFF_T])
25 26
27 dnl Whether to define the 'off64_t' type.
28 AC_REQUIRE([gl_TYPE_OFF64_T])
29
26 dnl Whether to override the 'dev_t' and 'ino_t' types. 30 dnl Whether to override the 'dev_t' and 'ino_t' types.
27 m4_ifdef([gl_WINDOWS_STAT_INODES], [ 31 m4_ifdef([gl_WINDOWS_STAT_INODES], [
28 AC_REQUIRE([gl_WINDOWS_STAT_INODES]) 32 AC_REQUIRE([gl_WINDOWS_STAT_INODES])
@@ -30,6 +34,14 @@ AC_DEFUN_ONCE([gl_SYS_TYPES_H],
30 WINDOWS_STAT_INODES=0 34 WINDOWS_STAT_INODES=0
31 ]) 35 ])
32 AC_SUBST([WINDOWS_STAT_INODES]) 36 AC_SUBST([WINDOWS_STAT_INODES])
37
38 dnl Test whether the 'blksize_t' type is defined.
39 AC_CHECK_TYPE([blksize_t], [HAVE_BLKSIZE_T=1], [HAVE_BLKSIZE_T=0])
40 AC_SUBST([HAVE_BLKSIZE_T])
41
42 dnl Test whether the 'blkcnt_t' type is defined.
43 AC_CHECK_TYPE([blkcnt_t], [HAVE_BLKCNT_T=1], [HAVE_BLKCNT_T=0])
44 AC_SUBST([HAVE_BLKCNT_T])
33]) 45])
34 46
35# Initializes the default values for AC_SUBSTed shell variables. 47# Initializes the default values for AC_SUBSTed shell variables.
diff --git a/gl/m4/sys_uio_h.m4 b/gl/m4/sys_uio_h.m4
index a471c720..eb0e8424 100644
--- a/gl/m4/sys_uio_h.m4
+++ b/gl/m4/sys_uio_h.m4
@@ -1,9 +1,10 @@
1# sys_uio_h.m4 1# sys_uio_h.m4
2# serial 3 2# serial 3
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2011-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN_ONCE([gl_SYS_UIO_H], 9AC_DEFUN_ONCE([gl_SYS_UIO_H],
9[ 10[
diff --git a/gl/m4/threadlib.m4 b/gl/m4/threadlib.m4
index f5e81479..333c8fe0 100644
--- a/gl/m4/threadlib.m4
+++ b/gl/m4/threadlib.m4
@@ -1,9 +1,10 @@
1# threadlib.m4 1# threadlib.m4
2# serial 42 2# serial 45.1
3dnl Copyright (C) 2005-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2005-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Bruno Haible. 9dnl From Bruno Haible.
9 10
@@ -56,24 +57,22 @@ AC_DEFUN([gl_ANYTHREADLIB_EARLY],
56[ 57[
57 AC_REQUIRE([AC_CANONICAL_HOST]) 58 AC_REQUIRE([AC_CANONICAL_HOST])
58 if test -z "$gl_anythreadlib_early_done"; then 59 if test -z "$gl_anythreadlib_early_done"; then
59 case "$host_os" in 60 AS_CASE([$host_os],
60 osf*) 61 [osf*],
61 # On OSF/1, the compiler needs the flag -D_REENTRANT so that it 62 [# On OSF/1, the compiler needs the flag -D_REENTRANT so that it
62 # groks <pthread.h>. cc also understands the flag -pthread, but 63 # groks <pthread.h>. cc also understands the flag -pthread, but
63 # we don't use it because 1. gcc-2.95 doesn't understand -pthread, 64 # we do not use it because 1. gcc-2.95 does not understand -pthread,
64 # 2. putting a flag into CPPFLAGS that has an effect on the linker 65 # 2. putting a flag into CPPFLAGS that has an effect on the linker
65 # causes the AC_LINK_IFELSE test below to succeed unexpectedly, 66 # causes the AC_LINK_IFELSE test below to succeed unexpectedly,
66 # leading to wrong values of LIBTHREAD and LTLIBTHREAD. 67 # leading to wrong values of LIBTHREAD and LTLIBTHREAD.
67 CPPFLAGS="$CPPFLAGS -D_REENTRANT" 68 CPPFLAGS="$CPPFLAGS -D_REENTRANT"
68 ;; 69 ])
69 esac
70 # Some systems optimize for single-threaded programs by default, and 70 # Some systems optimize for single-threaded programs by default, and
71 # need special flags to disable these optimizations. For example, the 71 # need special flags to disable these optimizations. For example, the
72 # definition of 'errno' in <errno.h>. 72 # definition of errno in <errno.h>.
73 case "$host_os" in 73 AS_CASE([$host_os],
74 aix* | freebsd*) CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" ;; 74 [aix* | freebsd*], [CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE"],
75 solaris*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" ;; 75 [hpux* | solaris*], [CPPFLAGS="$CPPFLAGS -D_REENTRANT"])
76 esac
77 gl_anythreadlib_early_done=done 76 gl_anythreadlib_early_done=done
78 fi 77 fi
79]) 78])
@@ -85,24 +84,26 @@ AC_DEFUN([gl_WEAK_SYMBOLS],
85 AC_REQUIRE([AC_CANONICAL_HOST]) 84 AC_REQUIRE([AC_CANONICAL_HOST])
86 AC_CACHE_CHECK([whether imported symbols can be declared weak], 85 AC_CACHE_CHECK([whether imported symbols can be declared weak],
87 [gl_cv_have_weak], 86 [gl_cv_have_weak],
88 [case "$host_os" in 87 [AS_CASE([$host_os],
89 cygwin* | mingw* | windows*) 88 [cygwin* | mingw* | windows*],
89 [
90 dnl On Cygwin 3.2.0 with gcc 10.2, and likewise on mingw 10.0.0 with 90 dnl On Cygwin 3.2.0 with gcc 10.2, and likewise on mingw 10.0.0 with
91 dnl gcc 11.3, the test below would succeed, but programs that use 91 dnl gcc 11.3, the test below would succeed, but programs that use
92 dnl pthread_in_use() with weak symbol references crash miserably at 92 dnl pthread_in_use() with weak symbol references crash miserably at
93 dnl runtime. 93 dnl runtime.
94 gl_cv_have_weak="guessing no" 94 gl_cv_have_weak="guessing no"
95 ;; 95 ],
96 *) 96 [
97 gl_cv_have_weak=no 97 gl_cv_have_weak=no
98 dnl First, test whether the compiler accepts it syntactically. 98 dnl First, test whether the compiler accepts it syntactically.
99 AC_LINK_IFELSE( 99 AC_LINK_IFELSE(
100 [AC_LANG_PROGRAM( 100 [AC_LANG_PROGRAM(
101 [[extern void xyzzy (); 101 [[extern void xyzzy ();
102#pragma weak xyzzy]], 102#pragma weak xyzzy
103 ]],
103 [[xyzzy();]])], 104 [[xyzzy();]])],
104 [gl_cv_have_weak=maybe]) 105 [gl_cv_have_weak=maybe])
105 if test $gl_cv_have_weak = maybe; then 106 AS_IF([test $gl_cv_have_weak = maybe], [
106 dnl Second, test whether it actually works. On Cygwin 1.7.2, with 107 dnl Second, test whether it actually works. On Cygwin 1.7.2, with
107 dnl gcc 4.3, symbols declared weak always evaluate to the address 0. 108 dnl gcc 4.3, symbols declared weak always evaluate to the address 0.
108 AC_RUN_IFELSE( 109 AC_RUN_IFELSE(
@@ -125,20 +126,19 @@ int main ()
125 [gl_cv_have_weak="guessing yes"], 126 [gl_cv_have_weak="guessing yes"],
126 [gl_cv_have_weak="guessing no"]) 127 [gl_cv_have_weak="guessing no"])
127 ]) 128 ])
128 fi 129 ])
129 ;; 130 ])
130 esac 131 dnl But when linking statically, weak symbols do not work.
131 dnl But when linking statically, weak symbols don't work. 132 AS_CASE([" $LDFLAGS "],
132 case " $LDFLAGS " in 133 [*" -static "*], [gl_cv_have_weak=no])
133 *" -static "*) gl_cv_have_weak=no ;;
134 esac
135 dnl Test for a bug in FreeBSD 11: A link error occurs when using a weak 134 dnl Test for a bug in FreeBSD 11: A link error occurs when using a weak
136 dnl symbol and linking against a shared library that has a dependency on 135 dnl symbol and linking against a shared library that has a dependency on
137 dnl the shared library that defines the symbol. 136 dnl the shared library that defines the symbol.
138 case "$gl_cv_have_weak" in 137 AS_CASE([$gl_cv_have_weak],
139 *yes) 138 [*yes],
140 case "$host_os" in 139 [AS_CASE([$host_os],
141 freebsd* | dragonfly* | midnightbsd*) 140 [freebsd* | dragonfly* | midnightbsd*],
141 [
142 : > conftest1.c 142 : > conftest1.c
143 $CC $CPPFLAGS $CFLAGS $LDFLAGS -fPIC -shared -o libempty.so conftest1.c -lpthread >&AS_MESSAGE_LOG_FD 2>&1 143 $CC $CPPFLAGS $CFLAGS $LDFLAGS -fPIC -shared -o libempty.so conftest1.c -lpthread >&AS_MESSAGE_LOG_FD 2>&1
144 cat <<EOF > conftest2.c 144 cat <<EOF > conftest2.c
@@ -152,17 +152,15 @@ EOF
152 $CC $CPPFLAGS $CFLAGS $LDFLAGS -o conftest conftest2.c libempty.so >&AS_MESSAGE_LOG_FD 2>&1 \ 152 $CC $CPPFLAGS $CFLAGS $LDFLAGS -o conftest conftest2.c libempty.so >&AS_MESSAGE_LOG_FD 2>&1 \
153 || gl_cv_have_weak=no 153 || gl_cv_have_weak=no
154 rm -f conftest1.c libempty.so conftest2.c conftest 154 rm -f conftest1.c libempty.so conftest2.c conftest
155 ;; 155 ])
156 esac 156 ])
157 ;;
158 esac
159 ]) 157 ])
160 case "$gl_cv_have_weak" in 158 AS_CASE([$gl_cv_have_weak],
161 *yes) 159 [*yes],
160 [
162 AC_DEFINE([HAVE_WEAK_SYMBOLS], [1], 161 AC_DEFINE([HAVE_WEAK_SYMBOLS], [1],
163 [Define to 1 if the compiler and linker support weak declarations of symbols.]) 162 [Define to 1 if the compiler and linker support weak declarations of symbols.])
164 ;; 163 ])
165 esac
166]) 164])
167 165
168dnl ============================================================================ 166dnl ============================================================================
@@ -188,15 +186,15 @@ dnl The guts of gl_PTHREADLIB. Needs to be expanded only once.
188AC_DEFUN([gl_PTHREADLIB_BODY], 186AC_DEFUN([gl_PTHREADLIB_BODY],
189[ 187[
190 AC_REQUIRE([gl_ANYTHREADLIB_EARLY]) 188 AC_REQUIRE([gl_ANYTHREADLIB_EARLY])
191 if test -z "$gl_pthreadlib_body_done"; then 189 AS_IF([test -z "$gl_pthreadlib_body_done"], [
192 gl_pthread_api=no 190 gl_pthread_api=no
193 LIBPTHREAD= 191 LIBPTHREAD=
194 LIBPMULTITHREAD= 192 LIBPMULTITHREAD=
195 # On OSF/1, the compiler needs the flag -pthread or -D_REENTRANT so that 193 # On OSF/1, the compiler needs the flag -pthread or -D_REENTRANT so that
196 # it groks <pthread.h>. It's added above, in gl_ANYTHREADLIB_EARLY. 194 # it groks <pthread.h>. It is added above, in gl_ANYTHREADLIB_EARLY.
197 AC_CHECK_HEADER([pthread.h], 195 AC_CHECK_HEADER([pthread.h],
198 [gl_have_pthread_h=yes], [gl_have_pthread_h=no]) 196 [gl_have_pthread_h=yes], [gl_have_pthread_h=no])
199 if test "$gl_have_pthread_h" = yes; then 197 AS_IF([test "$gl_have_pthread_h" = yes], [
200 # Other possible tests: 198 # Other possible tests:
201 # -lpthreads (FSU threads, PCthreads) 199 # -lpthreads (FSU threads, PCthreads)
202 # -lgthreads 200 # -lgthreads
@@ -208,7 +206,7 @@ AC_DEFUN([gl_PTHREADLIB_BODY],
208 # needs -pthread for some reason. See: 206 # needs -pthread for some reason. See:
209 # https://lists.gnu.org/r/bug-gnulib/2014-09/msg00023.html 207 # https://lists.gnu.org/r/bug-gnulib/2014-09/msg00023.html
210 saved_LIBS="$LIBS" 208 saved_LIBS="$LIBS"
211 for gl_pthread in '' '-pthread'; do 209 for gl_pthread in "" "-pthread"; do
212 LIBS="$LIBS $gl_pthread" 210 LIBS="$LIBS $gl_pthread"
213 AC_LINK_IFELSE( 211 AC_LINK_IFELSE(
214 [AC_LANG_PROGRAM( 212 [AC_LANG_PROGRAM(
@@ -230,8 +228,9 @@ AC_DEFUN([gl_PTHREADLIB_BODY],
230 gl_pthread_in_glibc=no 228 gl_pthread_in_glibc=no
231 # On Linux with glibc >= 2.34, libc contains the fully functional 229 # On Linux with glibc >= 2.34, libc contains the fully functional
232 # pthread functions. 230 # pthread functions.
233 case "$host_os" in 231 AS_CASE([$host_os],
234 linux*) 232 [linux*],
233 [
235 AC_EGREP_CPP([Lucky user], 234 AC_EGREP_CPP([Lucky user],
236 [#include <features.h> 235 [#include <features.h>
237 #ifdef __GNU_LIBRARY__ 236 #ifdef __GNU_LIBRARY__
@@ -242,19 +241,18 @@ AC_DEFUN([gl_PTHREADLIB_BODY],
242 ], 241 ],
243 [gl_pthread_in_glibc=yes], 242 [gl_pthread_in_glibc=yes],
244 []) 243 [])
245 ;; 244 ])
246 esac
247 echo "$as_me:__oline__: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&AS_MESSAGE_LOG_FD 245 echo "$as_me:__oline__: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&AS_MESSAGE_LOG_FD
248 246
249 # Test for libpthread by looking for pthread_kill. (Not pthread_self, 247 # Test for libpthread by looking for pthread_kill. (Not pthread_self,
250 # since it is defined as a macro on OSF/1.) 248 # since it is defined as a macro on OSF/1.)
251 if test $gl_pthread_api = yes && test -z "$LIBPTHREAD"; then 249 AS_IF([test $gl_pthread_api = yes && test -z "$LIBPTHREAD"], [
252 # The program links fine without libpthread. But it may actually 250 # The program links fine without libpthread. But it may actually
253 # need to link with libpthread in order to create multiple threads. 251 # need to link with libpthread in order to create multiple threads.
254 AC_CHECK_LIB([pthread], [pthread_kill], 252 AC_CHECK_LIB([pthread], [pthread_kill],
255 [if test $gl_pthread_in_glibc = yes; then 253 [AS_IF([test $gl_pthread_in_glibc = yes], [
256 LIBPMULTITHREAD= 254 LIBPMULTITHREAD=
257 else 255 ], [
258 LIBPMULTITHREAD=-lpthread 256 LIBPMULTITHREAD=-lpthread
259 # On Solaris and HP-UX, most pthread functions exist also in libc. 257 # On Solaris and HP-UX, most pthread functions exist also in libc.
260 # Therefore pthread_in_use() needs to actually try to create a 258 # Therefore pthread_in_use() needs to actually try to create a
@@ -262,14 +260,13 @@ AC_DEFUN([gl_PTHREADLIB_BODY],
262 # pthread_create will actually create a thread. 260 # pthread_create will actually create a thread.
263 # On Solaris 10 or newer, this test is no longer needed, because 261 # On Solaris 10 or newer, this test is no longer needed, because
264 # libc contains the fully functional pthread functions. 262 # libc contains the fully functional pthread functions.
265 case "$host_os" in 263 AS_CASE([$host_os],
266changequote(,)dnl 264 [[solaris | solaris2.[1-9] | solaris2.[1-9].* | hpux*]],
267 solaris | solaris2.[1-9] | solaris2.[1-9].* | hpux*) 265 [
268changequote([,])dnl 266 AC_DEFINE([PTHREAD_IN_USE_DETECTION_HARD], [1],
269 AC_DEFINE([PTHREAD_IN_USE_DETECTION_HARD], [1], 267 [Define if the pthread_in_use() detection is hard.])
270 [Define if the pthread_in_use() detection is hard.]) 268 ])
271 esac 269 ])
272 fi
273 ], 270 ],
274 [dnl This is needed on FreeBSD 5.2.1. 271 [dnl This is needed on FreeBSD 5.2.1.
275 AC_CHECK_LIB([thr], [pthread_kill], 272 AC_CHECK_LIB([thr], [pthread_kill],
@@ -280,35 +277,36 @@ changequote([,])dnl
280 fi 277 fi
281 ]) 278 ])
282 ]) 279 ])
283 elif test $gl_pthread_api != yes; then 280 ], [test $gl_pthread_api != yes], [
284 # Some library is needed. Try libpthread and libc_r. 281 # Some library is needed. Try libpthread and libc_r.
285 AC_CHECK_LIB([pthread], [pthread_kill], 282 AC_CHECK_LIB([pthread], [pthread_kill],
286 [gl_pthread_api=yes 283 [gl_pthread_api=yes
287 LIBPTHREAD=-lpthread 284 LIBPTHREAD=-lpthread
288 LIBPMULTITHREAD=-lpthread]) 285 LIBPMULTITHREAD=-lpthread])
289 if test $gl_pthread_api != yes; then 286 AS_IF([test $gl_pthread_api != yes], [
290 # For FreeBSD 4. 287 # For FreeBSD 4.
291 AC_CHECK_LIB([c_r], [pthread_kill], 288 AC_CHECK_LIB([c_r], [pthread_kill],
292 [gl_pthread_api=yes 289 [gl_pthread_api=yes
293 LIBPTHREAD=-lc_r 290 LIBPTHREAD=-lc_r
294 LIBPMULTITHREAD=-lc_r]) 291 LIBPMULTITHREAD=-lc_r])
295 fi 292 ])
296 fi 293 ])
297 echo "$as_me:__oline__: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&AS_MESSAGE_LOG_FD 294 echo "$as_me:__oline__: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&AS_MESSAGE_LOG_FD
298 fi 295 ])
299 AC_MSG_CHECKING([whether POSIX threads API is available]) 296 AC_MSG_CHECKING([whether POSIX threads API is available])
300 AC_MSG_RESULT([$gl_pthread_api]) 297 AC_MSG_RESULT([$gl_pthread_api])
301 AC_SUBST([LIBPTHREAD]) 298 AC_SUBST([LIBPTHREAD])
302 AC_SUBST([LIBPMULTITHREAD]) 299 AC_SUBST([LIBPMULTITHREAD])
303 if test $gl_pthread_api = yes; then 300 AS_IF([test $gl_pthread_api = yes], [
304 AC_DEFINE([HAVE_PTHREAD_API], [1], 301 AC_DEFINE([HAVE_PTHREAD_API], [1],
305 [Define if you have the <pthread.h> header and the POSIX threads API.]) 302 [Define if you have the <pthread.h> header and the POSIX threads API.])
306 fi 303 ])
307 304
308 dnl On some systems, sched_yield is in librt, rather than in libpthread. 305 dnl On some systems, sched_yield is in librt, rather than in libpthread.
309 AC_LINK_IFELSE( 306 AC_LINK_IFELSE(
310 [AC_LANG_PROGRAM( 307 [AC_LANG_PROGRAM(
311 [[#include <sched.h>]], 308 [[#include <sched.h>
309 ]],
312 [[sched_yield ();]])], 310 [[sched_yield ();]])],
313 [SCHED_YIELD_LIB= 311 [SCHED_YIELD_LIB=
314 ], 312 ],
@@ -323,7 +321,7 @@ changequote([,])dnl
323 AC_SUBST([LIB_SCHED_YIELD]) 321 AC_SUBST([LIB_SCHED_YIELD])
324 322
325 gl_pthreadlib_body_done=done 323 gl_pthreadlib_body_done=done
326 fi 324 ])
327]) 325])
328 326
329AC_DEFUN([gl_PTHREADLIB], 327AC_DEFUN([gl_PTHREADLIB],
@@ -350,44 +348,45 @@ AC_DEFUN([gl_STDTHREADLIB_BODY],
350[ 348[
351 AC_REQUIRE([gl_ANYTHREADLIB_EARLY]) 349 AC_REQUIRE([gl_ANYTHREADLIB_EARLY])
352 AC_REQUIRE([AC_CANONICAL_HOST]) 350 AC_REQUIRE([AC_CANONICAL_HOST])
353 if test -z "$gl_stdthreadlib_body_done"; then 351 AS_IF([test -z "$gl_stdthreadlib_body_done"], [
354 AC_CHECK_HEADERS_ONCE([threads.h]) 352 AC_CHECK_HEADERS_ONCE([threads.h])
355 353
356 case "$host_os" in 354 AS_CASE([$host_os],
357 mingw* | windows*) 355 [mingw* | windows*],
356 [
358 LIBSTDTHREAD= 357 LIBSTDTHREAD=
359 ;; 358 ],
360 *) 359 [
361 gl_PTHREADLIB_BODY 360 gl_PTHREADLIB_BODY
362 if test $ac_cv_header_threads_h = yes; then 361 AS_IF([test $ac_cv_header_threads_h = yes], [
363 dnl glibc >= 2.29 has thrd_create in libpthread. 362 dnl glibc >= 2.29 has thrd_create in libpthread.
364 dnl FreeBSD >= 10 has thrd_create in libstdthreads; this library depends 363 dnl FreeBSD >= 10 has thrd_create in libstdthreads; this library depends
365 dnl on libpthread (for the symbol 'pthread_mutexattr_gettype'). 364 dnl on libpthread (for the symbol pthread_mutexattr_gettype).
366 dnl glibc >= 2.34, AIX >= 7.1, and Solaris >= 11.4 have thrd_create in 365 dnl glibc >= 2.34, AIX >= 7.1, and Solaris >= 11.4 have thrd_create in
367 dnl libc. 366 dnl libc.
368 gl_CHECK_FUNCS_ANDROID([thrd_create], [[#include <threads.h>]]) 367 gl_CHECK_FUNCS_ANDROID([thrd_create], [[#include <threads.h>
369 if test $ac_cv_func_thrd_create = yes; then 368 ]])
369 AS_IF([test $ac_cv_func_thrd_create = yes], [
370 LIBSTDTHREAD= 370 LIBSTDTHREAD=
371 else 371 ], [
372 AC_CHECK_LIB([stdthreads], [thrd_create], [ 372 AC_CHECK_LIB([stdthreads], [thrd_create], [
373 LIBSTDTHREAD='-lstdthreads -lpthread' 373 LIBSTDTHREAD="-lstdthreads -lpthread"
374 ], [ 374 ], [
375 dnl Guess that thrd_create is in libpthread. 375 dnl Guess that thrd_create is in libpthread.
376 LIBSTDTHREAD="$LIBPMULTITHREAD" 376 LIBSTDTHREAD="$LIBPMULTITHREAD"
377 ]) 377 ])
378 fi 378 ])
379 else 379 ], [
380 dnl Libraries needed by thrd.c, mtx.c, cnd.c, tss.c. 380 dnl Libraries needed by thrd.c, mtx.c, cnd.c, tss.c.
381 LIBSTDTHREAD="$LIBPMULTITHREAD $SCHED_YIELD_LIB" 381 LIBSTDTHREAD="$LIBPMULTITHREAD $SCHED_YIELD_LIB"
382 fi 382 ])
383 ;; 383 ])
384 esac
385 AC_SUBST([LIBSTDTHREAD]) 384 AC_SUBST([LIBSTDTHREAD])
386 385
387 AC_MSG_CHECKING([whether ISO C threads API is available]) 386 AC_MSG_CHECKING([whether ISO C threads API is available])
388 AC_MSG_RESULT([$ac_cv_header_threads_h]) 387 AC_MSG_RESULT([$ac_cv_header_threads_h])
389 gl_stdthreadlib_body_done=done 388 gl_stdthreadlib_body_done=done
390 fi 389 ])
391]) 390])
392 391
393AC_DEFUN([gl_STDTHREADLIB], 392AC_DEFUN([gl_STDTHREADLIB],
@@ -404,7 +403,7 @@ dnl ------------
404dnl Tests for a multithreading library to be used. 403dnl Tests for a multithreading library to be used.
405dnl If the configure.ac contains a definition of the gl_THREADLIB_DEFAULT_NO 404dnl If the configure.ac contains a definition of the gl_THREADLIB_DEFAULT_NO
406dnl (it must be placed before the invocation of gl_THREADLIB_EARLY!), then the 405dnl (it must be placed before the invocation of gl_THREADLIB_EARLY!), then the
407dnl default is 'no', otherwise it is system dependent. In both cases, the user 406dnl default is "no", otherwise it is system dependent. In both cases, the user
408dnl can change the choice through the options --enable-threads=choice or 407dnl can change the choice through the options --enable-threads=choice or
409dnl --disable-threads. 408dnl --disable-threads.
410dnl Defines at most one of the macros USE_ISOC_THREADS, USE_POSIX_THREADS, 409dnl Defines at most one of the macros USE_ISOC_THREADS, USE_POSIX_THREADS,
@@ -449,7 +448,7 @@ AC_DEFUN([gl_THREADLIB_EARLY_BODY],
449 m4_ifdef([gl_THREADLIB_DEFAULT_NO], 448 m4_ifdef([gl_THREADLIB_DEFAULT_NO],
450 [m4_divert_text([DEFAULTS], [gl_use_threads_default=no])], 449 [m4_divert_text([DEFAULTS], [gl_use_threads_default=no])],
451 [m4_divert_text([DEFAULTS], [gl_use_threads_default=])]) 450 [m4_divert_text([DEFAULTS], [gl_use_threads_default=])])
452 dnl gl_use_winpthreads_default defaults to 'no', because in mingw 10, like 451 dnl gl_use_winpthreads_default defaults to "no", because in mingw 10, like
453 dnl in mingw 5, the use of libwinpthread still makes test-pthread-tss crash. 452 dnl in mingw 5, the use of libwinpthread still makes test-pthread-tss crash.
454 m4_divert_text([DEFAULTS], [gl_use_winpthreads_default=no]) 453 m4_divert_text([DEFAULTS], [gl_use_winpthreads_default=no])
455 AC_ARG_ENABLE([threads], 454 AC_ARG_ENABLE([threads],
@@ -459,41 +458,35 @@ AS_HELP_STRING([[--disable-threads]], [build without multithread safety])]),
459 [if test -n "$gl_use_threads_default"; then 458 [if test -n "$gl_use_threads_default"; then
460 gl_use_threads="$gl_use_threads_default" 459 gl_use_threads="$gl_use_threads_default"
461 else 460 else
462changequote(,)dnl 461 AS_CASE([$host_os],
463 case "$host_os" in
464 dnl Disable multithreading by default on OSF/1, because it interferes 462 dnl Disable multithreading by default on OSF/1, because it interferes
465 dnl with fork()/exec(): When msgexec is linked with -lpthread, its 463 dnl with fork()/exec(): When msgexec is linked with -lpthread, its
466 dnl child process gets an endless segmentation fault inside execvp(). 464 dnl child process gets an endless segmentation fault inside execvp().
467 osf*) gl_use_threads=no ;; 465 [osf*], [gl_use_threads=no],
468 dnl Disable multithreading by default on Cygwin 1.5.x, because it has 466 dnl Disable multithreading by default on Cygwin 1.5.x, because it has
469 dnl bugs that lead to endless loops or crashes. See 467 dnl bugs that lead to endless loops or crashes. See
470 dnl <https://cygwin.com/ml/cygwin/2009-08/msg00283.html>. 468 dnl <https://cygwin.com/ml/cygwin/2009-08/msg00283.html>.
471 cygwin*) 469 [cygwin*],
472 case `uname -r` in 470 [AS_CASE([$(uname -r)],
473 1.[0-5].*) gl_use_threads=no ;; 471 [[1.[0-5].*]], [gl_use_threads=no],
474 *) gl_use_threads=yes ;; 472 [gl_use_threads=yes])
475 esac 473 ],
476 ;;
477 dnl Obey gl_AVOID_WINPTHREAD on mingw. 474 dnl Obey gl_AVOID_WINPTHREAD on mingw.
478 mingw* | windows*) 475 [mingw* | windows*],
479 case "$gl_use_winpthreads_default" in 476 [AS_CASE([$gl_use_winpthreads_default],
480 yes) gl_use_threads=posix ;; 477 [yes], [gl_use_threads=posix],
481 no) gl_use_threads=windows ;; 478 [no], [gl_use_threads=windows],
482 *) gl_use_threads=yes ;; 479 [gl_use_threads=yes])
483 esac 480 ],
484 ;; 481 [gl_use_threads=yes])
485 *) gl_use_threads=yes ;;
486 esac
487changequote([,])dnl
488 fi 482 fi
489 ]) 483 ])
490 if test "$gl_use_threads" = yes \ 484 AS_CASE([$gl_use_threads],
491 || test "$gl_use_threads" = isoc \ 485 [yes | isoc | posix | isoc+posix],
492 || test "$gl_use_threads" = posix \ 486 [
493 || test "$gl_use_threads" = isoc+posix; then 487 # For using <threads.h> or <pthread.h>:
494 # For using <threads.h> or <pthread.h>: 488 gl_ANYTHREADLIB_EARLY
495 gl_ANYTHREADLIB_EARLY 489 ])
496 fi
497]) 490])
498 491
499dnl The guts of gl_THREADLIB. Needs to be expanded only once. 492dnl The guts of gl_THREADLIB. Needs to be expanded only once.
@@ -506,90 +499,95 @@ AC_DEFUN([gl_THREADLIB_BODY],
506 LTLIBTHREAD= 499 LTLIBTHREAD=
507 LIBMULTITHREAD= 500 LIBMULTITHREAD=
508 LTLIBMULTITHREAD= 501 LTLIBMULTITHREAD=
509 if test "$gl_use_threads" != no; then 502 AS_IF([test "$gl_use_threads" = no],
503 [AC_DEFINE([AVOID_ANY_THREADS], [1],
504 [Define if no multithread safety and no multithreading is desired.])],
505 [
510 dnl Check whether the compiler and linker support weak declarations. 506 dnl Check whether the compiler and linker support weak declarations.
511 gl_WEAK_SYMBOLS 507 gl_WEAK_SYMBOLS
512 if case "$gl_cv_have_weak" in *yes) true;; *) false;; esac; then 508 AS_CASE([$gl_cv_have_weak],
513 dnl If we use weak symbols to implement pthread_in_use / pth_in_use / 509 [*yes],
514 dnl thread_in_use, we also need to test whether the ISO C 11 thrd_create 510 [
515 dnl facility is in use. 511 dnl If we use weak symbols to implement pthread_in_use / pth_in_use /
516 AC_CHECK_HEADERS_ONCE([threads.h]) 512 dnl thread_in_use, we also need to test whether the ISO C 11 thrd_create
517 : 513 dnl facility is in use.
518 fi 514 AC_CHECK_HEADERS_ONCE([threads.h])
519 if test "$gl_use_threads" = isoc || test "$gl_use_threads" = isoc+posix; then 515 :
520 AC_CHECK_HEADERS_ONCE([threads.h]) 516 ])
521 gl_have_isoc_threads="$ac_cv_header_threads_h" 517 AS_CASE([$gl_use_threads],
522 fi 518 [isoc | isoc+posix],
523 if test "$gl_use_threads" = yes \ 519 [
524 || test "$gl_use_threads" = posix \ 520 AC_CHECK_HEADERS_ONCE([threads.h])
525 || test "$gl_use_threads" = isoc+posix; then 521 gl_have_isoc_threads="$ac_cv_header_threads_h"
526 gl_PTHREADLIB_BODY 522 ])
527 LIBTHREAD=$LIBPTHREAD LTLIBTHREAD=$LIBPTHREAD 523 AS_CASE([$gl_use_threads],
528 LIBMULTITHREAD=$LIBPMULTITHREAD LTLIBMULTITHREAD=$LIBPMULTITHREAD 524 [yes | posix | isoc+posix],
529 if test $gl_pthread_api = yes; then 525 [
530 if test "$gl_use_threads" = isoc+posix && test "$gl_have_isoc_threads" = yes; then 526 gl_PTHREADLIB_BODY
531 gl_threads_api='isoc+posix' 527 LIBTHREAD=$LIBPTHREAD LTLIBTHREAD=$LIBPTHREAD
532 AC_DEFINE([USE_ISOC_AND_POSIX_THREADS], [1], 528 LIBMULTITHREAD=$LIBPMULTITHREAD LTLIBMULTITHREAD=$LIBPMULTITHREAD
533 [Define if the combination of the ISO C and POSIX multithreading APIs can be used.]) 529 AS_IF([test $gl_pthread_api = yes], [
534 LIBTHREAD= LTLIBTHREAD= 530 AS_IF([test "$gl_use_threads" = isoc+posix &&
535 else 531 test "$gl_have_isoc_threads" = yes], [
536 gl_threads_api=posix 532 gl_threads_api="isoc+posix"
537 AC_DEFINE([USE_POSIX_THREADS], [1], 533 AC_DEFINE([USE_ISOC_AND_POSIX_THREADS], [1],
538 [Define if the POSIX multithreading library can be used.]) 534 [Define if the combination of the ISO C and POSIX multithreading APIs can be used.])
539 if test -z "$LIBMULTITHREAD" && test -z "$LTLIBMULTITHREAD"; then 535 LIBTHREAD= LTLIBTHREAD=
540 AC_DEFINE([USE_POSIX_THREADS_FROM_LIBC], [1], 536 ], [
541 [Define if references to the POSIX multithreading library are satisfied by libc.]) 537 gl_threads_api=posix
542 else 538 AC_DEFINE([USE_POSIX_THREADS], [1],
543 if case "$gl_cv_have_weak" in *yes) true;; *) false;; esac; then 539 [Define if the POSIX multithreading library can be used.])
544 AC_DEFINE([USE_POSIX_THREADS_WEAK], [1], 540 AS_IF([test -z "$LIBMULTITHREAD" && test -z "$LTLIBMULTITHREAD"], [
545 [Define if references to the POSIX multithreading library should be made weak.]) 541 AC_DEFINE([USE_POSIX_THREADS_FROM_LIBC], [1],
546 LIBTHREAD= LTLIBTHREAD= 542 [Define if references to the POSIX multithreading library are satisfied by libc.])
547 else 543 ], [
548 case "$host_os" in 544 AS_CASE([$gl_cv_have_weak],
549 freebsd* | dragonfly* | midnightbsd*) 545 [*yes],
550 if test "x$LIBTHREAD" != "x$LIBMULTITHREAD"; then 546 [
551 dnl If weak symbols can't tell whether pthread_create(), pthread_key_create() 547 AC_DEFINE([USE_POSIX_THREADS_WEAK], [1],
552 dnl etc. will succeed, we need a runtime test. 548 [Define if references to the POSIX multithreading library should be made weak.])
553 AC_DEFINE([PTHREAD_IN_USE_DETECTION_HARD], [1], 549 LIBTHREAD= LTLIBTHREAD=
554 [Define if the pthread_in_use() detection is hard.]) 550 ],
555 fi 551 [AS_CASE([$host_os],
556 ;; 552 [freebsd* | dragonfly* | midnightbsd*],
557 esac 553 [
558 fi 554 AS_IF([test "x$LIBTHREAD" != "x$LIBMULTITHREAD"], [
559 fi 555 dnl If weak symbols cannot tell whether
560 fi 556 dnl pthread_create(), dnl pthread_key_create()
561 fi 557 dnl etc. will succeed, we need a runtime test.
562 fi 558 AC_DEFINE([PTHREAD_IN_USE_DETECTION_HARD], [1],
563 if test $gl_threads_api = none; then 559 [Define if the pthread_in_use() detection is hard.])
564 if test "$gl_use_threads" = isoc && test "$gl_have_isoc_threads" = yes; then 560 ])
561 ])
562 ])
563 ])
564 ])
565 ])
566 ])
567 AS_IF([test $gl_threads_api = none], [
568 AS_IF([test "$gl_use_threads" = isoc && test "$gl_have_isoc_threads" = yes], [
565 gl_STDTHREADLIB_BODY 569 gl_STDTHREADLIB_BODY
566 LIBTHREAD=$LIBSTDTHREAD LTLIBTHREAD=$LIBSTDTHREAD 570 LIBTHREAD=$LIBSTDTHREAD LTLIBTHREAD=$LIBSTDTHREAD
567 LIBMULTITHREAD=$LIBSTDTHREAD LTLIBMULTITHREAD=$LIBSTDTHREAD 571 LIBMULTITHREAD=$LIBSTDTHREAD LTLIBMULTITHREAD=$LIBSTDTHREAD
568 gl_threads_api=isoc 572 gl_threads_api=isoc
569 AC_DEFINE([USE_ISOC_THREADS], [1], 573 AC_DEFINE([USE_ISOC_THREADS], [1],
570 [Define if the ISO C multithreading library can be used.]) 574 [Define if the ISO C multithreading library can be used.])
571 fi 575 ])
572 fi 576 ])
573 if test $gl_threads_api = none; then 577 AS_IF([test $gl_threads_api = none], [
574 case "$gl_use_threads" in 578 # The "win32" is for backward compatibility.
575 yes | windows | win32) # The 'win32' is for backward compatibility. 579 AS_CASE([$gl_use_threads],
576 if { case "$host_os" in 580 [yes | windows | win32],
577 mingw* | windows*) true;; 581 [AS_CASE([$host_os],
578 *) false;; 582 [mingw* | windows*],
579 esac 583 [
580 }; then 584 gl_threads_api=windows
581 gl_threads_api=windows 585 AC_DEFINE([USE_WINDOWS_THREADS], [1],
582 AC_DEFINE([USE_WINDOWS_THREADS], [1], 586 [Define if the native Windows multithreading API can be used.])
583 [Define if the native Windows multithreading API can be used.]) 587 ])
584 fi 588 ])
585 ;; 589 ])
586 esac 590 ])
587 fi
588 else
589 dnl "$gl_use_threads" is "no".
590 AC_DEFINE([AVOID_ANY_THREADS], [1],
591 [Define if no multithread safety and no multithreading is desired.])
592 fi
593 AC_MSG_CHECKING([for multithread API to use]) 591 AC_MSG_CHECKING([for multithread API to use])
594 AC_MSG_RESULT([$gl_threads_api]) 592 AC_MSG_RESULT([$gl_threads_api])
595 AC_SUBST([LIBTHREAD]) 593 AC_SUBST([LIBTHREAD])
@@ -609,7 +607,7 @@ dnl gl_DISABLE_THREADS
609dnl ------------------ 607dnl ------------------
610dnl Sets the gl_THREADLIB default so that threads are not used by default. 608dnl Sets the gl_THREADLIB default so that threads are not used by default.
611dnl The user can still override it at installation time, by using the 609dnl The user can still override it at installation time, by using the
612dnl configure option '--enable-threads'. 610dnl configure option "--enable-threads".
613 611
614AC_DEFUN([gl_DISABLE_THREADS], [ 612AC_DEFUN([gl_DISABLE_THREADS], [
615 m4_divert_text([INIT_PREPARE], [gl_use_threads_default=no]) 613 m4_divert_text([INIT_PREPARE], [gl_use_threads_default=no])
@@ -621,7 +619,7 @@ dnl -------------------
621dnl Sets the gl_THREADLIB default so that on mingw, a dependency to the 619dnl Sets the gl_THREADLIB default so that on mingw, a dependency to the
622dnl libwinpthread DLL (mingw-w64 winpthreads library) is avoided. 620dnl libwinpthread DLL (mingw-w64 winpthreads library) is avoided.
623dnl The user can still override it at installation time, by using the 621dnl The user can still override it at installation time, by using the
624dnl configure option '--enable-threads=posix'. 622dnl configure option "--enable-threads=posix".
625dnl As of 2023, this is now the default. 623dnl As of 2023, this is now the default.
626 624
627AC_DEFUN([gl_AVOID_WINPTHREAD], [ 625AC_DEFUN([gl_AVOID_WINPTHREAD], [
diff --git a/gl/m4/time_h.m4 b/gl/m4/time_h.m4
index d2f3c970..f4d8e20f 100644
--- a/gl/m4/time_h.m4
+++ b/gl/m4/time_h.m4
@@ -1,9 +1,11 @@
1# time_h.m4 1# time_h.m4
2# serial 25 2# serial 27
3dnl Copyright (C) 2000-2001, 2003-2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2000-2001, 2003-2007, 2009-2025 Free Software Foundation,
4dnl Inc.
4dnl This file is free software; the Free Software Foundation 5dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 6dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 7dnl with or without modifications, as long as this notice is preserved.
8dnl This file is offered as-is, without any warranty.
7 9
8# Configure a more-standard replacement for <time.h>. 10# Configure a more-standard replacement for <time.h>.
9 11
@@ -145,6 +147,7 @@ AC_DEFUN([gl_TIME_H_REQUIRE_DEFAULTS],
145 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIMESPEC_GETRES]) 147 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIMESPEC_GETRES])
146 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIME_R]) 148 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIME_R])
147 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIME_RZ]) 149 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIME_RZ])
150 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TZNAME])
148 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TZSET]) 151 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TZSET])
149 dnl Support Microsoft deprecated alias function names by default. 152 dnl Support Microsoft deprecated alias function names by default.
150 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_TZSET], [1]) 153 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_TZSET], [1])
@@ -162,13 +165,16 @@ AC_DEFUN([gl_TIME_H_DEFAULTS],
162 HAVE_TIMEGM=1; AC_SUBST([HAVE_TIMEGM]) 165 HAVE_TIMEGM=1; AC_SUBST([HAVE_TIMEGM])
163 HAVE_TIMESPEC_GET=1; AC_SUBST([HAVE_TIMESPEC_GET]) 166 HAVE_TIMESPEC_GET=1; AC_SUBST([HAVE_TIMESPEC_GET])
164 HAVE_TIMESPEC_GETRES=1; AC_SUBST([HAVE_TIMESPEC_GETRES]) 167 HAVE_TIMESPEC_GETRES=1; AC_SUBST([HAVE_TIMESPEC_GETRES])
165 dnl Even GNU libc does not have timezone_t yet. 168 dnl Even GNU libc does not have timezone_t and tzalloc() yet.
166 HAVE_TIMEZONE_T=0; AC_SUBST([HAVE_TIMEZONE_T]) 169 HAVE_TIMEZONE_T=0; AC_SUBST([HAVE_TIMEZONE_T])
170 HAVE_TZALLOC=0; AC_SUBST([HAVE_TZALLOC])
167 REPLACE_CTIME=0; AC_SUBST([REPLACE_CTIME]) 171 REPLACE_CTIME=0; AC_SUBST([REPLACE_CTIME])
168 REPLACE_GMTIME=0; AC_SUBST([REPLACE_GMTIME]) 172 REPLACE_GMTIME=0; AC_SUBST([REPLACE_GMTIME])
169 REPLACE_LOCALTIME=0; AC_SUBST([REPLACE_LOCALTIME]) 173 REPLACE_LOCALTIME=0; AC_SUBST([REPLACE_LOCALTIME])
170 REPLACE_LOCALTIME_R=0; AC_SUBST([REPLACE_LOCALTIME_R]) 174 REPLACE_LOCALTIME_R=0; AC_SUBST([REPLACE_LOCALTIME_R])
175 REPLACE_LOCALTIME_RZ=0; AC_SUBST([REPLACE_LOCALTIME_RZ])
171 REPLACE_MKTIME=0; AC_SUBST([REPLACE_MKTIME]) 176 REPLACE_MKTIME=0; AC_SUBST([REPLACE_MKTIME])
177 REPLACE_MKTIME_Z=0; AC_SUBST([REPLACE_MKTIME_Z])
172 REPLACE_NANOSLEEP=0; AC_SUBST([REPLACE_NANOSLEEP]) 178 REPLACE_NANOSLEEP=0; AC_SUBST([REPLACE_NANOSLEEP])
173 REPLACE_STRFTIME=0; AC_SUBST([REPLACE_STRFTIME]) 179 REPLACE_STRFTIME=0; AC_SUBST([REPLACE_STRFTIME])
174 REPLACE_TIME=0; AC_SUBST([REPLACE_TIME]) 180 REPLACE_TIME=0; AC_SUBST([REPLACE_TIME])
diff --git a/gl/m4/time_r.m4 b/gl/m4/time_r.m4
index 3675390e..96f5c5b5 100644
--- a/gl/m4/time_r.m4
+++ b/gl/m4/time_r.m4
@@ -1,9 +1,10 @@
1# time_r.m4 1# time_r.m4
2# serial 1 2# serial 1
3dnl Copyright (C) 2003, 2006-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2003, 2006-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Reentrant time functions: localtime_r, gmtime_r. 9dnl Reentrant time functions: localtime_r, gmtime_r.
9 10
diff --git a/gl/m4/timegm.m4 b/gl/m4/timegm.m4
index c1ff2677..cb6da6da 100644
--- a/gl/m4/timegm.m4
+++ b/gl/m4/timegm.m4
@@ -1,9 +1,10 @@
1# timegm.m4 1# timegm.m4
2# serial 16 2# serial 16
3dnl Copyright (C) 2003, 2007, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2003, 2007, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_TIMEGM], 9AC_DEFUN([gl_FUNC_TIMEGM],
9[ 10[
diff --git a/gl/m4/uchar_h.m4 b/gl/m4/uchar_h.m4
new file mode 100644
index 00000000..b2309385
--- /dev/null
+++ b/gl/m4/uchar_h.m4
@@ -0,0 +1,279 @@
1# uchar_h.m4
2# serial 32
3dnl Copyright (C) 2019-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9dnl From Bruno Haible.
10dnl Prepare the overridden <uchar.h>.
11
12AC_DEFUN_ONCE([gl_UCHAR_H],
13[
14 AC_REQUIRE([gl_UCHAR_H_DEFAULTS])
15
16 gl_CHECK_NEXT_HEADERS([uchar.h])
17 if test $ac_cv_header_uchar_h = yes; then
18 HAVE_UCHAR_H=1
19 else
20 HAVE_UCHAR_H=0
21 fi
22 AC_SUBST([HAVE_UCHAR_H])
23
24 dnl On macOS 15, in C mode, <uchar.h> does not exist. But in C++ mode,
25 dnl it exists, and we need to #include_next it, otherwise we get an error
26 dnl "<cuchar> tried including <uchar.h> but didn't find libc++'s <uchar.h>
27 dnl header."
28 m4_ifdef([gl_ANSI_CXX], [AC_REQUIRE([gl_ANSI_CXX])])
29 CXX_HAVE_UCHAR_H=0
30 if test "$CXX" != no; then
31 AC_CACHE_CHECK([whether the C++ compiler has <uchar.h>],
32 [gl_cv_cxx_have_uchar_h],
33 [dnl We can't use AC_LANG_PUSH([C++]) and AC_LANG_POP([C++]) here, due to
34 dnl an autoconf bug <https://savannah.gnu.org/support/?110294>.
35 cat > conftest.cpp <<\EOF
36#include <uchar.h>
37EOF
38 gl_command="$CXX $CXXFLAGS $CPPFLAGS -c conftest.cpp"
39 if AC_TRY_EVAL([gl_command]); then
40 gl_cv_cxx_have_uchar_h=yes
41 else
42 gl_cv_cxx_have_uchar_h=no
43 fi
44 rm -fr conftest*
45 ])
46 if test $gl_cv_cxx_have_uchar_h = yes; then
47 CXX_HAVE_UCHAR_H=1
48 fi
49 fi
50 AC_SUBST([CXX_HAVE_UCHAR_H])
51
52 gl_TYPE_CHAR8_T
53 gl_TYPE_CHAR16_T
54 gl_TYPE_CHAR32_T
55
56 dnl In C++ mode, clang defines 'char16_t' and 'char32_t' as built-in types
57 dnl on some platforms (e.g. OpenBSD 6.7), and as types defined by many
58 dnl header files (<limits.h>, <stddef.h>, <stdint.h>, <stdio.h>, <stdlib.h>
59 dnl and others) on some platforms (e.g. Mac OS X 10.13).
60 dnl The same thing may also happen for 'char8_t'; so, be prepared for it.
61 m4_ifdef([gl_ANSI_CXX], [AC_REQUIRE([gl_ANSI_CXX])])
62 CXX_HAS_UCHAR_TYPES=0
63 if test $HAVE_UCHAR_H = 0; then
64 if test "$CXX" != no; then
65 AC_CACHE_CHECK([whether the C++ compiler predefines the <uchar.h> types],
66 [gl_cv_cxx_has_uchar_types],
67 [dnl We can't use AC_LANG_PUSH([C++]) and AC_LANG_POP([C++]) here, due to
68 dnl an autoconf bug <https://savannah.gnu.org/support/?110294>.
69 cat > conftest.cpp <<\EOF
70#include <stddef.h>
71char16_t a;
72char32_t b;
73EOF
74 gl_command="$CXX $CXXFLAGS $CPPFLAGS -c conftest.cpp"
75 if AC_TRY_EVAL([gl_command]); then
76 gl_cv_cxx_has_uchar_types=yes
77 else
78 gl_cv_cxx_has_uchar_types=no
79 fi
80 rm -fr conftest*
81 ])
82 if test $gl_cv_cxx_has_uchar_types = yes; then
83 CXX_HAS_UCHAR_TYPES=1
84 fi
85 fi
86 fi
87 AC_SUBST([CXX_HAS_UCHAR_TYPES])
88 CXX_HAS_CHAR8_TYPE=0
89 if test $HAVE_UCHAR_H = 0; then
90 if test "$CXX" != no; then
91 AC_CACHE_CHECK([whether the C++ compiler predefines the char8_t type],
92 [gl_cv_cxx_has_char8_type],
93 [dnl We can't use AC_LANG_PUSH([C++]) and AC_LANG_POP([C++]) here, due to
94 dnl an autoconf bug <https://savannah.gnu.org/support/?110294>.
95 cat > conftest.cpp <<\EOF
96#include <stddef.h>
97char8_t a;
98EOF
99 gl_command="$CXX $CXXFLAGS $CPPFLAGS -c conftest.cpp"
100 if AC_TRY_EVAL([gl_command]); then
101 gl_cv_cxx_has_char8_type=yes
102 else
103 gl_cv_cxx_has_char8_type=no
104 fi
105 rm -fr conftest*
106 ])
107 if test $gl_cv_cxx_has_char8_type = yes; then
108 CXX_HAS_CHAR8_TYPE=1
109 fi
110 fi
111 fi
112 AC_SUBST([CXX_HAS_CHAR8_TYPE])
113
114 dnl Test whether a 'char32_t' can hold more characters than a 'wchar_t'.
115 gl_STDINT_BITSIZEOF([wchar_t], [gl_STDINT_INCLUDES])
116 if test $BITSIZEOF_WCHAR_T -lt 32; then
117 SMALL_WCHAR_T=1
118 else
119 SMALL_WCHAR_T=0
120 fi
121 dnl SMALL_WCHAR_T is expected to be 1 on 32-bit AIX, Cygwin, native Windows.
122 AC_SUBST([SMALL_WCHAR_T])
123
124 dnl Check for declarations of anything we want to poison if the
125 dnl corresponding gnulib module is not in use, and which is not
126 dnl guaranteed by C11.
127 gl_WARN_ON_USE_PREPARE([[
128 #ifdef __HAIKU__
129 #include <stdint.h>
130 #endif
131 #include <uchar.h>
132 ]], [c32rtomb mbrtoc16 mbrtoc32])
133])
134
135AC_DEFUN_ONCE([gl_TYPE_CHAR8_T],
136[
137 dnl Determine whether gnulib's <uchar.h> would, if present, override char8_t.
138 AC_CACHE_CHECK([whether char8_t is correctly defined],
139 [gl_cv_type_char8_t_works],
140 [AC_COMPILE_IFELSE(
141 [AC_LANG_PROGRAM([[
142 #ifdef __HAIKU__
143 #include <stdint.h>
144 #endif
145 #include <uchar.h>
146 int verify[(char8_t)(-1) >= 0 && sizeof (char8_t) == sizeof (unsigned char) ? 1 : -1];
147 ]])
148 ],
149 [gl_cv_type_char8_t_works=yes],
150 [gl_cv_type_char8_t_works=no])
151 ])
152 if test $gl_cv_type_char8_t_works = no; then
153 GNULIBHEADERS_OVERRIDE_CHAR8_T=1
154 else
155 GNULIBHEADERS_OVERRIDE_CHAR8_T=0
156 fi
157 AC_SUBST([GNULIBHEADERS_OVERRIDE_CHAR8_T])
158])
159
160dnl On Haiku 2020, char16_t and char32_t are incorrectly defined.
161dnl See <https://dev.haiku-os.org/ticket/15990>.
162AC_DEFUN_ONCE([gl_TYPE_CHAR16_T],
163[
164 dnl Determine whether gnulib's <uchar.h> would, if present, override char16_t.
165 AC_CACHE_CHECK([whether char16_t is correctly defined],
166 [gl_cv_type_char16_t_works],
167 [AC_COMPILE_IFELSE(
168 [AC_LANG_PROGRAM([[
169 #ifdef __HAIKU__
170 #include <stdint.h>
171 #endif
172 #include <uchar.h>
173 /* For simplicity, assume that uint16_least_t is equivalent to
174 'unsigned short'. */
175 int verify[(char16_t)(-1) >= 0 && sizeof (char16_t) == sizeof (unsigned short) ? 1 : -1];
176 ]])
177 ],
178 [gl_cv_type_char16_t_works=yes],
179 [gl_cv_type_char16_t_works=no])
180 ])
181 if test $gl_cv_type_char16_t_works = no; then
182 GNULIBHEADERS_OVERRIDE_CHAR16_T=1
183 else
184 GNULIBHEADERS_OVERRIDE_CHAR16_T=0
185 fi
186 AC_SUBST([GNULIBHEADERS_OVERRIDE_CHAR16_T])
187])
188AC_DEFUN_ONCE([gl_TYPE_CHAR32_T],
189[
190 dnl Determine whether gnulib's <uchar.h> would, if present, override char32_t.
191 AC_CACHE_CHECK([whether char32_t is correctly defined],
192 [gl_cv_type_char32_t_works],
193 [AC_COMPILE_IFELSE(
194 [AC_LANG_PROGRAM([[
195 #ifdef __HAIKU__
196 #include <stdint.h>
197 #endif
198 #include <uchar.h>
199 /* For simplicity, assume that uint32_least_t is equivalent to
200 'unsigned int'. */
201 int verify[(char32_t)(-1) >= 0 && sizeof (char32_t) == sizeof (unsigned int) ? 1 : -1];
202 ]])
203 ],
204 [gl_cv_type_char32_t_works=yes],
205 [gl_cv_type_char32_t_works=no])
206 ])
207 if test $gl_cv_type_char32_t_works = no; then
208 GNULIBHEADERS_OVERRIDE_CHAR32_T=1
209 else
210 GNULIBHEADERS_OVERRIDE_CHAR32_T=0
211 fi
212 AC_SUBST([GNULIBHEADERS_OVERRIDE_CHAR32_T])
213])
214
215# gl_UCHAR_MODULE_INDICATOR([modulename])
216# sets the shell variable that indicates the presence of the given module
217# to a C preprocessor expression that will evaluate to 1.
218# This macro invocation must not occur in macros that are AC_REQUIREd.
219AC_DEFUN([gl_UCHAR_MODULE_INDICATOR],
220[
221 dnl Ensure to expand the default settings once only.
222 gl_UCHAR_H_REQUIRE_DEFAULTS
223 gl_MODULE_INDICATOR_SET_VARIABLE([$1])
224 dnl Define it also as a C macro, for the benefit of the unit tests.
225 gl_MODULE_INDICATOR_FOR_TESTS([$1])
226])
227
228# Initializes the default values for AC_SUBSTed shell variables.
229# This macro must not be AC_REQUIREd. It must only be invoked, and only
230# outside of macros or in macros that are not AC_REQUIREd.
231AC_DEFUN([gl_UCHAR_H_REQUIRE_DEFAULTS],
232[
233 m4_defun(GL_MODULE_INDICATOR_PREFIX[_UCHAR_H_MODULE_INDICATOR_DEFAULTS], [
234 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_BTOC32])
235 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32ISALNUM])
236 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32ISALPHA])
237 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32ISBLANK])
238 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32ISCNTRL])
239 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32ISDIGIT])
240 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32ISGRAPH])
241 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32ISLOWER])
242 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32ISPRINT])
243 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32ISPUNCT])
244 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32ISSPACE])
245 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32ISUPPER])
246 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32ISXDIGIT])
247 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32TOLOWER])
248 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32TOUPPER])
249 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32WIDTH])
250 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32RTOMB])
251 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32SNRTOMBS])
252 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32SRTOMBS])
253 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32STOMBS])
254 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32SWIDTH])
255 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32TOB])
256 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32_APPLY_MAPPING])
257 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32_APPLY_TYPE_TEST])
258 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32_GET_MAPPING])
259 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_C32_GET_TYPE_TEST])
260 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBRTOC16])
261 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBRTOC32])
262 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSNRTOC32S])
263 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSRTOC32S])
264 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSTOC32S])
265 ])
266 m4_require(GL_MODULE_INDICATOR_PREFIX[_UCHAR_H_MODULE_INDICATOR_DEFAULTS])
267 AC_REQUIRE([gl_UCHAR_H_DEFAULTS])
268])
269
270AC_DEFUN([gl_UCHAR_H_DEFAULTS],
271[
272 dnl Assume proper GNU behavior unless another module says otherwise.
273 HAVE_C32RTOMB=1; AC_SUBST([HAVE_C32RTOMB])
274 HAVE_MBRTOC16=1; AC_SUBST([HAVE_MBRTOC16])
275 HAVE_MBRTOC32=1; AC_SUBST([HAVE_MBRTOC32])
276 REPLACE_C32RTOMB=0; AC_SUBST([REPLACE_C32RTOMB])
277 REPLACE_MBRTOC16=0; AC_SUBST([REPLACE_MBRTOC16])
278 REPLACE_MBRTOC32=0; AC_SUBST([REPLACE_MBRTOC32])
279])
diff --git a/gl/m4/ungetc.m4 b/gl/m4/ungetc.m4
index 42f7ec32..969b60e8 100644
--- a/gl/m4/ungetc.m4
+++ b/gl/m4/ungetc.m4
@@ -1,9 +1,10 @@
1# ungetc.m4 1# ungetc.m4
2# serial 12 2# serial 12
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN_ONCE([gl_FUNC_UNGETC_WORKS], 9AC_DEFUN_ONCE([gl_FUNC_UNGETC_WORKS],
9[ 10[
diff --git a/gl/m4/unicase_h.m4 b/gl/m4/unicase_h.m4
new file mode 100644
index 00000000..bf5d4c2e
--- /dev/null
+++ b/gl/m4/unicase_h.m4
@@ -0,0 +1,45 @@
1# unicase_h.m4
2# serial 1
3dnl Copyright (C) 2023-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9AC_DEFUN_ONCE([gl_UNICASE_H],
10[
11 dnl Ensure to expand the default settings once only, before all statements
12 dnl that occur in other macros.
13 AC_REQUIRE([gl_UNICASE_H_DEFAULTS])
14])
15
16# gl_UNICASE_MODULE_INDICATOR([modulename])
17# sets the shell variable that indicates the presence of the given module
18# to a C preprocessor expression that will evaluate to 1.
19# This macro invocation must not occur in macros that are AC_REQUIREd.
20AC_DEFUN([gl_UNICASE_MODULE_INDICATOR],
21[
22 dnl Ensure to expand the default settings once only.
23 gl_UNICASE_H_REQUIRE_DEFAULTS
24 gl_MODULE_INDICATOR_SET_VARIABLE([$1])
25 dnl Define it also as a C macro, for the benefit of the unit tests.
26 gl_MODULE_INDICATOR_FOR_TESTS([$1])
27])
28
29# Initializes the default values for AC_SUBSTed shell variables.
30# This macro must not be AC_REQUIREd. It must only be invoked, and only
31# outside of macros or in macros that are not AC_REQUIREd.
32AC_DEFUN([gl_UNICASE_H_REQUIRE_DEFAULTS],
33[
34 m4_defun(GL_MODULE_INDICATOR_PREFIX[_UNICASE_H_MODULE_INDICATOR_DEFAULTS], [
35 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICASE_EMPTY_PREFIX_CONTEXT_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
36 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICASE_EMPTY_SUFFIX_CONTEXT_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
37 ])
38 m4_require(GL_MODULE_INDICATOR_PREFIX[_UNICASE_H_MODULE_INDICATOR_DEFAULTS])
39 AC_REQUIRE([gl_UNICASE_H_DEFAULTS])
40])
41
42AC_DEFUN([gl_UNICASE_H_DEFAULTS],
43[
44 dnl Assume proper GNU behavior unless another module says otherwise.
45])
diff --git a/gl/m4/unictype_h.m4 b/gl/m4/unictype_h.m4
new file mode 100644
index 00000000..68ddaf6c
--- /dev/null
+++ b/gl/m4/unictype_h.m4
@@ -0,0 +1,179 @@
1# unictype_h.m4
2# serial 4
3dnl Copyright (C) 2023-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9AC_DEFUN_ONCE([gl_UNICTYPE_H],
10[
11 dnl Ensure to expand the default settings once only, before all statements
12 dnl that occur in other macros.
13 AC_REQUIRE([gl_UNICTYPE_H_DEFAULTS])
14])
15
16# gl_UNICTYPE_MODULE_INDICATOR([modulename])
17# sets the shell variable that indicates the presence of the given module
18# to a C preprocessor expression that will evaluate to 1.
19# This macro invocation must not occur in macros that are AC_REQUIREd.
20AC_DEFUN([gl_UNICTYPE_MODULE_INDICATOR],
21[
22 dnl Ensure to expand the default settings once only.
23 gl_UNICTYPE_H_REQUIRE_DEFAULTS
24 gl_MODULE_INDICATOR_SET_VARIABLE([$1])
25 dnl Define it also as a C macro, for the benefit of the unit tests.
26 gl_MODULE_INDICATOR_FOR_TESTS([$1])
27])
28
29# Initializes the default values for AC_SUBSTed shell variables.
30# This macro must not be AC_REQUIREd. It must only be invoked, and only
31# outside of macros or in macros that are not AC_REQUIREd.
32AC_DEFUN([gl_UNICTYPE_H_REQUIRE_DEFAULTS],
33[
34 m4_defun(GL_MODULE_INDICATOR_PREFIX[_UNICTYPE_H_MODULE_INDICATOR_DEFAULTS], [
35 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_L_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
36 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_LC_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
37 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_LU_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
38 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_LL_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
39 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_LT_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
40 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_LM_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
41 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_LO_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
42 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_M_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
43 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_MN_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
44 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_MC_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
45 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_ME_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
46 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_N_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
47 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_ND_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
48 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_NL_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
49 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_NO_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
50 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_P_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
51 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_PC_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
52 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_PD_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
53 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_PS_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
54 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_PE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
55 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_PI_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
56 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_PF_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
57 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_PO_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
58 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_S_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
59 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_SM_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
60 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_SC_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
61 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_SK_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
62 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_SO_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
63 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_Z_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
64 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_ZS_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
65 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_ZL_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
66 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_ZP_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
67 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_C_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
68 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_CC_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
69 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_CF_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
70 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_CS_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
71 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_CO_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
72 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_CATEGORY_CN_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
73 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_WHITE_SPACE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
74 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_ALPHABETIC_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
75 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_OTHER_ALPHABETIC_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
76 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_NOT_A_CHARACTER_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
77 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_DEFAULT_IGNORABLE_CODE_POINT_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
78 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_OTHER_DEFAULT_IGNORABLE_CODE_POINT_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
79 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_DEPRECATED_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
80 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_LOGICAL_ORDER_EXCEPTION_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
81 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_VARIATION_SELECTOR_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
82 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_PRIVATE_USE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
83 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_UNASSIGNED_CODE_VALUE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
84 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_UPPERCASE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
85 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_OTHER_UPPERCASE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
86 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_LOWERCASE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
87 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_OTHER_LOWERCASE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
88 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_TITLECASE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
89 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_CASED_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
90 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_CASE_IGNORABLE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
91 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_LOWERCASED_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
92 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_UPPERCASED_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
93 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_TITLECASED_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
94 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_CASEFOLDED_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
95 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_CASEMAPPED_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
96 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_SOFT_DOTTED_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
97 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_ID_START_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
98 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_OTHER_ID_START_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
99 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_ID_CONTINUE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
100 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_OTHER_ID_CONTINUE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
101 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_XID_START_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
102 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_XID_CONTINUE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
103 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_ID_COMPAT_MATH_START_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
104 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_ID_COMPAT_MATH_CONTINUE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
105 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_PATTERN_WHITE_SPACE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
106 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_PATTERN_SYNTAX_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
107 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_JOIN_CONTROL_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
108 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_GRAPHEME_BASE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
109 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_GRAPHEME_EXTEND_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
110 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_OTHER_GRAPHEME_EXTEND_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
111 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_GRAPHEME_LINK_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
112 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_MODIFIER_COMBINING_MARK_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
113 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_CONTROL_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
114 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_LEFT_TO_RIGHT_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
115 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_HEBREW_RIGHT_TO_LEFT_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
116 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_ARABIC_RIGHT_TO_LEFT_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
117 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_EUROPEAN_DIGIT_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
118 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_EUR_NUM_SEPARATOR_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
119 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_EUR_NUM_TERMINATOR_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
120 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_ARABIC_DIGIT_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
121 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_COMMON_SEPARATOR_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
122 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_BLOCK_SEPARATOR_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
123 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_SEGMENT_SEPARATOR_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
124 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_WHITESPACE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
125 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_NON_SPACING_MARK_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
126 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_BOUNDARY_NEUTRAL_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
127 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_PDF_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
128 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_EMBEDDING_OR_OVERRIDE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
129 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_BIDI_OTHER_NEUTRAL_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
130 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_HEX_DIGIT_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
131 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_ASCII_HEX_DIGIT_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
132 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_IDEOGRAPHIC_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
133 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_UNIFIED_IDEOGRAPH_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
134 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_RADICAL_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
135 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_IDS_UNARY_OPERATOR_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
136 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_IDS_BINARY_OPERATOR_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
137 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_IDS_TRINARY_OPERATOR_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
138 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_EMOJI_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
139 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_EMOJI_PRESENTATION_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
140 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_EMOJI_MODIFIER_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
141 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_EMOJI_MODIFIER_BASE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
142 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_EMOJI_COMPONENT_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
143 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_EXTENDED_PICTOGRAPHIC_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
144 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_ZERO_WIDTH_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
145 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_SPACE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
146 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_NON_BREAK_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
147 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_ISO_CONTROL_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
148 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_FORMAT_CONTROL_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
149 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_PREPENDED_CONCATENATION_MARK_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
150 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_DASH_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
151 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_HYPHEN_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
152 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_PUNCTUATION_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
153 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_LINE_SEPARATOR_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
154 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_PARAGRAPH_SEPARATOR_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
155 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_QUOTATION_MARK_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
156 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_SENTENCE_TERMINAL_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
157 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_TERMINAL_PUNCTUATION_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
158 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_CURRENCY_SYMBOL_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
159 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_MATH_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
160 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_OTHER_MATH_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
161 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_PAIRED_PUNCTUATION_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
162 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_LEFT_OF_PAIR_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
163 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_COMBINING_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
164 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_COMPOSITE_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
165 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_DECIMAL_DIGIT_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
166 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_NUMERIC_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
167 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_DIACRITIC_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
168 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_EXTENDER_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
169 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_IGNORABLE_CONTROL_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
170 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNICTYPE_PROPERTY_REGIONAL_INDICATOR_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
171 ])
172 m4_require(GL_MODULE_INDICATOR_PREFIX[_UNICTYPE_H_MODULE_INDICATOR_DEFAULTS])
173 AC_REQUIRE([gl_UNICTYPE_H_DEFAULTS])
174])
175
176AC_DEFUN([gl_UNICTYPE_H_DEFAULTS],
177[
178 dnl Assume proper GNU behavior unless another module says otherwise.
179])
diff --git a/gl/m4/uninorm_h.m4 b/gl/m4/uninorm_h.m4
new file mode 100644
index 00000000..d416f73b
--- /dev/null
+++ b/gl/m4/uninorm_h.m4
@@ -0,0 +1,47 @@
1# uninorm_h.m4
2# serial 1
3dnl Copyright (C) 2023-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9AC_DEFUN_ONCE([gl_UNINORM_H],
10[
11 dnl Ensure to expand the default settings once only, before all statements
12 dnl that occur in other macros.
13 AC_REQUIRE([gl_UNINORM_H_DEFAULTS])
14])
15
16# gl_UNINORM_MODULE_INDICATOR([modulename])
17# sets the shell variable that indicates the presence of the given module
18# to a C preprocessor expression that will evaluate to 1.
19# This macro invocation must not occur in macros that are AC_REQUIREd.
20AC_DEFUN([gl_UNINORM_MODULE_INDICATOR],
21[
22 dnl Ensure to expand the default settings once only.
23 gl_UNINORM_H_REQUIRE_DEFAULTS
24 gl_MODULE_INDICATOR_SET_VARIABLE([$1])
25 dnl Define it also as a C macro, for the benefit of the unit tests.
26 gl_MODULE_INDICATOR_FOR_TESTS([$1])
27])
28
29# Initializes the default values for AC_SUBSTed shell variables.
30# This macro must not be AC_REQUIREd. It must only be invoked, and only
31# outside of macros or in macros that are not AC_REQUIREd.
32AC_DEFUN([gl_UNINORM_H_REQUIRE_DEFAULTS],
33[
34 m4_defun(GL_MODULE_INDICATOR_PREFIX[_UNINORM_H_MODULE_INDICATOR_DEFAULTS], [
35 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNINORM_NFD_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
36 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNINORM_NFC_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
37 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNINORM_NFKD_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
38 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNINORM_NFKC_DLL_VARIABLE], ['LIBUNISTRING_DLL_VARIABLE'])
39 ])
40 m4_require(GL_MODULE_INDICATOR_PREFIX[_UNINORM_H_MODULE_INDICATOR_DEFAULTS])
41 AC_REQUIRE([gl_UNINORM_H_DEFAULTS])
42])
43
44AC_DEFUN([gl_UNINORM_H_DEFAULTS],
45[
46 dnl Assume proper GNU behavior unless another module says otherwise.
47])
diff --git a/gl/m4/unistd_h.m4 b/gl/m4/unistd_h.m4
index 81d1b9f6..6ec16286 100644
--- a/gl/m4/unistd_h.m4
+++ b/gl/m4/unistd_h.m4
@@ -1,9 +1,10 @@
1# unistd_h.m4 1# unistd_h.m4
2# serial 95 2# serial 97
3dnl Copyright (C) 2006-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2006-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Written by Simon Josefsson, Bruno Haible. 9dnl Written by Simon Josefsson, Bruno Haible.
9 10
@@ -243,11 +244,13 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS],
243 REPLACE_GETDOMAINNAME=0; AC_SUBST([REPLACE_GETDOMAINNAME]) 244 REPLACE_GETDOMAINNAME=0; AC_SUBST([REPLACE_GETDOMAINNAME])
244 REPLACE_GETDTABLESIZE=0; AC_SUBST([REPLACE_GETDTABLESIZE]) 245 REPLACE_GETDTABLESIZE=0; AC_SUBST([REPLACE_GETDTABLESIZE])
245 REPLACE_GETENTROPY=0; AC_SUBST([REPLACE_GETENTROPY]) 246 REPLACE_GETENTROPY=0; AC_SUBST([REPLACE_GETENTROPY])
247 REPLACE_GETLOGIN=0; AC_SUBST([REPLACE_GETLOGIN])
246 REPLACE_GETLOGIN_R=0; AC_SUBST([REPLACE_GETLOGIN_R]) 248 REPLACE_GETLOGIN_R=0; AC_SUBST([REPLACE_GETLOGIN_R])
247 REPLACE_GETGROUPS=0; AC_SUBST([REPLACE_GETGROUPS]) 249 REPLACE_GETGROUPS=0; AC_SUBST([REPLACE_GETGROUPS])
248 REPLACE_GETPAGESIZE=0; AC_SUBST([REPLACE_GETPAGESIZE]) 250 REPLACE_GETPAGESIZE=0; AC_SUBST([REPLACE_GETPAGESIZE])
249 REPLACE_GETPASS=0; AC_SUBST([REPLACE_GETPASS]) 251 REPLACE_GETPASS=0; AC_SUBST([REPLACE_GETPASS])
250 REPLACE_GETPASS_FOR_GETPASS_GNU=0; AC_SUBST([REPLACE_GETPASS_FOR_GETPASS_GNU]) 252 REPLACE_GETPASS_FOR_GETPASS_GNU=0; AC_SUBST([REPLACE_GETPASS_FOR_GETPASS_GNU])
253 REPLACE_GETUSERSHELL=0; AC_SUBST([REPLACE_GETUSERSHELL])
251 REPLACE_ISATTY=0; AC_SUBST([REPLACE_ISATTY]) 254 REPLACE_ISATTY=0; AC_SUBST([REPLACE_ISATTY])
252 REPLACE_LCHOWN=0; AC_SUBST([REPLACE_LCHOWN]) 255 REPLACE_LCHOWN=0; AC_SUBST([REPLACE_LCHOWN])
253 REPLACE_LINK=0; AC_SUBST([REPLACE_LINK]) 256 REPLACE_LINK=0; AC_SUBST([REPLACE_LINK])
diff --git a/gl/m4/unitypes_h.m4 b/gl/m4/unitypes_h.m4
new file mode 100644
index 00000000..264e61be
--- /dev/null
+++ b/gl/m4/unitypes_h.m4
@@ -0,0 +1,26 @@
1# unitypes_h.m4
2# serial 1
3dnl Copyright (C) 2021-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9AC_DEFUN_ONCE([gl_UNITYPES_H],
10[
11 AH_VERBATIM([unitypes_restrict], [
12/* This definition is a duplicate of the one in unitypes.h.
13 It is here so that we can cope with an older version of unitypes.h
14 that does not contain this definition and that is pre-installed among
15 the public header files. */
16# if defined __restrict \
17 || 2 < __GNUC__ + (95 <= __GNUC_MINOR__) \
18 || __clang_major__ >= 3
19# define _UC_RESTRICT __restrict
20# elif 199901L <= __STDC_VERSION__ || defined restrict
21# define _UC_RESTRICT restrict
22# else
23# define _UC_RESTRICT
24# endif
25])
26])
diff --git a/gl/m4/unlocked-io.m4 b/gl/m4/unlocked-io.m4
index e96cf5f8..97f43f4b 100644
--- a/gl/m4/unlocked-io.m4
+++ b/gl/m4/unlocked-io.m4
@@ -1,9 +1,10 @@
1# unlocked-io.m4 1# unlocked-io.m4
2# serial 16 2# serial 16
3dnl Copyright (C) 1998-2006, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 1998-2006, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Jim Meyering. 9dnl From Jim Meyering.
9dnl 10dnl
diff --git a/gl/m4/vararrays.m4 b/gl/m4/vararrays.m4
index 9211f69d..086e409f 100644
--- a/gl/m4/vararrays.m4
+++ b/gl/m4/vararrays.m4
@@ -1,9 +1,10 @@
1# vararrays.m4 1# vararrays.m4
2# serial 6 2# serial 6
3dnl Copyright (C) 2001, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2001, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# Check for variable-length arrays. 9# Check for variable-length arrays.
9 10
diff --git a/gl/m4/vasnprintf.m4 b/gl/m4/vasnprintf.m4
index 1ea2055e..1d040d6e 100644
--- a/gl/m4/vasnprintf.m4
+++ b/gl/m4/vasnprintf.m4
@@ -1,14 +1,47 @@
1# vasnprintf.m4 1# vasnprintf.m4
2# serial 52 2# serial 56
3dnl Copyright (C) 2002-2004, 2006-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2002-2004, 2006-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_VASNPRINTF], 9AC_DEFUN([gl_FUNC_VASNPRINTF],
9[ 10[
11 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
10 AC_CHECK_FUNCS_ONCE([vasnprintf]) 12 AC_CHECK_FUNCS_ONCE([vasnprintf])
11 if test $ac_cv_func_vasnprintf = no; then 13 if test $ac_cv_func_vasnprintf = yes; then
14 dnl On Cygwin, in directives with a huge width, the width is ignored, and
15 dnl the function returns a wrong result.
16 AC_CACHE_CHECK([whether vasnprintf works],
17 [gl_cv_func_vasnprintf_works],
18 [AC_RUN_IFELSE(
19 [AC_LANG_SOURCE(
20 [[#include <stdio.h>
21 ]],
22 [[size_t len;
23 char *res = vasnprintf (NULL, &len, "x%03000000000dy\n", -17);
24 /* On Cygwin 3.4.6, res is "x-17y\n" and len == 6: wrong. */
25 return (res != NULL && len < 10);
26 ]])
27 ],
28 [gl_cv_func_vasnprintf_works=yes],
29 [gl_cv_func_vasnprintf_works=no],
30 [case "$host_os" in
31 # Guess no on Cygwin.
32 cygwin*) gl_cv_func_vasnprintf_works="guessing no";;
33 # If we don't know, obey --enable-cross-guesses.
34 *) gl_cv_func_vasnprintf_works="$gl_cross_guess_normal";;
35 esac
36 ])
37 ])
38 fi
39 if test $ac_cv_func_vasnprintf != yes \
40 || case "$gl_cv_func_vasnprintf_works" in
41 *yes) false;;
42 *) true;;
43 esac
44 then
12 gl_REPLACE_VASNPRINTF 45 gl_REPLACE_VASNPRINTF
13 fi 46 fi
14]) 47])
@@ -42,7 +75,6 @@ AC_DEFUN([gl_FUNC_VASNWPRINTF],
42# Prerequisites of lib/printf-args.h, lib/printf-args.c. 75# Prerequisites of lib/printf-args.h, lib/printf-args.c.
43AC_DEFUN([gl_PREREQ_PRINTF_ARGS], 76AC_DEFUN([gl_PREREQ_PRINTF_ARGS],
44[ 77[
45 AC_REQUIRE([gt_TYPE_WCHAR_T])
46 AC_REQUIRE([gt_TYPE_WINT_T]) 78 AC_REQUIRE([gt_TYPE_WINT_T])
47]) 79])
48 80
@@ -51,7 +83,6 @@ AC_DEFUN([gl_PREREQ_PRINTF_ARGS],
51AC_DEFUN([gl_PREREQ_PRINTF_PARSE], 83AC_DEFUN([gl_PREREQ_PRINTF_PARSE],
52[ 84[
53 AC_REQUIRE([gl_FEATURES_H]) 85 AC_REQUIRE([gl_FEATURES_H])
54 AC_REQUIRE([gt_TYPE_WCHAR_T])
55 AC_REQUIRE([gt_TYPE_WINT_T]) 86 AC_REQUIRE([gt_TYPE_WINT_T])
56 AC_REQUIRE([AC_TYPE_SIZE_T]) 87 AC_REQUIRE([AC_TYPE_SIZE_T])
57 AC_CHECK_TYPE([ptrdiff_t], , 88 AC_CHECK_TYPE([ptrdiff_t], ,
@@ -185,7 +216,6 @@ int main()
185AC_DEFUN_ONCE([gl_PREREQ_VASNXPRINTF], 216AC_DEFUN_ONCE([gl_PREREQ_VASNXPRINTF],
186[ 217[
187 AC_REQUIRE([AC_FUNC_ALLOCA]) 218 AC_REQUIRE([AC_FUNC_ALLOCA])
188 AC_REQUIRE([gt_TYPE_WCHAR_T])
189 AC_REQUIRE([gt_TYPE_WINT_T]) 219 AC_REQUIRE([gt_TYPE_WINT_T])
190 AC_CHECK_FUNCS([wcslen]) 220 AC_CHECK_FUNCS([wcslen])
191 dnl Knowing DBL_EXPBIT0_WORD and DBL_EXPBIT0_BIT enables an optimization 221 dnl Knowing DBL_EXPBIT0_WORD and DBL_EXPBIT0_BIT enables an optimization
@@ -327,15 +357,39 @@ AC_DEFUN([gl_PREREQ_VASNPRINTF_DIRECTIVE_LC],
327# Extra prerequisites of lib/vasnprintf.c for supporting the ' flag. 357# Extra prerequisites of lib/vasnprintf.c for supporting the ' flag.
328AC_DEFUN([gl_PREREQ_VASNPRINTF_FLAG_GROUPING], 358AC_DEFUN([gl_PREREQ_VASNPRINTF_FLAG_GROUPING],
329[ 359[
360 AC_REQUIRE([AC_CANONICAL_HOST])
330 AC_REQUIRE([gl_PRINTF_FLAG_GROUPING]) 361 AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
331 case "$gl_cv_func_printf_flag_grouping" in 362 AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_INT_PRECISION])
332 *yes) 363 AC_REQUIRE([gl_PRINTF_FLAG_GROUPING_MULTIBYTE])
333 ;; 364 case "$host_os" in
334 *) 365 mingw* | windows*)
366 dnl MSVC does not support the ' flag at all.
367 dnl mingw does not support it, unless __USE_MINGW_ANSI_STDIO is defined.
368 dnl mingw also has other bugs regarding the ' flag.
335 AC_DEFINE([NEED_PRINTF_FLAG_GROUPING], [1], 369 AC_DEFINE([NEED_PRINTF_FLAG_GROUPING], [1],
336 [Define if the vasnprintf implementation needs special code for the 370 [Define if the vasnprintf implementation needs special code for the
337 ' flag.]) 371 ' flag.])
338 ;; 372 ;;
373 *)
374 case "$gl_cv_func_printf_flag_grouping,$gl_cv_func_printf_flag_grouping_multibyte" in
375 *yes,*yes)
376 case "$gl_cv_func_printf_flag_grouping_int_precision" in
377 *yes)
378 ;;
379 *)
380 AC_DEFINE([NEED_PRINTF_FLAG_GROUPING_INT], [1],
381 [Define if the vasnprintf implementation needs special code for the
382 ' flag, for integer directives only.])
383 ;;
384 esac
385 ;;
386 *)
387 AC_DEFINE([NEED_PRINTF_FLAG_GROUPING], [1],
388 [Define if the vasnprintf implementation needs special code for the
389 ' flag.])
390 ;;
391 esac
392 ;;
339 esac 393 esac
340]) 394])
341 395
diff --git a/gl/m4/vasprintf.m4 b/gl/m4/vasprintf.m4
index 73f7b807..6ea602bd 100644
--- a/gl/m4/vasprintf.m4
+++ b/gl/m4/vasprintf.m4
@@ -1,10 +1,11 @@
1# vasprintf.m4 1# vasprintf.m4
2# serial 6 2# serial 6
3dnl Copyright (C) 2002-2003, 2006-2007, 2009-2024 Free Software Foundation, 3dnl Copyright (C) 2002-2003, 2006-2007, 2009-2025 Free Software Foundation,
4dnl Inc. 4dnl Inc.
5dnl This file is free software; the Free Software Foundation 5dnl This file is free software; the Free Software Foundation
6dnl gives unlimited permission to copy and/or distribute it, 6dnl gives unlimited permission to copy and/or distribute it,
7dnl with or without modifications, as long as this notice is preserved. 7dnl with or without modifications, as long as this notice is preserved.
8dnl This file is offered as-is, without any warranty.
8 9
9AC_DEFUN([gl_FUNC_VASPRINTF], 10AC_DEFUN([gl_FUNC_VASPRINTF],
10[ 11[
diff --git a/gl/m4/visibility.m4 b/gl/m4/visibility.m4
index ecf09686..c2cd38d0 100644
--- a/gl/m4/visibility.m4
+++ b/gl/m4/visibility.m4
@@ -1,9 +1,10 @@
1# visibility.m4 1# visibility.m4
2# serial 9 2# serial 9
3dnl Copyright (C) 2005, 2008, 2010-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2005, 2008, 2010-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Bruno Haible. 9dnl From Bruno Haible.
9 10
diff --git a/gl/m4/vsnprintf.m4 b/gl/m4/vsnprintf.m4
index 9f321f3f..68ab757d 100644
--- a/gl/m4/vsnprintf.m4
+++ b/gl/m4/vsnprintf.m4
@@ -1,9 +1,10 @@
1# vsnprintf.m4 1# vsnprintf.m4
2# serial 7 2# serial 7
3dnl Copyright (C) 2002-2004, 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2002-2004, 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl Libintl 0.17 will replace vsnprintf only if it does not support %1$s, 9dnl Libintl 0.17 will replace vsnprintf only if it does not support %1$s,
9dnl but defers to any gnulib vsnprintf replacements. Therefore, gnulib 10dnl but defers to any gnulib vsnprintf replacements. Therefore, gnulib
diff --git a/gl/m4/warn-on-use.m4 b/gl/m4/warn-on-use.m4
index 6c8c76b8..73cf16fb 100644
--- a/gl/m4/warn-on-use.m4
+++ b/gl/m4/warn-on-use.m4
@@ -1,9 +1,10 @@
1# warn-on-use.m4 1# warn-on-use.m4
2# serial 11 2# serial 11
3dnl Copyright (C) 2010-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2010-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8# gl_WARN_ON_USE_PREPARE(INCLUDES, NAMES) 9# gl_WARN_ON_USE_PREPARE(INCLUDES, NAMES)
9# --------------------------------------- 10# ---------------------------------------
diff --git a/gl/m4/wchar_h.m4 b/gl/m4/wchar_h.m4
index 995bdc65..722fcfc2 100644
--- a/gl/m4/wchar_h.m4
+++ b/gl/m4/wchar_h.m4
@@ -1,9 +1,10 @@
1# wchar_h.m4 1# wchar_h.m4
2# serial 64 2# serial 65
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl A placeholder for ISO C99 <wchar.h>, for platforms that have issues. 9dnl A placeholder for ISO C99 <wchar.h>, for platforms that have issues.
9 10
@@ -256,6 +257,7 @@ AC_DEFUN([gl_WCHAR_H_DEFAULTS],
256 REPLACE_WCSWIDTH=0; AC_SUBST([REPLACE_WCSWIDTH]) 257 REPLACE_WCSWIDTH=0; AC_SUBST([REPLACE_WCSWIDTH])
257 REPLACE_WCSFTIME=0; AC_SUBST([REPLACE_WCSFTIME]) 258 REPLACE_WCSFTIME=0; AC_SUBST([REPLACE_WCSFTIME])
258 REPLACE_WCSCMP=0; AC_SUBST([REPLACE_WCSCMP]) 259 REPLACE_WCSCMP=0; AC_SUBST([REPLACE_WCSCMP])
260 REPLACE_WCSNCAT=0; AC_SUBST([REPLACE_WCSNCAT])
259 REPLACE_WCSNCMP=0; AC_SUBST([REPLACE_WCSNCMP]) 261 REPLACE_WCSNCMP=0; AC_SUBST([REPLACE_WCSNCMP])
260 REPLACE_WCSSTR=0; AC_SUBST([REPLACE_WCSSTR]) 262 REPLACE_WCSSTR=0; AC_SUBST([REPLACE_WCSSTR])
261 REPLACE_WCSTOK=0; AC_SUBST([REPLACE_WCSTOK]) 263 REPLACE_WCSTOK=0; AC_SUBST([REPLACE_WCSTOK])
diff --git a/gl/m4/wchar_t.m4 b/gl/m4/wchar_t.m4
deleted file mode 100644
index 968832cb..00000000
--- a/gl/m4/wchar_t.m4
+++ /dev/null
@@ -1,25 +0,0 @@
1# wchar_t.m4
2# serial 4 (gettext-0.18.2)
3dnl Copyright (C) 2002-2003, 2008-2024 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7
8dnl From Bruno Haible.
9dnl Test whether <stddef.h> has the 'wchar_t' type.
10dnl Prerequisite: AC_PROG_CC
11
12AC_DEFUN([gt_TYPE_WCHAR_T],
13[
14 AC_CACHE_CHECK([for wchar_t], [gt_cv_c_wchar_t],
15 [AC_COMPILE_IFELSE(
16 [AC_LANG_PROGRAM(
17 [[#include <stddef.h>
18 wchar_t foo = (wchar_t)'\0';]],
19 [[]])],
20 [gt_cv_c_wchar_t=yes],
21 [gt_cv_c_wchar_t=no])])
22 if test $gt_cv_c_wchar_t = yes; then
23 AC_DEFINE([HAVE_WCHAR_T], [1], [Define if you have the 'wchar_t' type.])
24 fi
25])
diff --git a/gl/m4/wcrtomb.m4 b/gl/m4/wcrtomb.m4
index 35dff6f0..91530176 100644
--- a/gl/m4/wcrtomb.m4
+++ b/gl/m4/wcrtomb.m4
@@ -1,9 +1,10 @@
1# wcrtomb.m4 1# wcrtomb.m4
2# serial 19 2# serial 21
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_FUNC_WCRTOMB], 9AC_DEFUN([gl_FUNC_WCRTOMB],
9[ 10[
@@ -36,7 +37,7 @@ AC_DEFUN([gl_FUNC_WCRTOMB],
36 dnl sometimes returns 0 instead of 1. 37 dnl sometimes returns 0 instead of 1.
37 AC_REQUIRE([AC_PROG_CC]) 38 AC_REQUIRE([AC_PROG_CC])
38 AC_REQUIRE([gt_LOCALE_FR]) 39 AC_REQUIRE([gt_LOCALE_FR])
39 AC_REQUIRE([gt_LOCALE_FR_UTF8]) 40 AC_REQUIRE([gt_LOCALE_EN_UTF8])
40 AC_REQUIRE([gt_LOCALE_JA]) 41 AC_REQUIRE([gt_LOCALE_JA])
41 AC_REQUIRE([gt_LOCALE_ZH_CN]) 42 AC_REQUIRE([gt_LOCALE_ZH_CN])
42 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles 43 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
@@ -90,7 +91,7 @@ changequote(,)dnl
90 gl_cv_func_wcrtomb_retval="guessing yes" ;; 91 gl_cv_func_wcrtomb_retval="guessing yes" ;;
91 esac 92 esac
92changequote([,])dnl 93changequote([,])dnl
93 if test $LOCALE_FR != none || test $LOCALE_FR_UTF8 != none || test $LOCALE_JA != none || test $LOCALE_ZH_CN != none; then 94 if test $LOCALE_FR != none || test "$LOCALE_EN_UTF8" != none || test $LOCALE_JA != none || test $LOCALE_ZH_CN != none; then
94 AC_RUN_IFELSE( 95 AC_RUN_IFELSE(
95 [AC_LANG_SOURCE([[ 96 [AC_LANG_SOURCE([[
96#include <locale.h> 97#include <locale.h>
@@ -106,8 +107,8 @@ int main ()
106 if (wcrtomb (NULL, 0, NULL) != 1) 107 if (wcrtomb (NULL, 0, NULL) != 1)
107 result |= 1; 108 result |= 1;
108 } 109 }
109 if (strcmp ("$LOCALE_FR_UTF8", "none") != 0 110 if (strcmp ("$LOCALE_EN_UTF8", "none") != 0
110 && setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL) 111 && setlocale (LC_ALL, "$LOCALE_EN_UTF8") != NULL)
111 { 112 {
112 if (wcrtomb (NULL, 0, NULL) != 1) 113 if (wcrtomb (NULL, 0, NULL) != 1)
113 result |= 2; 114 result |= 2;
diff --git a/gl/m4/wctype.m4 b/gl/m4/wctype.m4
index e5d70740..56593cd5 100644
--- a/gl/m4/wctype.m4
+++ b/gl/m4/wctype.m4
@@ -1,9 +1,10 @@
1# wctype.m4 1# wctype.m4
2# serial 6 2# serial 6
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2011-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN_ONCE([gl_FUNC_WCTYPE], 9AC_DEFUN_ONCE([gl_FUNC_WCTYPE],
9[ 10[
diff --git a/gl/m4/wctype_h.m4 b/gl/m4/wctype_h.m4
index a3b07c2a..8e54678d 100644
--- a/gl/m4/wctype_h.m4
+++ b/gl/m4/wctype_h.m4
@@ -3,10 +3,11 @@
3 3
4dnl A placeholder for ISO C99 <wctype.h>, for platforms that lack it. 4dnl A placeholder for ISO C99 <wctype.h>, for platforms that lack it.
5 5
6dnl Copyright (C) 2006-2024 Free Software Foundation, Inc. 6dnl Copyright (C) 2006-2025 Free Software Foundation, Inc.
7dnl This file is free software; the Free Software Foundation 7dnl This file is free software; the Free Software Foundation
8dnl gives unlimited permission to copy and/or distribute it, 8dnl gives unlimited permission to copy and/or distribute it,
9dnl with or without modifications, as long as this notice is preserved. 9dnl with or without modifications, as long as this notice is preserved.
10dnl This file is offered as-is, without any warranty.
10 11
11dnl Written by Paul Eggert. 12dnl Written by Paul Eggert.
12 13
diff --git a/gl/m4/wcwidth.m4 b/gl/m4/wcwidth.m4
new file mode 100644
index 00000000..2cc6ebb1
--- /dev/null
+++ b/gl/m4/wcwidth.m4
@@ -0,0 +1,116 @@
1# wcwidth.m4
2# serial 38
3dnl Copyright (C) 2006-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
8
9AC_DEFUN([gl_FUNC_WCWIDTH],
10[
11 AC_REQUIRE([gl_WCHAR_H_DEFAULTS])
12 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
13
14 dnl Persuade glibc <wchar.h> to declare wcwidth().
15 AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
16
17 AC_REQUIRE([gt_TYPE_WINT_T])
18
19 AC_CHECK_HEADERS_ONCE([wchar.h])
20 AC_CHECK_FUNCS_ONCE([wcwidth])
21
22 AC_CHECK_DECLS([wcwidth], [], [], [[
23 #include <wchar.h>
24 ]])
25 if test $ac_cv_have_decl_wcwidth != yes; then
26 HAVE_DECL_WCWIDTH=0
27 fi
28
29 if test $ac_cv_func_wcwidth != yes; then
30 AC_CACHE_CHECK([whether wcwidth is a macro],
31 [gl_cv_func_wcwidth_macro],
32 [AC_EGREP_CPP([wchar_header_defines_wcwidth], [
33#include <wchar.h>
34#ifdef wcwidth
35 wchar_header_defines_wcwidth
36#endif],
37 [gl_cv_func_wcwidth_macro=yes],
38 [gl_cv_func_wcwidth_macro=no])
39 ])
40 fi
41
42 if test $ac_cv_func_wcwidth = yes || test $gl_cv_func_wcwidth_macro = yes; then
43 HAVE_WCWIDTH=1
44 dnl On Mac OS X 10.3, wcwidth(0x0301) (COMBINING ACUTE ACCENT) returns 1.
45 dnl On macOS 12.5, NetBSD 9.3, OpenBSD 5.0, MidnightBSD 1.1,
46 dnl wcwidth(0x05B0) (HEBREW POINT SHEVA) returns 1.
47 dnl On macOS 12.5, NetBSD 9.3, MidnightBSD 1.1, OSF/1 5.1,
48 dnl wcwidth(0x200B) (ZERO WIDTH SPACE) returns 1.
49 dnl On OpenBSD 5.8, wcwidth(0xFF1A) (FULLWIDTH COLON) returns 0.
50 dnl This leads to bugs in 'ls' (coreutils).
51 dnl On Solaris 11.4, wcwidth(0x2202) (PARTIAL DIFFERENTIAL) returns 2,
52 dnl even in Western locales.
53 AC_CACHE_CHECK([whether wcwidth works reasonably in UTF-8 locales],
54 [gl_cv_func_wcwidth_works],
55 [
56 AC_RUN_IFELSE(
57 [AC_LANG_SOURCE([[
58#include <locale.h>
59#include <wchar.h>
60#if !HAVE_DECL_WCWIDTH
61extern
62# ifdef __cplusplus
63"C"
64# endif
65int wcwidth (int);
66#endif
67int main ()
68{
69 int result = 0;
70 if (setlocale (LC_ALL, "en_US.UTF-8") != NULL)
71 {
72 if (wcwidth (0x0301) > 0)
73 result |= 1;
74 if (wcwidth (0x05B0) > 0)
75 result |= 2;
76 if (wcwidth (0x200B) > 0)
77 result |= 4;
78 if (wcwidth (0xFF1A) == 0)
79 result |= 8;
80 if (wcwidth (0x2202) > 1)
81 result |= 16;
82 }
83 return result;
84}]])],
85 [gl_cv_func_wcwidth_works=yes],
86 [gl_cv_func_wcwidth_works=no],
87 [
88changequote(,)dnl
89 case "$host_os" in
90 # Guess yes on glibc systems.
91 *-gnu* | gnu*) gl_cv_func_wcwidth_works="guessing yes";;
92 # Guess yes on musl systems.
93 *-musl* | midipix*) gl_cv_func_wcwidth_works="guessing yes";;
94 # Guess yes on AIX 7 systems.
95 aix[7-9]*) gl_cv_func_wcwidth_works="guessing yes";;
96 *) gl_cv_func_wcwidth_works="$gl_cross_guess_normal";;
97 esac
98changequote([,])dnl
99 ])
100 ])
101 case "$gl_cv_func_wcwidth_works" in
102 *yes) ;;
103 *no) REPLACE_WCWIDTH=1 ;;
104 esac
105 else
106 HAVE_WCWIDTH=0
107 fi
108 dnl We don't substitute HAVE_WCWIDTH. We assume that if the system does not
109 dnl have the wcwidth function, then it does not declare it.
110])
111
112# Prerequisites of lib/wcwidth.c.
113AC_DEFUN([gl_PREREQ_WCWIDTH], [
114 AC_REQUIRE([AC_C_INLINE])
115 :
116])
diff --git a/gl/m4/wint_t.m4 b/gl/m4/wint_t.m4
index 883fac28..8a3c7944 100644
--- a/gl/m4/wint_t.m4
+++ b/gl/m4/wint_t.m4
@@ -1,9 +1,10 @@
1# wint_t.m4 1# wint_t.m4
2# serial 11 2# serial 11
3dnl Copyright (C) 2003, 2007-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2003, 2007-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl From Bruno Haible. 9dnl From Bruno Haible.
9dnl Test whether <wchar.h> has the 'wint_t' type and whether gnulib's 10dnl Test whether <wchar.h> has the 'wint_t' type and whether gnulib's
diff --git a/gl/m4/xalloc.m4 b/gl/m4/xalloc.m4
index d44d0f08..c10c4189 100644
--- a/gl/m4/xalloc.m4
+++ b/gl/m4/xalloc.m4
@@ -1,8 +1,9 @@
1# xalloc.m4 1# xalloc.m4
2# serial 18 2# serial 18
3dnl Copyright (C) 2002-2006, 2009-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2002-2006, 2009-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_XALLOC], [:]) 9AC_DEFUN([gl_XALLOC], [:])
diff --git a/gl/m4/xsize.m4 b/gl/m4/xsize.m4
index e5784973..157d635c 100644
--- a/gl/m4/xsize.m4
+++ b/gl/m4/xsize.m4
@@ -1,9 +1,10 @@
1# xsize.m4 1# xsize.m4
2# serial 5 2# serial 5
3dnl Copyright (C) 2003-2004, 2008-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2003-2004, 2008-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8AC_DEFUN([gl_XSIZE], 9AC_DEFUN([gl_XSIZE],
9[ 10[
diff --git a/gl/m4/zzgnulib.m4 b/gl/m4/zzgnulib.m4
index 710fba4e..343bda5c 100644
--- a/gl/m4/zzgnulib.m4
+++ b/gl/m4/zzgnulib.m4
@@ -1,9 +1,10 @@
1# zzgnulib.m4 1# zzgnulib.m4
2# serial 1 2# serial 1
3dnl Copyright (C) 2020-2024 Free Software Foundation, Inc. 3dnl Copyright (C) 2020-2025 Free Software Foundation, Inc.
4dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7dnl This file is offered as-is, without any warranty.
7 8
8dnl This file must be named something that sorts after all other 9dnl This file must be named something that sorts after all other
9dnl package- or gnulib-provided .m4 files - at least for those packages 10dnl package- or gnulib-provided .m4 files - at least for those packages
diff --git a/gl/malloc.c b/gl/malloc.c
index 2a7867a1..5642c83c 100644
--- a/gl/malloc.c
+++ b/gl/malloc.c
@@ -1,6 +1,6 @@
1/* malloc() function that is glibc compatible. 1/* malloc() function that is glibc compatible.
2 2
3 Copyright (C) 1997-1998, 2006-2007, 2009-2024 Free Software Foundation, Inc. 3 Copyright (C) 1997-1998, 2006-2007, 2009-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -17,28 +17,33 @@
17 17
18/* written by Jim Meyering and Bruno Haible */ 18/* written by Jim Meyering and Bruno Haible */
19 19
20/* Ensure that we call the system's malloc() below. */
20#define _GL_USE_STDLIB_ALLOC 1 21#define _GL_USE_STDLIB_ALLOC 1
21#include <config.h> 22#include <config.h>
22 23
23#include <stdlib.h> 24#include <stdlib.h>
24 25
25#include <errno.h> 26#include <errno.h>
26 27#include <stdckdint.h>
27#include "xalloc-oversized.h"
28 28
29/* Allocate an N-byte block of memory from the heap, even if N is 0. */ 29/* Allocate an N-byte block of memory from the heap, even if N is 0. */
30 30
31void * 31void *
32rpl_malloc (size_t n) 32rpl_malloc (size_t n)
33{ 33{
34#if !HAVE_MALLOC_0_NONNULL
34 if (n == 0) 35 if (n == 0)
35 n = 1; 36 n = 1;
37#endif
36 38
37 if (xalloc_oversized (n, 1)) 39#if !HAVE_MALLOC_PTRDIFF
40 ptrdiff_t signed_n;
41 if (ckd_add (&signed_n, n, 0))
38 { 42 {
39 errno = ENOMEM; 43 errno = ENOMEM;
40 return NULL; 44 return NULL;
41 } 45 }
46#endif
42 47
43 void *result = malloc (n); 48 void *result = malloc (n);
44 49
diff --git a/gl/malloc/dynarray-skeleton.c b/gl/malloc/dynarray-skeleton.c
index a95241ab..6b0585c1 100644
--- a/gl/malloc/dynarray-skeleton.c
+++ b/gl/malloc/dynarray-skeleton.c
@@ -1,5 +1,5 @@
1/* Type-safe arrays which grow dynamically. 1/* Type-safe arrays which grow dynamically.
2 Copyright (C) 2017-2024 Free Software Foundation, Inc. 2 Copyright (C) 2017-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 4
5 The GNU C Library is free software; you can redistribute it and/or 5 The GNU C Library is free software; you can redistribute it and/or
diff --git a/gl/malloc/dynarray.h b/gl/malloc/dynarray.h
index 3163e278..6cbbe50e 100644
--- a/gl/malloc/dynarray.h
+++ b/gl/malloc/dynarray.h
@@ -1,5 +1,5 @@
1/* Type-safe arrays which grow dynamically. Shared definitions. 1/* Type-safe arrays which grow dynamically. Shared definitions.
2 Copyright (C) 2017-2024 Free Software Foundation, Inc. 2 Copyright (C) 2017-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 4
5 The GNU C Library is free software; you can redistribute it and/or 5 The GNU C Library is free software; you can redistribute it and/or
diff --git a/gl/malloc/dynarray_at_failure.c b/gl/malloc/dynarray_at_failure.c
index 95e34e7a..b94ac3df 100644
--- a/gl/malloc/dynarray_at_failure.c
+++ b/gl/malloc/dynarray_at_failure.c
@@ -1,5 +1,5 @@
1/* Report an dynamic array index out of bounds condition. 1/* Report an dynamic array index out of bounds condition.
2 Copyright (C) 2017-2024 Free Software Foundation, Inc. 2 Copyright (C) 2017-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 4
5 The GNU C Library is free software; you can redistribute it and/or 5 The GNU C Library is free software; you can redistribute it and/or
diff --git a/gl/malloc/dynarray_emplace_enlarge.c b/gl/malloc/dynarray_emplace_enlarge.c
index 7bdba159..53126863 100644
--- a/gl/malloc/dynarray_emplace_enlarge.c
+++ b/gl/malloc/dynarray_emplace_enlarge.c
@@ -1,5 +1,5 @@
1/* Increase the size of a dynamic array in preparation of an emplace operation. 1/* Increase the size of a dynamic array in preparation of an emplace operation.
2 Copyright (C) 2017-2024 Free Software Foundation, Inc. 2 Copyright (C) 2017-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 4
5 The GNU C Library is free software; you can redistribute it and/or 5 The GNU C Library is free software; you can redistribute it and/or
diff --git a/gl/malloc/dynarray_finalize.c b/gl/malloc/dynarray_finalize.c
index 52764f73..3178c687 100644
--- a/gl/malloc/dynarray_finalize.c
+++ b/gl/malloc/dynarray_finalize.c
@@ -1,5 +1,5 @@
1/* Copy the dynamically-allocated area to an explicitly-sized heap allocation. 1/* Copy the dynamically-allocated area to an explicitly-sized heap allocation.
2 Copyright (C) 2017-2024 Free Software Foundation, Inc. 2 Copyright (C) 2017-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 4
5 The GNU C Library is free software; you can redistribute it and/or 5 The GNU C Library is free software; you can redistribute it and/or
diff --git a/gl/malloc/dynarray_resize.c b/gl/malloc/dynarray_resize.c
index 7323f8ee..3cd1626a 100644
--- a/gl/malloc/dynarray_resize.c
+++ b/gl/malloc/dynarray_resize.c
@@ -1,5 +1,5 @@
1/* Increase the size of a dynamic array. 1/* Increase the size of a dynamic array.
2 Copyright (C) 2017-2024 Free Software Foundation, Inc. 2 Copyright (C) 2017-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 4
5 The GNU C Library is free software; you can redistribute it and/or 5 The GNU C Library is free software; you can redistribute it and/or
diff --git a/gl/malloc/dynarray_resize_clear.c b/gl/malloc/dynarray_resize_clear.c
index aa17f740..7bfc0005 100644
--- a/gl/malloc/dynarray_resize_clear.c
+++ b/gl/malloc/dynarray_resize_clear.c
@@ -1,5 +1,5 @@
1/* Increase the size of a dynamic array and clear the new part. 1/* Increase the size of a dynamic array and clear the new part.
2 Copyright (C) 2017-2024 Free Software Foundation, Inc. 2 Copyright (C) 2017-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 4
5 The GNU C Library is free software; you can redistribute it and/or 5 The GNU C Library is free software; you can redistribute it and/or
diff --git a/gl/malloca.c b/gl/malloca.c
index e75c72df..4bce9a3d 100644
--- a/gl/malloca.c
+++ b/gl/malloca.c
@@ -1,5 +1,5 @@
1/* Safe automatic memory allocation. 1/* Safe automatic memory allocation.
2 Copyright (C) 2003, 2006-2007, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2003, 2006-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2003, 2018. 3 Written by Bruno Haible <bruno@clisp.org>, 2003, 2018.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
@@ -93,7 +93,7 @@ mmalloca (size_t n)
93 /* Out of memory. */ 93 /* Out of memory. */
94 return NULL; 94 return NULL;
95#else 95#else
96# if !MALLOC_0_IS_NONNULL 96# if !HAVE_MALLOC_0_NONNULL
97 if (n == 0) 97 if (n == 0)
98 n = 1; 98 n = 1;
99# endif 99# endif
@@ -118,7 +118,7 @@ freea (void *p)
118 char *cp = p; 118 char *cp = p;
119 small_t *sp = p; 119 small_t *sp = p;
120# if defined __CHERI_PURE_CAPABILITY__ 120# if defined __CHERI_PURE_CAPABILITY__
121 void *mem = sp[-1]; 121 void *mem = (void *) sp[-1];
122# else 122# else
123 void *mem = cp - sp[-1]; 123 void *mem = cp - sp[-1];
124# endif 124# endif
diff --git a/gl/malloca.h b/gl/malloca.h
index c5208421..f131fd5a 100644
--- a/gl/malloca.h
+++ b/gl/malloca.h
@@ -1,5 +1,5 @@
1/* Safe automatic memory allocation. 1/* Safe automatic memory allocation.
2 Copyright (C) 2003-2007, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2003-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2003. 3 Written by Bruno Haible <bruno@clisp.org>, 2003.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/math.c b/gl/math.c
index 78da4d4a..febdf82a 100644
--- a/gl/math.c
+++ b/gl/math.c
@@ -1,6 +1,6 @@
1/* Inline functions for <math.h>. 1/* Inline functions for <math.h>.
2 2
3 Copyright (C) 2012-2024 Free Software Foundation, Inc. 3 Copyright (C) 2012-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -15,8 +15,8 @@
15 You should have received a copy of the GNU Lesser General Public License 15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 17
18#define _GL_MATH_INLINE _GL_EXTERN_INLINE
18#include <config.h> 19#include <config.h>
19 20
20#define _GL_MATH_INLINE _GL_EXTERN_INLINE
21#include <math.h> 21#include <math.h>
22typedef int dummy; 22typedef int dummy;
diff --git a/gl/math.in.h b/gl/math.in.h
index 96d0da44..f4e80c53 100644
--- a/gl/math.in.h
+++ b/gl/math.in.h
@@ -1,6 +1,6 @@
1/* A GNU-like <math.h>. 1/* A GNU-like <math.h>.
2 2
3 Copyright (C) 2002-2003, 2007-2024 Free Software Foundation, Inc. 3 Copyright (C) 2002-2003, 2007-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -160,12 +160,23 @@ static void (*_gl_math_fix_itold) (long double *, int) = _Qp_itoq;
160#endif 160#endif
161 161
162 162
163/* Ensure that INFINITY is a constant expression, of type 'float'. */
164#if !defined INFINITY || (defined __FreeBSD__ && __FreeBSD__ < 8) || defined _AIX || defined __MINGW32__
165# undef INFINITY
166# if defined __GNUC__ || defined __clang__
167# define INFINITY (__builtin_inff ())
168# else
169# define INFINITY (1.0f / 0.0f)
170# endif
171#endif
172
163/* POSIX allows platforms that don't support NAN. But all major 173/* POSIX allows platforms that don't support NAN. But all major
164 machines in the past 15 years have supported something close to 174 machines in the past 15 years have supported something close to
165 IEEE NaN, so we define this unconditionally. We also must define 175 IEEE NaN, so we define this unconditionally. We also must define
166 it on platforms like Solaris 10, where NAN is present but defined 176 it on platforms like Solaris 10, where NAN is present but defined
167 as a function pointer rather than a floating point constant. */ 177 as a function pointer rather than a floating point constant.
168#if !defined NAN || @REPLACE_NAN@ 178 Also ensure that it is a constant expression, of type 'float'. */
179#if !defined NAN || @REPLACE_NAN@ || (defined __FreeBSD__ && __FreeBSD__ < 8) || defined _AIX || defined __MINGW32__
169# if !GNULIB_defined_NAN 180# if !GNULIB_defined_NAN
170# undef NAN 181# undef NAN
171 /* The Compaq (ex-DEC) C 6.4 compiler and the Microsoft MSVC 9 compiler 182 /* The Compaq (ex-DEC) C 6.4 compiler and the Microsoft MSVC 9 compiler
@@ -178,6 +189,8 @@ _NaN ()
178 return zero / zero; 189 return zero / zero;
179} 190}
180# define NAN (_NaN()) 191# define NAN (_NaN())
192# elif defined __GNUC__ || defined __clang__
193# define NAN (__builtin_nanf (""))
181# else 194# else
182# define NAN (0.0f / 0.0f) 195# define NAN (0.0f / 0.0f)
183# endif 196# endif
@@ -197,46 +210,46 @@ _NaN ()
197#endif 210#endif
198 211
199/* HUGE_VALF is a 'float' Infinity. */ 212/* HUGE_VALF is a 'float' Infinity. */
200#ifndef HUGE_VALF 213#if !defined HUGE_VALF || (defined __FreeBSD__ && __FreeBSD__ < 6)
214# undef HUGE_VALF
201# if defined _MSC_VER 215# if defined _MSC_VER
202/* The Microsoft MSVC 9 compiler chokes on the expression 1.0f / 0.0f. */ 216/* The Microsoft MSVC 9 compiler chokes on the expression 1.0f / 0.0f. */
203# define HUGE_VALF (1e25f * 1e25f) 217# define HUGE_VALF (1e25f * 1e25f)
218# elif defined __GNUC__ || defined __clang__
219# define HUGE_VALF (__builtin_inff ())
204# else 220# else
205# define HUGE_VALF (1.0f / 0.0f) 221# define HUGE_VALF (1.0f / 0.0f)
206# endif 222# endif
207#endif 223#endif
208 224
209/* HUGE_VAL is a 'double' Infinity. */ 225/* HUGE_VAL is a 'double' Infinity. */
210#ifndef HUGE_VAL 226#if !defined HUGE_VAL || (defined __FreeBSD__ && __FreeBSD__ < 6) || defined _AIX
227# undef HUGE_VAL
211# if defined _MSC_VER 228# if defined _MSC_VER
212/* The Microsoft MSVC 9 compiler chokes on the expression 1.0 / 0.0. */ 229/* The Microsoft MSVC 9 compiler chokes on the expression 1.0 / 0.0. */
213# define HUGE_VAL (1e250 * 1e250) 230# define HUGE_VAL (1e250 * 1e250)
231# elif defined __GNUC__ || defined __clang__
232# define HUGE_VAL (__builtin_inf ())
214# else 233# else
215# define HUGE_VAL (1.0 / 0.0) 234# define HUGE_VAL (1.0 / 0.0)
216# endif 235# endif
217#endif 236#endif
218 237
219/* HUGE_VALL is a 'long double' Infinity. */ 238/* HUGE_VALL is a 'long double' Infinity. */
220#ifndef HUGE_VALL 239#if !defined HUGE_VALL || (defined __FreeBSD__ && __FreeBSD__ < 6) || defined _AIX
240# undef HUGE_VALL
221# if defined _MSC_VER 241# if defined _MSC_VER
222/* The Microsoft MSVC 9 compiler chokes on the expression 1.0L / 0.0L. */ 242/* The Microsoft MSVC 9 compiler chokes on the expression 1.0L / 0.0L. */
223# define HUGE_VALL (1e250L * 1e250L) 243# define HUGE_VALL (1e250L * 1e250L)
244# elif defined __GNUC__ || defined __clang__
245# define HUGE_VALL (__builtin_infl ())
224# else 246# else
225# define HUGE_VALL (1.0L / 0.0L) 247# define HUGE_VALL (1.0L / 0.0L)
226# endif 248# endif
227#endif 249#endif
228 250
229 251
230#if defined FP_ILOGB0 && defined FP_ILOGBNAN 252#if !(defined FP_ILOGB0 && defined FP_ILOGBNAN)
231 /* Ensure FP_ILOGB0 and FP_ILOGBNAN are correct. */
232# if defined __HAIKU__
233 /* Haiku: match what ilogb() does */
234# undef FP_ILOGB0
235# undef FP_ILOGBNAN
236# define FP_ILOGB0 (- 2147483647 - 1) /* INT_MIN */
237# define FP_ILOGBNAN (- 2147483647 - 1) /* INT_MIN */
238# endif
239#else
240 /* Ensure FP_ILOGB0 and FP_ILOGBNAN are defined. */ 253 /* Ensure FP_ILOGB0 and FP_ILOGBNAN are defined. */
241# if defined __NetBSD__ || defined __sgi 254# if defined __NetBSD__ || defined __sgi
242 /* NetBSD, IRIX 6.5: match what ilogb() does */ 255 /* NetBSD, IRIX 6.5: match what ilogb() does */
@@ -264,12 +277,12 @@ _NaN ()
264# undef acosf 277# undef acosf
265# define acosf rpl_acosf 278# define acosf rpl_acosf
266# endif 279# endif
267_GL_FUNCDECL_RPL (acosf, float, (float x)); 280_GL_FUNCDECL_RPL (acosf, float, (float x), );
268_GL_CXXALIAS_RPL (acosf, float, (float x)); 281_GL_CXXALIAS_RPL (acosf, float, (float x));
269# else 282# else
270# if !@HAVE_ACOSF@ 283# if !@HAVE_ACOSF@
271# undef acosf 284# undef acosf
272_GL_FUNCDECL_SYS (acosf, float, (float x)); 285_GL_FUNCDECL_SYS (acosf, float, (float x), );
273# endif 286# endif
274_GL_CXXALIAS_SYS (acosf, float, (float x)); 287_GL_CXXALIAS_SYS (acosf, float, (float x));
275# endif 288# endif
@@ -285,7 +298,7 @@ _GL_WARN_ON_USE (acosf, "acosf is unportable - "
285#if @GNULIB_ACOSL@ 298#if @GNULIB_ACOSL@
286# if !@HAVE_ACOSL@ || !@HAVE_DECL_ACOSL@ 299# if !@HAVE_ACOSL@ || !@HAVE_DECL_ACOSL@
287# undef acosl 300# undef acosl
288_GL_FUNCDECL_SYS (acosl, long double, (long double x)); 301_GL_FUNCDECL_SYS (acosl, long double, (long double x), );
289# endif 302# endif
290_GL_CXXALIAS_SYS (acosl, long double, (long double x)); 303_GL_CXXALIAS_SYS (acosl, long double, (long double x));
291# if __GLIBC__ >= 2 304# if __GLIBC__ >= 2
@@ -306,12 +319,12 @@ _GL_WARN_ON_USE (acosl, "acosl is unportable - "
306# undef asinf 319# undef asinf
307# define asinf rpl_asinf 320# define asinf rpl_asinf
308# endif 321# endif
309_GL_FUNCDECL_RPL (asinf, float, (float x)); 322_GL_FUNCDECL_RPL (asinf, float, (float x), );
310_GL_CXXALIAS_RPL (asinf, float, (float x)); 323_GL_CXXALIAS_RPL (asinf, float, (float x));
311# else 324# else
312# if !@HAVE_ASINF@ 325# if !@HAVE_ASINF@
313# undef asinf 326# undef asinf
314_GL_FUNCDECL_SYS (asinf, float, (float x)); 327_GL_FUNCDECL_SYS (asinf, float, (float x), );
315# endif 328# endif
316_GL_CXXALIAS_SYS (asinf, float, (float x)); 329_GL_CXXALIAS_SYS (asinf, float, (float x));
317# endif 330# endif
@@ -327,7 +340,7 @@ _GL_WARN_ON_USE (asinf, "asinf is unportable - "
327#if @GNULIB_ASINL@ 340#if @GNULIB_ASINL@
328# if !@HAVE_ASINL@ || !@HAVE_DECL_ASINL@ 341# if !@HAVE_ASINL@ || !@HAVE_DECL_ASINL@
329# undef asinl 342# undef asinl
330_GL_FUNCDECL_SYS (asinl, long double, (long double x)); 343_GL_FUNCDECL_SYS (asinl, long double, (long double x), );
331# endif 344# endif
332_GL_CXXALIAS_SYS (asinl, long double, (long double x)); 345_GL_CXXALIAS_SYS (asinl, long double, (long double x));
333# if __GLIBC__ >= 2 346# if __GLIBC__ >= 2
@@ -348,12 +361,12 @@ _GL_WARN_ON_USE (asinl, "asinl is unportable - "
348# undef atanf 361# undef atanf
349# define atanf rpl_atanf 362# define atanf rpl_atanf
350# endif 363# endif
351_GL_FUNCDECL_RPL (atanf, float, (float x)); 364_GL_FUNCDECL_RPL (atanf, float, (float x), );
352_GL_CXXALIAS_RPL (atanf, float, (float x)); 365_GL_CXXALIAS_RPL (atanf, float, (float x));
353# else 366# else
354# if !@HAVE_ATANF@ 367# if !@HAVE_ATANF@
355# undef atanf 368# undef atanf
356_GL_FUNCDECL_SYS (atanf, float, (float x)); 369_GL_FUNCDECL_SYS (atanf, float, (float x), );
357# endif 370# endif
358_GL_CXXALIAS_SYS (atanf, float, (float x)); 371_GL_CXXALIAS_SYS (atanf, float, (float x));
359# endif 372# endif
@@ -369,7 +382,7 @@ _GL_WARN_ON_USE (atanf, "atanf is unportable - "
369#if @GNULIB_ATANL@ 382#if @GNULIB_ATANL@
370# if !@HAVE_ATANL@ || !@HAVE_DECL_ATANL@ 383# if !@HAVE_ATANL@ || !@HAVE_DECL_ATANL@
371# undef atanl 384# undef atanl
372_GL_FUNCDECL_SYS (atanl, long double, (long double x)); 385_GL_FUNCDECL_SYS (atanl, long double, (long double x), );
373# endif 386# endif
374_GL_CXXALIAS_SYS (atanl, long double, (long double x)); 387_GL_CXXALIAS_SYS (atanl, long double, (long double x));
375# if __GLIBC__ >= 2 388# if __GLIBC__ >= 2
@@ -390,12 +403,12 @@ _GL_WARN_ON_USE (atanl, "atanl is unportable - "
390# undef atan2f 403# undef atan2f
391# define atan2f rpl_atan2f 404# define atan2f rpl_atan2f
392# endif 405# endif
393_GL_FUNCDECL_RPL (atan2f, float, (float y, float x)); 406_GL_FUNCDECL_RPL (atan2f, float, (float y, float x), );
394_GL_CXXALIAS_RPL (atan2f, float, (float y, float x)); 407_GL_CXXALIAS_RPL (atan2f, float, (float y, float x));
395# else 408# else
396# if !@HAVE_ATAN2F@ 409# if !@HAVE_ATAN2F@
397# undef atan2f 410# undef atan2f
398_GL_FUNCDECL_SYS (atan2f, float, (float y, float x)); 411_GL_FUNCDECL_SYS (atan2f, float, (float y, float x), );
399# endif 412# endif
400_GL_CXXALIAS_SYS (atan2f, float, (float y, float x)); 413_GL_CXXALIAS_SYS (atan2f, float, (float y, float x));
401# endif 414# endif
@@ -415,11 +428,11 @@ _GL_WARN_ON_USE (atan2f, "atan2f is unportable - "
415# undef cbrtf 428# undef cbrtf
416# define cbrtf rpl_cbrtf 429# define cbrtf rpl_cbrtf
417# endif 430# endif
418_GL_FUNCDECL_RPL (cbrtf, float, (float x)); 431_GL_FUNCDECL_RPL (cbrtf, float, (float x), );
419_GL_CXXALIAS_RPL (cbrtf, float, (float x)); 432_GL_CXXALIAS_RPL (cbrtf, float, (float x));
420# else 433# else
421# if !@HAVE_DECL_CBRTF@ 434# if !@HAVE_DECL_CBRTF@
422_GL_FUNCDECL_SYS (cbrtf, float, (float x)); 435_GL_FUNCDECL_SYS (cbrtf, float, (float x), );
423# endif 436# endif
424_GL_CXXALIAS_SYS (cbrtf, float, (float x)); 437_GL_CXXALIAS_SYS (cbrtf, float, (float x));
425# endif 438# endif
@@ -434,7 +447,7 @@ _GL_WARN_ON_USE (cbrtf, "cbrtf is unportable - "
434 447
435#if @GNULIB_CBRT@ 448#if @GNULIB_CBRT@
436# if !@HAVE_CBRT@ 449# if !@HAVE_CBRT@
437_GL_FUNCDECL_SYS (cbrt, double, (double x)); 450_GL_FUNCDECL_SYS (cbrt, double, (double x), );
438# endif 451# endif
439_GL_CXXALIAS_SYS (cbrt, double, (double x)); 452_GL_CXXALIAS_SYS (cbrt, double, (double x));
440# if __GLIBC__ >= 2 453# if __GLIBC__ >= 2
@@ -454,11 +467,11 @@ _GL_WARN_ON_USE (cbrt, "cbrt is unportable - "
454# undef cbrtl 467# undef cbrtl
455# define cbrtl rpl_cbrtl 468# define cbrtl rpl_cbrtl
456# endif 469# endif
457_GL_FUNCDECL_RPL (cbrtl, long double, (long double x)); 470_GL_FUNCDECL_RPL (cbrtl, long double, (long double x), );
458_GL_CXXALIAS_RPL (cbrtl, long double, (long double x)); 471_GL_CXXALIAS_RPL (cbrtl, long double, (long double x));
459# else 472# else
460# if !@HAVE_DECL_CBRTL@ 473# if !@HAVE_DECL_CBRTL@
461_GL_FUNCDECL_SYS (cbrtl, long double, (long double x)); 474_GL_FUNCDECL_SYS (cbrtl, long double, (long double x), );
462# endif 475# endif
463_GL_CXXALIAS_SYS (cbrtl, long double, (long double x)); 476_GL_CXXALIAS_SYS (cbrtl, long double, (long double x));
464# endif 477# endif
@@ -480,12 +493,12 @@ _GL_WARN_ON_USE (cbrtl, "cbrtl is unportable - "
480# undef ceilf 493# undef ceilf
481# define ceilf rpl_ceilf 494# define ceilf rpl_ceilf
482# endif 495# endif
483_GL_FUNCDECL_RPL (ceilf, float, (float x)); 496_GL_FUNCDECL_RPL (ceilf, float, (float x), );
484_GL_CXXALIAS_RPL (ceilf, float, (float x)); 497_GL_CXXALIAS_RPL (ceilf, float, (float x));
485# else 498# else
486# if !@HAVE_DECL_CEILF@ 499# if !@HAVE_DECL_CEILF@
487# undef ceilf 500# undef ceilf
488_GL_FUNCDECL_SYS (ceilf, float, (float x)); 501_GL_FUNCDECL_SYS (ceilf, float, (float x), );
489# endif 502# endif
490_GL_CXXALIAS_SYS (ceilf, float, (float x)); 503_GL_CXXALIAS_SYS (ceilf, float, (float x));
491# endif 504# endif
@@ -504,7 +517,7 @@ _GL_WARN_ON_USE (ceilf, "ceilf is unportable - "
504# undef ceil 517# undef ceil
505# define ceil rpl_ceil 518# define ceil rpl_ceil
506# endif 519# endif
507_GL_FUNCDECL_RPL (ceil, double, (double x)); 520_GL_FUNCDECL_RPL (ceil, double, (double x), );
508_GL_CXXALIAS_RPL (ceil, double, (double x)); 521_GL_CXXALIAS_RPL (ceil, double, (double x));
509# else 522# else
510_GL_CXXALIAS_SYS (ceil, double, (double x)); 523_GL_CXXALIAS_SYS (ceil, double, (double x));
@@ -520,12 +533,12 @@ _GL_CXXALIASWARN1 (ceil, double, (double x));
520# undef ceill 533# undef ceill
521# define ceill rpl_ceill 534# define ceill rpl_ceill
522# endif 535# endif
523_GL_FUNCDECL_RPL (ceill, long double, (long double x)); 536_GL_FUNCDECL_RPL (ceill, long double, (long double x), );
524_GL_CXXALIAS_RPL (ceill, long double, (long double x)); 537_GL_CXXALIAS_RPL (ceill, long double, (long double x));
525# else 538# else
526# if !@HAVE_DECL_CEILL@ 539# if !@HAVE_DECL_CEILL@
527# undef ceill 540# undef ceill
528_GL_FUNCDECL_SYS (ceill, long double, (long double x)); 541_GL_FUNCDECL_SYS (ceill, long double, (long double x), );
529# endif 542# endif
530_GL_CXXALIAS_SYS (ceill, long double, (long double x)); 543_GL_CXXALIAS_SYS (ceill, long double, (long double x));
531# endif 544# endif
@@ -544,7 +557,7 @@ _GL_WARN_ON_USE (ceill, "ceill is unportable - "
544#if @GNULIB_COPYSIGNF@ 557#if @GNULIB_COPYSIGNF@
545# if !@HAVE_DECL_COPYSIGNF@ 558# if !@HAVE_DECL_COPYSIGNF@
546# undef copysignf 559# undef copysignf
547_GL_FUNCDECL_SYS (copysignf, float, (float x, float y)); 560_GL_FUNCDECL_SYS (copysignf, float, (float x, float y), );
548# endif 561# endif
549_GL_CXXALIAS_SYS (copysignf, float, (float x, float y)); 562_GL_CXXALIAS_SYS (copysignf, float, (float x, float y));
550_GL_CXXALIASWARN (copysignf); 563_GL_CXXALIASWARN (copysignf);
@@ -558,7 +571,7 @@ _GL_WARN_ON_USE (copysignf, "copysignf is unportable - "
558 571
559#if @GNULIB_COPYSIGN@ 572#if @GNULIB_COPYSIGN@
560# if !@HAVE_COPYSIGN@ 573# if !@HAVE_COPYSIGN@
561_GL_FUNCDECL_SYS (copysign, double, (double x, double y)); 574_GL_FUNCDECL_SYS (copysign, double, (double x, double y), );
562# endif 575# endif
563_GL_CXXALIAS_SYS (copysign, double, (double x, double y)); 576_GL_CXXALIAS_SYS (copysign, double, (double x, double y));
564# if __GLIBC__ >= 2 577# if __GLIBC__ >= 2
@@ -574,7 +587,7 @@ _GL_WARN_ON_USE (copysign, "copysign is unportable - "
574 587
575#if @GNULIB_COPYSIGNL@ 588#if @GNULIB_COPYSIGNL@
576# if !@HAVE_COPYSIGNL@ 589# if !@HAVE_COPYSIGNL@
577_GL_FUNCDECL_SYS (copysignl, long double, (long double x, long double y)); 590_GL_FUNCDECL_SYS (copysignl, long double, (long double x, long double y), );
578# endif 591# endif
579_GL_CXXALIAS_SYS (copysignl, long double, (long double x, long double y)); 592_GL_CXXALIAS_SYS (copysignl, long double, (long double x, long double y));
580# if __GLIBC__ >= 2 593# if __GLIBC__ >= 2
@@ -595,12 +608,12 @@ _GL_WARN_ON_USE (copysign, "copysignl is unportable - "
595# undef cosf 608# undef cosf
596# define cosf rpl_cosf 609# define cosf rpl_cosf
597# endif 610# endif
598_GL_FUNCDECL_RPL (cosf, float, (float x)); 611_GL_FUNCDECL_RPL (cosf, float, (float x), );
599_GL_CXXALIAS_RPL (cosf, float, (float x)); 612_GL_CXXALIAS_RPL (cosf, float, (float x));
600# else 613# else
601# if !@HAVE_COSF@ 614# if !@HAVE_COSF@
602# undef cosf 615# undef cosf
603_GL_FUNCDECL_SYS (cosf, float, (float x)); 616_GL_FUNCDECL_SYS (cosf, float, (float x), );
604# endif 617# endif
605_GL_CXXALIAS_SYS (cosf, float, (float x)); 618_GL_CXXALIAS_SYS (cosf, float, (float x));
606# endif 619# endif
@@ -616,7 +629,7 @@ _GL_WARN_ON_USE (cosf, "cosf is unportable - "
616#if @GNULIB_COSL@ 629#if @GNULIB_COSL@
617# if !@HAVE_COSL@ || !@HAVE_DECL_COSL@ 630# if !@HAVE_COSL@ || !@HAVE_DECL_COSL@
618# undef cosl 631# undef cosl
619_GL_FUNCDECL_SYS (cosl, long double, (long double x)); 632_GL_FUNCDECL_SYS (cosl, long double, (long double x), );
620# endif 633# endif
621_GL_CXXALIAS_SYS (cosl, long double, (long double x)); 634_GL_CXXALIAS_SYS (cosl, long double, (long double x));
622# if __GLIBC__ >= 2 635# if __GLIBC__ >= 2
@@ -637,12 +650,12 @@ _GL_WARN_ON_USE (cosl, "cosl is unportable - "
637# undef coshf 650# undef coshf
638# define coshf rpl_coshf 651# define coshf rpl_coshf
639# endif 652# endif
640_GL_FUNCDECL_RPL (coshf, float, (float x)); 653_GL_FUNCDECL_RPL (coshf, float, (float x), );
641_GL_CXXALIAS_RPL (coshf, float, (float x)); 654_GL_CXXALIAS_RPL (coshf, float, (float x));
642# else 655# else
643# if !@HAVE_COSHF@ 656# if !@HAVE_COSHF@
644# undef coshf 657# undef coshf
645_GL_FUNCDECL_SYS (coshf, float, (float x)); 658_GL_FUNCDECL_SYS (coshf, float, (float x), );
646# endif 659# endif
647_GL_CXXALIAS_SYS (coshf, float, (float x)); 660_GL_CXXALIAS_SYS (coshf, float, (float x));
648# endif 661# endif
@@ -662,12 +675,12 @@ _GL_WARN_ON_USE (coshf, "coshf is unportable - "
662# undef expf 675# undef expf
663# define expf rpl_expf 676# define expf rpl_expf
664# endif 677# endif
665_GL_FUNCDECL_RPL (expf, float, (float x)); 678_GL_FUNCDECL_RPL (expf, float, (float x), );
666_GL_CXXALIAS_RPL (expf, float, (float x)); 679_GL_CXXALIAS_RPL (expf, float, (float x));
667# else 680# else
668# if !@HAVE_EXPF@ 681# if !@HAVE_EXPF@
669# undef expf 682# undef expf
670_GL_FUNCDECL_SYS (expf, float, (float x)); 683_GL_FUNCDECL_SYS (expf, float, (float x), );
671# endif 684# endif
672_GL_CXXALIAS_SYS (expf, float, (float x)); 685_GL_CXXALIAS_SYS (expf, float, (float x));
673# endif 686# endif
@@ -686,12 +699,12 @@ _GL_WARN_ON_USE (expf, "expf is unportable - "
686# undef expl 699# undef expl
687# define expl rpl_expl 700# define expl rpl_expl
688# endif 701# endif
689_GL_FUNCDECL_RPL (expl, long double, (long double x)); 702_GL_FUNCDECL_RPL (expl, long double, (long double x), );
690_GL_CXXALIAS_RPL (expl, long double, (long double x)); 703_GL_CXXALIAS_RPL (expl, long double, (long double x));
691# else 704# else
692# if !@HAVE_EXPL@ || !@HAVE_DECL_EXPL@ 705# if !@HAVE_EXPL@ || !@HAVE_DECL_EXPL@
693# undef expl 706# undef expl
694_GL_FUNCDECL_SYS (expl, long double, (long double x)); 707_GL_FUNCDECL_SYS (expl, long double, (long double x), );
695# endif 708# endif
696_GL_CXXALIAS_SYS (expl, long double, (long double x)); 709_GL_CXXALIAS_SYS (expl, long double, (long double x));
697# endif 710# endif
@@ -709,7 +722,7 @@ _GL_WARN_ON_USE (expl, "expl is unportable - "
709 722
710#if @GNULIB_EXP2F@ 723#if @GNULIB_EXP2F@
711# if !@HAVE_DECL_EXP2F@ 724# if !@HAVE_DECL_EXP2F@
712_GL_FUNCDECL_SYS (exp2f, float, (float x)); 725_GL_FUNCDECL_SYS (exp2f, float, (float x), );
713# endif 726# endif
714_GL_CXXALIAS_SYS (exp2f, float, (float x)); 727_GL_CXXALIAS_SYS (exp2f, float, (float x));
715_GL_CXXALIASWARN (exp2f); 728_GL_CXXALIASWARN (exp2f);
@@ -727,11 +740,11 @@ _GL_WARN_ON_USE (exp2f, "exp2f is unportable - "
727# undef exp2 740# undef exp2
728# define exp2 rpl_exp2 741# define exp2 rpl_exp2
729# endif 742# endif
730_GL_FUNCDECL_RPL (exp2, double, (double x)); 743_GL_FUNCDECL_RPL (exp2, double, (double x), );
731_GL_CXXALIAS_RPL (exp2, double, (double x)); 744_GL_CXXALIAS_RPL (exp2, double, (double x));
732# else 745# else
733# if !@HAVE_DECL_EXP2@ 746# if !@HAVE_DECL_EXP2@
734_GL_FUNCDECL_SYS (exp2, double, (double x)); 747_GL_FUNCDECL_SYS (exp2, double, (double x), );
735# endif 748# endif
736_GL_CXXALIAS_SYS (exp2, double, (double x)); 749_GL_CXXALIAS_SYS (exp2, double, (double x));
737# endif 750# endif
@@ -752,12 +765,12 @@ _GL_WARN_ON_USE (exp2, "exp2 is unportable - "
752# undef exp2l 765# undef exp2l
753# define exp2l rpl_exp2l 766# define exp2l rpl_exp2l
754# endif 767# endif
755_GL_FUNCDECL_RPL (exp2l, long double, (long double x)); 768_GL_FUNCDECL_RPL (exp2l, long double, (long double x), );
756_GL_CXXALIAS_RPL (exp2l, long double, (long double x)); 769_GL_CXXALIAS_RPL (exp2l, long double, (long double x));
757# else 770# else
758# if !@HAVE_DECL_EXP2L@ 771# if !@HAVE_DECL_EXP2L@
759# undef exp2l 772# undef exp2l
760_GL_FUNCDECL_SYS (exp2l, long double, (long double x)); 773_GL_FUNCDECL_SYS (exp2l, long double, (long double x), );
761# endif 774# endif
762_GL_CXXALIAS_SYS (exp2l, long double, (long double x)); 775_GL_CXXALIAS_SYS (exp2l, long double, (long double x));
763# endif 776# endif
@@ -779,11 +792,11 @@ _GL_WARN_ON_USE (exp2l, "exp2l is unportable - "
779# undef expm1f 792# undef expm1f
780# define expm1f rpl_expm1f 793# define expm1f rpl_expm1f
781# endif 794# endif
782_GL_FUNCDECL_RPL (expm1f, float, (float x)); 795_GL_FUNCDECL_RPL (expm1f, float, (float x), );
783_GL_CXXALIAS_RPL (expm1f, float, (float x)); 796_GL_CXXALIAS_RPL (expm1f, float, (float x));
784# else 797# else
785# if !@HAVE_EXPM1F@ 798# if !@HAVE_EXPM1F@
786_GL_FUNCDECL_SYS (expm1f, float, (float x)); 799_GL_FUNCDECL_SYS (expm1f, float, (float x), );
787# endif 800# endif
788_GL_CXXALIAS_SYS (expm1f, float, (float x)); 801_GL_CXXALIAS_SYS (expm1f, float, (float x));
789# endif 802# endif
@@ -802,11 +815,11 @@ _GL_WARN_ON_USE (expm1f, "expm1f is unportable - "
802# undef expm1 815# undef expm1
803# define expm1 rpl_expm1 816# define expm1 rpl_expm1
804# endif 817# endif
805_GL_FUNCDECL_RPL (expm1, double, (double x)); 818_GL_FUNCDECL_RPL (expm1, double, (double x), );
806_GL_CXXALIAS_RPL (expm1, double, (double x)); 819_GL_CXXALIAS_RPL (expm1, double, (double x));
807# else 820# else
808# if !@HAVE_EXPM1@ 821# if !@HAVE_EXPM1@
809_GL_FUNCDECL_SYS (expm1, double, (double x)); 822_GL_FUNCDECL_SYS (expm1, double, (double x), );
810# endif 823# endif
811_GL_CXXALIAS_SYS (expm1, double, (double x)); 824_GL_CXXALIAS_SYS (expm1, double, (double x));
812# endif 825# endif
@@ -827,13 +840,13 @@ _GL_WARN_ON_USE (expm1, "expm1 is unportable - "
827# undef expm1l 840# undef expm1l
828# define expm1l rpl_expm1l 841# define expm1l rpl_expm1l
829# endif 842# endif
830_GL_FUNCDECL_RPL (expm1l, long double, (long double x)); 843_GL_FUNCDECL_RPL (expm1l, long double, (long double x), );
831_GL_CXXALIAS_RPL (expm1l, long double, (long double x)); 844_GL_CXXALIAS_RPL (expm1l, long double, (long double x));
832# else 845# else
833# if !@HAVE_DECL_EXPM1L@ 846# if !@HAVE_DECL_EXPM1L@
834# undef expm1l 847# undef expm1l
835# if !(defined __cplusplus && defined _AIX) 848# if !(defined __cplusplus && defined _AIX)
836_GL_FUNCDECL_SYS (expm1l, long double, (long double x)); 849_GL_FUNCDECL_SYS (expm1l, long double, (long double x), );
837# endif 850# endif
838# endif 851# endif
839_GL_CXXALIAS_SYS (expm1l, long double, (long double x)); 852_GL_CXXALIAS_SYS (expm1l, long double, (long double x));
@@ -853,7 +866,7 @@ _GL_WARN_ON_USE (expm1l, "expm1l is unportable - "
853#if @GNULIB_FABSF@ 866#if @GNULIB_FABSF@
854# if !@HAVE_FABSF@ 867# if !@HAVE_FABSF@
855# undef fabsf 868# undef fabsf
856_GL_FUNCDECL_SYS (fabsf, float, (float x)); 869_GL_FUNCDECL_SYS (fabsf, float, (float x), );
857# endif 870# endif
858_GL_CXXALIAS_SYS (fabsf, float, (float x)); 871_GL_CXXALIAS_SYS (fabsf, float, (float x));
859# if __GLIBC__ >= 2 872# if __GLIBC__ >= 2
@@ -873,12 +886,12 @@ _GL_WARN_ON_USE (fabsf, "fabsf is unportable - "
873# undef fabsl 886# undef fabsl
874# define fabsl rpl_fabsl 887# define fabsl rpl_fabsl
875# endif 888# endif
876_GL_FUNCDECL_RPL (fabsl, long double, (long double x)); 889_GL_FUNCDECL_RPL (fabsl, long double, (long double x), );
877_GL_CXXALIAS_RPL (fabsl, long double, (long double x)); 890_GL_CXXALIAS_RPL (fabsl, long double, (long double x));
878# else 891# else
879# if !@HAVE_FABSL@ 892# if !@HAVE_FABSL@
880# undef fabsl 893# undef fabsl
881_GL_FUNCDECL_SYS (fabsl, long double, (long double x)); 894_GL_FUNCDECL_SYS (fabsl, long double, (long double x), );
882# endif 895# endif
883_GL_CXXALIAS_SYS (fabsl, long double, (long double x)); 896_GL_CXXALIAS_SYS (fabsl, long double, (long double x));
884# endif 897# endif
@@ -900,12 +913,12 @@ _GL_WARN_ON_USE (fabsl, "fabsl is unportable - "
900# undef floorf 913# undef floorf
901# define floorf rpl_floorf 914# define floorf rpl_floorf
902# endif 915# endif
903_GL_FUNCDECL_RPL (floorf, float, (float x)); 916_GL_FUNCDECL_RPL (floorf, float, (float x), );
904_GL_CXXALIAS_RPL (floorf, float, (float x)); 917_GL_CXXALIAS_RPL (floorf, float, (float x));
905# else 918# else
906# if !@HAVE_DECL_FLOORF@ 919# if !@HAVE_DECL_FLOORF@
907# undef floorf 920# undef floorf
908_GL_FUNCDECL_SYS (floorf, float, (float x)); 921_GL_FUNCDECL_SYS (floorf, float, (float x), );
909# endif 922# endif
910_GL_CXXALIAS_SYS (floorf, float, (float x)); 923_GL_CXXALIAS_SYS (floorf, float, (float x));
911# endif 924# endif
@@ -924,7 +937,7 @@ _GL_WARN_ON_USE (floorf, "floorf is unportable - "
924# undef floor 937# undef floor
925# define floor rpl_floor 938# define floor rpl_floor
926# endif 939# endif
927_GL_FUNCDECL_RPL (floor, double, (double x)); 940_GL_FUNCDECL_RPL (floor, double, (double x), );
928_GL_CXXALIAS_RPL (floor, double, (double x)); 941_GL_CXXALIAS_RPL (floor, double, (double x));
929# else 942# else
930_GL_CXXALIAS_SYS (floor, double, (double x)); 943_GL_CXXALIAS_SYS (floor, double, (double x));
@@ -940,12 +953,12 @@ _GL_CXXALIASWARN1 (floor, double, (double x));
940# undef floorl 953# undef floorl
941# define floorl rpl_floorl 954# define floorl rpl_floorl
942# endif 955# endif
943_GL_FUNCDECL_RPL (floorl, long double, (long double x)); 956_GL_FUNCDECL_RPL (floorl, long double, (long double x), );
944_GL_CXXALIAS_RPL (floorl, long double, (long double x)); 957_GL_CXXALIAS_RPL (floorl, long double, (long double x));
945# else 958# else
946# if !@HAVE_DECL_FLOORL@ 959# if !@HAVE_DECL_FLOORL@
947# undef floorl 960# undef floorl
948_GL_FUNCDECL_SYS (floorl, long double, (long double x)); 961_GL_FUNCDECL_SYS (floorl, long double, (long double x), );
949# endif 962# endif
950_GL_CXXALIAS_SYS (floorl, long double, (long double x)); 963_GL_CXXALIAS_SYS (floorl, long double, (long double x));
951# endif 964# endif
@@ -967,12 +980,12 @@ _GL_WARN_ON_USE (floorl, "floorl is unportable - "
967# undef fmaf 980# undef fmaf
968# define fmaf rpl_fmaf 981# define fmaf rpl_fmaf
969# endif 982# endif
970_GL_FUNCDECL_RPL (fmaf, float, (float x, float y, float z)); 983_GL_FUNCDECL_RPL (fmaf, float, (float x, float y, float z), );
971_GL_CXXALIAS_RPL (fmaf, float, (float x, float y, float z)); 984_GL_CXXALIAS_RPL (fmaf, float, (float x, float y, float z));
972# else 985# else
973# if !@HAVE_FMAF@ 986# if !@HAVE_FMAF@
974# undef fmaf 987# undef fmaf
975_GL_FUNCDECL_SYS (fmaf, float, (float x, float y, float z)); 988_GL_FUNCDECL_SYS (fmaf, float, (float x, float y, float z), );
976# endif 989# endif
977_GL_CXXALIAS_SYS (fmaf, float, (float x, float y, float z)); 990_GL_CXXALIAS_SYS (fmaf, float, (float x, float y, float z));
978# endif 991# endif
@@ -991,12 +1004,12 @@ _GL_WARN_ON_USE (fmaf, "fmaf is unportable - "
991# undef fma 1004# undef fma
992# define fma rpl_fma 1005# define fma rpl_fma
993# endif 1006# endif
994_GL_FUNCDECL_RPL (fma, double, (double x, double y, double z)); 1007_GL_FUNCDECL_RPL (fma, double, (double x, double y, double z), );
995_GL_CXXALIAS_RPL (fma, double, (double x, double y, double z)); 1008_GL_CXXALIAS_RPL (fma, double, (double x, double y, double z));
996# else 1009# else
997# if !@HAVE_FMA@ 1010# if !@HAVE_FMA@
998# undef fma 1011# undef fma
999_GL_FUNCDECL_SYS (fma, double, (double x, double y, double z)); 1012_GL_FUNCDECL_SYS (fma, double, (double x, double y, double z), );
1000# endif 1013# endif
1001_GL_CXXALIAS_SYS (fma, double, (double x, double y, double z)); 1014_GL_CXXALIAS_SYS (fma, double, (double x, double y, double z));
1002# endif 1015# endif
@@ -1018,7 +1031,7 @@ _GL_WARN_ON_USE (fma, "fma is unportable - "
1018# define fmal rpl_fmal 1031# define fmal rpl_fmal
1019# endif 1032# endif
1020_GL_FUNCDECL_RPL (fmal, long double, 1033_GL_FUNCDECL_RPL (fmal, long double,
1021 (long double x, long double y, long double z)); 1034 (long double x, long double y, long double z), );
1022_GL_CXXALIAS_RPL (fmal, long double, 1035_GL_CXXALIAS_RPL (fmal, long double,
1023 (long double x, long double y, long double z)); 1036 (long double x, long double y, long double z));
1024# else 1037# else
@@ -1026,7 +1039,7 @@ _GL_CXXALIAS_RPL (fmal, long double,
1026# undef fmal 1039# undef fmal
1027# if !(defined __cplusplus && defined _AIX) 1040# if !(defined __cplusplus && defined _AIX)
1028_GL_FUNCDECL_SYS (fmal, long double, 1041_GL_FUNCDECL_SYS (fmal, long double,
1029 (long double x, long double y, long double z)); 1042 (long double x, long double y, long double z), );
1030# endif 1043# endif
1031# endif 1044# endif
1032_GL_CXXALIAS_SYS (fmal, long double, 1045_GL_CXXALIAS_SYS (fmal, long double,
@@ -1050,12 +1063,12 @@ _GL_WARN_ON_USE (fmal, "fmal is unportable - "
1050# undef fmodf 1063# undef fmodf
1051# define fmodf rpl_fmodf 1064# define fmodf rpl_fmodf
1052# endif 1065# endif
1053_GL_FUNCDECL_RPL (fmodf, float, (float x, float y)); 1066_GL_FUNCDECL_RPL (fmodf, float, (float x, float y), );
1054_GL_CXXALIAS_RPL (fmodf, float, (float x, float y)); 1067_GL_CXXALIAS_RPL (fmodf, float, (float x, float y));
1055# else 1068# else
1056# if !@HAVE_FMODF@ 1069# if !@HAVE_FMODF@
1057# undef fmodf 1070# undef fmodf
1058_GL_FUNCDECL_SYS (fmodf, float, (float x, float y)); 1071_GL_FUNCDECL_SYS (fmodf, float, (float x, float y), );
1059# endif 1072# endif
1060_GL_CXXALIAS_SYS (fmodf, float, (float x, float y)); 1073_GL_CXXALIAS_SYS (fmodf, float, (float x, float y));
1061# endif 1074# endif
@@ -1074,7 +1087,7 @@ _GL_WARN_ON_USE (fmodf, "fmodf is unportable - "
1074# undef fmod 1087# undef fmod
1075# define fmod rpl_fmod 1088# define fmod rpl_fmod
1076# endif 1089# endif
1077_GL_FUNCDECL_RPL (fmod, double, (double x, double y)); 1090_GL_FUNCDECL_RPL (fmod, double, (double x, double y), );
1078_GL_CXXALIAS_RPL (fmod, double, (double x, double y)); 1091_GL_CXXALIAS_RPL (fmod, double, (double x, double y));
1079# else 1092# else
1080_GL_CXXALIAS_SYS (fmod, double, (double x, double y)); 1093_GL_CXXALIAS_SYS (fmod, double, (double x, double y));
@@ -1096,12 +1109,12 @@ _GL_WARN_ON_USE (fmod, "fmod has portability problems - "
1096# undef fmodl 1109# undef fmodl
1097# define fmodl rpl_fmodl 1110# define fmodl rpl_fmodl
1098# endif 1111# endif
1099_GL_FUNCDECL_RPL (fmodl, long double, (long double x, long double y)); 1112_GL_FUNCDECL_RPL (fmodl, long double, (long double x, long double y), );
1100_GL_CXXALIAS_RPL (fmodl, long double, (long double x, long double y)); 1113_GL_CXXALIAS_RPL (fmodl, long double, (long double x, long double y));
1101# else 1114# else
1102# if !@HAVE_FMODL@ 1115# if !@HAVE_FMODL@
1103# undef fmodl 1116# undef fmodl
1104_GL_FUNCDECL_SYS (fmodl, long double, (long double x, long double y)); 1117_GL_FUNCDECL_SYS (fmodl, long double, (long double x, long double y), );
1105# endif 1118# endif
1106_GL_CXXALIAS_SYS (fmodl, long double, (long double x, long double y)); 1119_GL_CXXALIAS_SYS (fmodl, long double, (long double x, long double y));
1107# endif 1120# endif
@@ -1130,12 +1143,12 @@ _GL_WARN_ON_USE (fmodl, "fmodl is unportable - "
1130# undef frexpf 1143# undef frexpf
1131# define frexpf rpl_frexpf 1144# define frexpf rpl_frexpf
1132# endif 1145# endif
1133_GL_FUNCDECL_RPL (frexpf, float, (float x, int *expptr) _GL_ARG_NONNULL ((2))); 1146_GL_FUNCDECL_RPL (frexpf, float, (float x, int *expptr), _GL_ARG_NONNULL ((2)));
1134_GL_CXXALIAS_RPL (frexpf, float, (float x, int *expptr)); 1147_GL_CXXALIAS_RPL (frexpf, float, (float x, int *expptr));
1135# else 1148# else
1136# if !@HAVE_FREXPF@ 1149# if !@HAVE_FREXPF@
1137# undef frexpf 1150# undef frexpf
1138_GL_FUNCDECL_SYS (frexpf, float, (float x, int *expptr) _GL_ARG_NONNULL ((2))); 1151_GL_FUNCDECL_SYS (frexpf, float, (float x, int *expptr), _GL_ARG_NONNULL ((2)));
1139# endif 1152# endif
1140_GL_CXXALIAS_SYS (frexpf, float, (float x, int *expptr)); 1153_GL_CXXALIAS_SYS (frexpf, float, (float x, int *expptr));
1141# endif 1154# endif
@@ -1163,7 +1176,8 @@ _GL_WARN_ON_USE (frexpf, "frexpf is unportable - "
1163# undef frexp 1176# undef frexp
1164# define frexp rpl_frexp 1177# define frexp rpl_frexp
1165# endif 1178# endif
1166_GL_FUNCDECL_RPL (frexp, double, (double x, int *expptr) _GL_ARG_NONNULL ((2))); 1179_GL_FUNCDECL_RPL (frexp, double, (double x, int *expptr),
1180 _GL_ARG_NONNULL ((2)));
1167_GL_CXXALIAS_RPL (frexp, double, (double x, int *expptr)); 1181_GL_CXXALIAS_RPL (frexp, double, (double x, int *expptr));
1168# else 1182# else
1169_GL_CXXALIAS_SYS (frexp, double, (double x, int *expptr)); 1183_GL_CXXALIAS_SYS (frexp, double, (double x, int *expptr));
@@ -1174,8 +1188,10 @@ _GL_CXXALIASWARN1 (frexp, double, (double x, int *expptr));
1174#elif defined GNULIB_POSIXCHECK 1188#elif defined GNULIB_POSIXCHECK
1175# undef frexp 1189# undef frexp
1176/* Assume frexp is always declared. */ 1190/* Assume frexp is always declared. */
1177_GL_WARN_ON_USE (frexp, "frexp is unportable - " 1191_GL_WARN_ON_USE_CXX (frexp,
1178 "use gnulib module frexp for portability"); 1192 double, double, (double, int *),
1193 "frexp is unportable - "
1194 "use gnulib module frexp for portability");
1179#endif 1195#endif
1180 1196
1181/* Write x as 1197/* Write x as
@@ -1191,12 +1207,12 @@ _GL_WARN_ON_USE (frexp, "frexp is unportable - "
1191# define frexpl rpl_frexpl 1207# define frexpl rpl_frexpl
1192# endif 1208# endif
1193_GL_FUNCDECL_RPL (frexpl, long double, 1209_GL_FUNCDECL_RPL (frexpl, long double,
1194 (long double x, int *expptr) _GL_ARG_NONNULL ((2))); 1210 (long double x, int *expptr), _GL_ARG_NONNULL ((2)));
1195_GL_CXXALIAS_RPL (frexpl, long double, (long double x, int *expptr)); 1211_GL_CXXALIAS_RPL (frexpl, long double, (long double x, int *expptr));
1196#else 1212#else
1197# if !@HAVE_DECL_FREXPL@ 1213# if !@HAVE_DECL_FREXPL@
1198_GL_FUNCDECL_SYS (frexpl, long double, 1214_GL_FUNCDECL_SYS (frexpl, long double,
1199 (long double x, int *expptr) _GL_ARG_NONNULL ((2))); 1215 (long double x, int *expptr), _GL_ARG_NONNULL ((2)));
1200# endif 1216# endif
1201# if @GNULIB_FREXPL@ 1217# if @GNULIB_FREXPL@
1202_GL_CXXALIAS_SYS (frexpl, long double, (long double x, int *expptr)); 1218_GL_CXXALIAS_SYS (frexpl, long double, (long double x, int *expptr));
@@ -1223,11 +1239,11 @@ _GL_WARN_ON_USE (frexpl, "frexpl is unportable - "
1223# undef hypotf 1239# undef hypotf
1224# define hypotf rpl_hypotf 1240# define hypotf rpl_hypotf
1225# endif 1241# endif
1226_GL_FUNCDECL_RPL (hypotf, float, (float x, float y)); 1242_GL_FUNCDECL_RPL (hypotf, float, (float x, float y), );
1227_GL_CXXALIAS_RPL (hypotf, float, (float x, float y)); 1243_GL_CXXALIAS_RPL (hypotf, float, (float x, float y));
1228# else 1244# else
1229# if !@HAVE_HYPOTF@ 1245# if !@HAVE_HYPOTF@
1230_GL_FUNCDECL_SYS (hypotf, float, (float x, float y)); 1246_GL_FUNCDECL_SYS (hypotf, float, (float x, float y), );
1231# endif 1247# endif
1232_GL_CXXALIAS_SYS (hypotf, float, (float x, float y)); 1248_GL_CXXALIAS_SYS (hypotf, float, (float x, float y));
1233# endif 1249# endif
@@ -1249,7 +1265,7 @@ _GL_WARN_ON_USE (hypotf, "hypotf is unportable - "
1249# undef hypot 1265# undef hypot
1250# define hypot rpl_hypot 1266# define hypot rpl_hypot
1251# endif 1267# endif
1252_GL_FUNCDECL_RPL (hypot, double, (double x, double y)); 1268_GL_FUNCDECL_RPL (hypot, double, (double x, double y), );
1253_GL_CXXALIAS_RPL (hypot, double, (double x, double y)); 1269_GL_CXXALIAS_RPL (hypot, double, (double x, double y));
1254# else 1270# else
1255_GL_CXXALIAS_SYS (hypot, double, (double x, double y)); 1271_GL_CXXALIAS_SYS (hypot, double, (double x, double y));
@@ -1272,11 +1288,11 @@ _GL_WARN_ON_USE (hypotf, "hypot has portability problems - "
1272# undef hypotl 1288# undef hypotl
1273# define hypotl rpl_hypotl 1289# define hypotl rpl_hypotl
1274# endif 1290# endif
1275_GL_FUNCDECL_RPL (hypotl, long double, (long double x, long double y)); 1291_GL_FUNCDECL_RPL (hypotl, long double, (long double x, long double y), );
1276_GL_CXXALIAS_RPL (hypotl, long double, (long double x, long double y)); 1292_GL_CXXALIAS_RPL (hypotl, long double, (long double x, long double y));
1277# else 1293# else
1278# if !@HAVE_HYPOTL@ 1294# if !@HAVE_HYPOTL@
1279_GL_FUNCDECL_SYS (hypotl, long double, (long double x, long double y)); 1295_GL_FUNCDECL_SYS (hypotl, long double, (long double x, long double y), );
1280# endif 1296# endif
1281_GL_CXXALIAS_SYS (hypotl, long double, (long double x, long double y)); 1297_GL_CXXALIAS_SYS (hypotl, long double, (long double x, long double y));
1282# endif 1298# endif
@@ -1298,11 +1314,11 @@ _GL_WARN_ON_USE (hypotl, "hypotl is unportable - "
1298# undef ilogbf 1314# undef ilogbf
1299# define ilogbf rpl_ilogbf 1315# define ilogbf rpl_ilogbf
1300# endif 1316# endif
1301_GL_FUNCDECL_RPL (ilogbf, int, (float x)); 1317_GL_FUNCDECL_RPL (ilogbf, int, (float x), );
1302_GL_CXXALIAS_RPL (ilogbf, int, (float x)); 1318_GL_CXXALIAS_RPL (ilogbf, int, (float x));
1303# else 1319# else
1304# if !@HAVE_ILOGBF@ 1320# if !@HAVE_ILOGBF@
1305_GL_FUNCDECL_SYS (ilogbf, int, (float x)); 1321_GL_FUNCDECL_SYS (ilogbf, int, (float x), );
1306# endif 1322# endif
1307_GL_CXXALIAS_SYS (ilogbf, int, (float x)); 1323_GL_CXXALIAS_SYS (ilogbf, int, (float x));
1308# endif 1324# endif
@@ -1321,11 +1337,11 @@ _GL_WARN_ON_USE (ilogbf, "ilogbf is unportable - "
1321# undef ilogb 1337# undef ilogb
1322# define ilogb rpl_ilogb 1338# define ilogb rpl_ilogb
1323# endif 1339# endif
1324_GL_FUNCDECL_RPL (ilogb, int, (double x)); 1340_GL_FUNCDECL_RPL (ilogb, int, (double x), );
1325_GL_CXXALIAS_RPL (ilogb, int, (double x)); 1341_GL_CXXALIAS_RPL (ilogb, int, (double x));
1326# else 1342# else
1327# if !@HAVE_ILOGB@ 1343# if !@HAVE_ILOGB@
1328_GL_FUNCDECL_SYS (ilogb, int, (double x)); 1344_GL_FUNCDECL_SYS (ilogb, int, (double x), );
1329# endif 1345# endif
1330_GL_CXXALIAS_SYS (ilogb, int, (double x)); 1346_GL_CXXALIAS_SYS (ilogb, int, (double x));
1331# endif 1347# endif
@@ -1346,12 +1362,12 @@ _GL_WARN_ON_USE (ilogb, "ilogb is unportable - "
1346# undef ilogbl 1362# undef ilogbl
1347# define ilogbl rpl_ilogbl 1363# define ilogbl rpl_ilogbl
1348# endif 1364# endif
1349_GL_FUNCDECL_RPL (ilogbl, int, (long double x)); 1365_GL_FUNCDECL_RPL (ilogbl, int, (long double x), );
1350_GL_CXXALIAS_RPL (ilogbl, int, (long double x)); 1366_GL_CXXALIAS_RPL (ilogbl, int, (long double x));
1351# else 1367# else
1352# if !@HAVE_ILOGBL@ 1368# if !@HAVE_ILOGBL@
1353# undef ilogbl 1369# undef ilogbl
1354_GL_FUNCDECL_SYS (ilogbl, int, (long double x)); 1370_GL_FUNCDECL_SYS (ilogbl, int, (long double x), );
1355# endif 1371# endif
1356_GL_CXXALIAS_SYS (ilogbl, int, (long double x)); 1372_GL_CXXALIAS_SYS (ilogbl, int, (long double x));
1357# endif 1373# endif
@@ -1420,7 +1436,7 @@ _GL_CXXALIASWARN (jn);
1420#if @GNULIB_LDEXPF@ 1436#if @GNULIB_LDEXPF@
1421# if !@HAVE_LDEXPF@ 1437# if !@HAVE_LDEXPF@
1422# undef ldexpf 1438# undef ldexpf
1423_GL_FUNCDECL_SYS (ldexpf, float, (float x, int exp)); 1439_GL_FUNCDECL_SYS (ldexpf, float, (float x, int exp), );
1424# endif 1440# endif
1425_GL_CXXALIAS_SYS (ldexpf, float, (float x, int exp)); 1441_GL_CXXALIAS_SYS (ldexpf, float, (float x, int exp));
1426# if __GLIBC__ >= 2 1442# if __GLIBC__ >= 2
@@ -1441,7 +1457,7 @@ _GL_WARN_ON_USE (ldexpf, "ldexpf is unportable - "
1441# undef ldexp 1457# undef ldexp
1442# define ldexp rpl_ldexp 1458# define ldexp rpl_ldexp
1443# endif 1459# endif
1444_GL_FUNCDECL_RPL (ldexp, double, (double x, int exp)); 1460_GL_FUNCDECL_RPL (ldexp, double, (double x, int exp), );
1445_GL_CXXALIAS_RPL (ldexp, double, (double x, int exp)); 1461_GL_CXXALIAS_RPL (ldexp, double, (double x, int exp));
1446# else 1462# else
1447/* Assume ldexp is always declared. */ 1463/* Assume ldexp is always declared. */
@@ -1453,8 +1469,10 @@ _GL_CXXALIASWARN1 (ldexp, double, (double x, int exp));
1453#elif defined GNULIB_POSIXCHECK 1469#elif defined GNULIB_POSIXCHECK
1454# undef ldexp 1470# undef ldexp
1455/* Assume ldexp is always declared. */ 1471/* Assume ldexp is always declared. */
1456_GL_WARN_ON_USE (ldexp, "ldexp is unportable - " 1472_GL_WARN_ON_USE_CXX (ldexp,
1457 "use gnulib module ldexp for portability"); 1473 double, double, (double, int),
1474 "ldexp is unportable - "
1475 "use gnulib module ldexp for portability");
1458#endif 1476#endif
1459 1477
1460/* Return x * 2^exp. */ 1478/* Return x * 2^exp. */
@@ -1463,11 +1481,11 @@ _GL_WARN_ON_USE (ldexp, "ldexp is unportable - "
1463# undef ldexpl 1481# undef ldexpl
1464# define ldexpl rpl_ldexpl 1482# define ldexpl rpl_ldexpl
1465# endif 1483# endif
1466_GL_FUNCDECL_RPL (ldexpl, long double, (long double x, int exp)); 1484_GL_FUNCDECL_RPL (ldexpl, long double, (long double x, int exp), );
1467_GL_CXXALIAS_RPL (ldexpl, long double, (long double x, int exp)); 1485_GL_CXXALIAS_RPL (ldexpl, long double, (long double x, int exp));
1468#else 1486#else
1469# if !@HAVE_DECL_LDEXPL@ 1487# if !@HAVE_DECL_LDEXPL@
1470_GL_FUNCDECL_SYS (ldexpl, long double, (long double x, int exp)); 1488_GL_FUNCDECL_SYS (ldexpl, long double, (long double x, int exp), );
1471# endif 1489# endif
1472# if @GNULIB_LDEXPL@ 1490# if @GNULIB_LDEXPL@
1473_GL_CXXALIAS_SYS (ldexpl, long double, (long double x, int exp)); 1491_GL_CXXALIAS_SYS (ldexpl, long double, (long double x, int exp));
@@ -1493,12 +1511,12 @@ _GL_WARN_ON_USE (ldexpl, "ldexpl is unportable - "
1493# undef logf 1511# undef logf
1494# define logf rpl_logf 1512# define logf rpl_logf
1495# endif 1513# endif
1496_GL_FUNCDECL_RPL (logf, float, (float x)); 1514_GL_FUNCDECL_RPL (logf, float, (float x), );
1497_GL_CXXALIAS_RPL (logf, float, (float x)); 1515_GL_CXXALIAS_RPL (logf, float, (float x));
1498# else 1516# else
1499# if !@HAVE_LOGF@ 1517# if !@HAVE_LOGF@
1500# undef logf 1518# undef logf
1501_GL_FUNCDECL_SYS (logf, float, (float x)); 1519_GL_FUNCDECL_SYS (logf, float, (float x), );
1502# endif 1520# endif
1503_GL_CXXALIAS_SYS (logf, float, (float x)); 1521_GL_CXXALIAS_SYS (logf, float, (float x));
1504# endif 1522# endif
@@ -1517,7 +1535,7 @@ _GL_WARN_ON_USE (logf, "logf is unportable - "
1517# undef log 1535# undef log
1518# define log rpl_log 1536# define log rpl_log
1519# endif 1537# endif
1520_GL_FUNCDECL_RPL (log, double, (double x)); 1538_GL_FUNCDECL_RPL (log, double, (double x), );
1521_GL_CXXALIAS_RPL (log, double, (double x)); 1539_GL_CXXALIAS_RPL (log, double, (double x));
1522# else 1540# else
1523_GL_CXXALIAS_SYS (log, double, (double x)); 1541_GL_CXXALIAS_SYS (log, double, (double x));
@@ -1539,12 +1557,12 @@ _GL_WARN_ON_USE (log, "log has portability problems - "
1539# undef logl 1557# undef logl
1540# define logl rpl_logl 1558# define logl rpl_logl
1541# endif 1559# endif
1542_GL_FUNCDECL_RPL (logl, long double, (long double x)); 1560_GL_FUNCDECL_RPL (logl, long double, (long double x), );
1543_GL_CXXALIAS_RPL (logl, long double, (long double x)); 1561_GL_CXXALIAS_RPL (logl, long double, (long double x));
1544# else 1562# else
1545# if !@HAVE_LOGL@ || !@HAVE_DECL_LOGL@ 1563# if !@HAVE_LOGL@ || !@HAVE_DECL_LOGL@
1546# undef logl 1564# undef logl
1547_GL_FUNCDECL_SYS (logl, long double, (long double x)); 1565_GL_FUNCDECL_SYS (logl, long double, (long double x), );
1548# endif 1566# endif
1549_GL_CXXALIAS_SYS (logl, long double, (long double x)); 1567_GL_CXXALIAS_SYS (logl, long double, (long double x));
1550# endif 1568# endif
@@ -1566,12 +1584,12 @@ _GL_WARN_ON_USE (logl, "logl is unportable - "
1566# undef log10f 1584# undef log10f
1567# define log10f rpl_log10f 1585# define log10f rpl_log10f
1568# endif 1586# endif
1569_GL_FUNCDECL_RPL (log10f, float, (float x)); 1587_GL_FUNCDECL_RPL (log10f, float, (float x), );
1570_GL_CXXALIAS_RPL (log10f, float, (float x)); 1588_GL_CXXALIAS_RPL (log10f, float, (float x));
1571# else 1589# else
1572# if !@HAVE_LOG10F@ 1590# if !@HAVE_LOG10F@
1573# undef log10f 1591# undef log10f
1574_GL_FUNCDECL_SYS (log10f, float, (float x)); 1592_GL_FUNCDECL_SYS (log10f, float, (float x), );
1575# endif 1593# endif
1576_GL_CXXALIAS_SYS (log10f, float, (float x)); 1594_GL_CXXALIAS_SYS (log10f, float, (float x));
1577# endif 1595# endif
@@ -1590,7 +1608,7 @@ _GL_WARN_ON_USE (log10f, "log10f is unportable - "
1590# undef log10 1608# undef log10
1591# define log10 rpl_log10 1609# define log10 rpl_log10
1592# endif 1610# endif
1593_GL_FUNCDECL_RPL (log10, double, (double x)); 1611_GL_FUNCDECL_RPL (log10, double, (double x), );
1594_GL_CXXALIAS_RPL (log10, double, (double x)); 1612_GL_CXXALIAS_RPL (log10, double, (double x));
1595# else 1613# else
1596_GL_CXXALIAS_SYS (log10, double, (double x)); 1614_GL_CXXALIAS_SYS (log10, double, (double x));
@@ -1612,12 +1630,12 @@ _GL_WARN_ON_USE (log10, "log10 has portability problems - "
1612# undef log10l 1630# undef log10l
1613# define log10l rpl_log10l 1631# define log10l rpl_log10l
1614# endif 1632# endif
1615_GL_FUNCDECL_RPL (log10l, long double, (long double x)); 1633_GL_FUNCDECL_RPL (log10l, long double, (long double x), );
1616_GL_CXXALIAS_RPL (log10l, long double, (long double x)); 1634_GL_CXXALIAS_RPL (log10l, long double, (long double x));
1617# else 1635# else
1618# if !@HAVE_LOG10L@ || !@HAVE_DECL_LOG10L@ 1636# if !@HAVE_LOG10L@ || !@HAVE_DECL_LOG10L@
1619# undef log10l 1637# undef log10l
1620_GL_FUNCDECL_SYS (log10l, long double, (long double x)); 1638_GL_FUNCDECL_SYS (log10l, long double, (long double x), );
1621# endif 1639# endif
1622_GL_CXXALIAS_SYS (log10l, long double, (long double x)); 1640_GL_CXXALIAS_SYS (log10l, long double, (long double x));
1623# endif 1641# endif
@@ -1639,11 +1657,11 @@ _GL_WARN_ON_USE (log10l, "log10l is unportable - "
1639# undef log1pf 1657# undef log1pf
1640# define log1pf rpl_log1pf 1658# define log1pf rpl_log1pf
1641# endif 1659# endif
1642_GL_FUNCDECL_RPL (log1pf, float, (float x)); 1660_GL_FUNCDECL_RPL (log1pf, float, (float x), );
1643_GL_CXXALIAS_RPL (log1pf, float, (float x)); 1661_GL_CXXALIAS_RPL (log1pf, float, (float x));
1644# else 1662# else
1645# if !@HAVE_LOG1PF@ 1663# if !@HAVE_LOG1PF@
1646_GL_FUNCDECL_SYS (log1pf, float, (float x)); 1664_GL_FUNCDECL_SYS (log1pf, float, (float x), );
1647# endif 1665# endif
1648_GL_CXXALIAS_SYS (log1pf, float, (float x)); 1666_GL_CXXALIAS_SYS (log1pf, float, (float x));
1649# endif 1667# endif
@@ -1662,11 +1680,11 @@ _GL_WARN_ON_USE (log1pf, "log1pf is unportable - "
1662# undef log1p 1680# undef log1p
1663# define log1p rpl_log1p 1681# define log1p rpl_log1p
1664# endif 1682# endif
1665_GL_FUNCDECL_RPL (log1p, double, (double x)); 1683_GL_FUNCDECL_RPL (log1p, double, (double x), );
1666_GL_CXXALIAS_RPL (log1p, double, (double x)); 1684_GL_CXXALIAS_RPL (log1p, double, (double x));
1667# else 1685# else
1668# if !@HAVE_LOG1P@ 1686# if !@HAVE_LOG1P@
1669_GL_FUNCDECL_SYS (log1p, double, (double x)); 1687_GL_FUNCDECL_SYS (log1p, double, (double x), );
1670# endif 1688# endif
1671_GL_CXXALIAS_SYS (log1p, double, (double x)); 1689_GL_CXXALIAS_SYS (log1p, double, (double x));
1672# endif 1690# endif
@@ -1687,11 +1705,11 @@ _GL_WARN_ON_USE (log1p, "log1p has portability problems - "
1687# undef log1pl 1705# undef log1pl
1688# define log1pl rpl_log1pl 1706# define log1pl rpl_log1pl
1689# endif 1707# endif
1690_GL_FUNCDECL_RPL (log1pl, long double, (long double x)); 1708_GL_FUNCDECL_RPL (log1pl, long double, (long double x), );
1691_GL_CXXALIAS_RPL (log1pl, long double, (long double x)); 1709_GL_CXXALIAS_RPL (log1pl, long double, (long double x));
1692# else 1710# else
1693# if !@HAVE_LOG1PL@ 1711# if !@HAVE_LOG1PL@
1694_GL_FUNCDECL_SYS (log1pl, long double, (long double x)); 1712_GL_FUNCDECL_SYS (log1pl, long double, (long double x), );
1695# endif 1713# endif
1696_GL_CXXALIAS_SYS (log1pl, long double, (long double x)); 1714_GL_CXXALIAS_SYS (log1pl, long double, (long double x));
1697# endif 1715# endif
@@ -1713,12 +1731,12 @@ _GL_WARN_ON_USE (log1pl, "log1pl has portability problems - "
1713# undef log2f 1731# undef log2f
1714# define log2f rpl_log2f 1732# define log2f rpl_log2f
1715# endif 1733# endif
1716_GL_FUNCDECL_RPL (log2f, float, (float x)); 1734_GL_FUNCDECL_RPL (log2f, float, (float x), );
1717_GL_CXXALIAS_RPL (log2f, float, (float x)); 1735_GL_CXXALIAS_RPL (log2f, float, (float x));
1718# else 1736# else
1719# if !@HAVE_DECL_LOG2F@ 1737# if !@HAVE_DECL_LOG2F@
1720# undef log2f 1738# undef log2f
1721_GL_FUNCDECL_SYS (log2f, float, (float x)); 1739_GL_FUNCDECL_SYS (log2f, float, (float x), );
1722# endif 1740# endif
1723_GL_CXXALIAS_SYS (log2f, float, (float x)); 1741_GL_CXXALIAS_SYS (log2f, float, (float x));
1724# endif 1742# endif
@@ -1739,12 +1757,12 @@ _GL_WARN_ON_USE (log2f, "log2f is unportable - "
1739# undef log2 1757# undef log2
1740# define log2 rpl_log2 1758# define log2 rpl_log2
1741# endif 1759# endif
1742_GL_FUNCDECL_RPL (log2, double, (double x)); 1760_GL_FUNCDECL_RPL (log2, double, (double x), );
1743_GL_CXXALIAS_RPL (log2, double, (double x)); 1761_GL_CXXALIAS_RPL (log2, double, (double x));
1744# else 1762# else
1745# if !@HAVE_DECL_LOG2@ 1763# if !@HAVE_DECL_LOG2@
1746# undef log2 1764# undef log2
1747_GL_FUNCDECL_SYS (log2, double, (double x)); 1765_GL_FUNCDECL_SYS (log2, double, (double x), );
1748# endif 1766# endif
1749_GL_CXXALIAS_SYS (log2, double, (double x)); 1767_GL_CXXALIAS_SYS (log2, double, (double x));
1750# endif 1768# endif
@@ -1765,11 +1783,11 @@ _GL_WARN_ON_USE (log2, "log2 is unportable - "
1765# undef log2l 1783# undef log2l
1766# define log2l rpl_log2l 1784# define log2l rpl_log2l
1767# endif 1785# endif
1768_GL_FUNCDECL_RPL (log2l, long double, (long double x)); 1786_GL_FUNCDECL_RPL (log2l, long double, (long double x), );
1769_GL_CXXALIAS_RPL (log2l, long double, (long double x)); 1787_GL_CXXALIAS_RPL (log2l, long double, (long double x));
1770# else 1788# else
1771# if !@HAVE_DECL_LOG2L@ 1789# if !@HAVE_DECL_LOG2L@
1772_GL_FUNCDECL_SYS (log2l, long double, (long double x)); 1790_GL_FUNCDECL_SYS (log2l, long double, (long double x), );
1773# endif 1791# endif
1774_GL_CXXALIAS_SYS (log2l, long double, (long double x)); 1792_GL_CXXALIAS_SYS (log2l, long double, (long double x));
1775# endif 1793# endif
@@ -1791,11 +1809,11 @@ _GL_WARN_ON_USE (log2l, "log2l is unportable - "
1791# undef logbf 1809# undef logbf
1792# define logbf rpl_logbf 1810# define logbf rpl_logbf
1793# endif 1811# endif
1794_GL_FUNCDECL_RPL (logbf, float, (float x)); 1812_GL_FUNCDECL_RPL (logbf, float, (float x), );
1795_GL_CXXALIAS_RPL (logbf, float, (float x)); 1813_GL_CXXALIAS_RPL (logbf, float, (float x));
1796# else 1814# else
1797# if !@HAVE_LOGBF@ 1815# if !@HAVE_LOGBF@
1798_GL_FUNCDECL_SYS (logbf, float, (float x)); 1816_GL_FUNCDECL_SYS (logbf, float, (float x), );
1799# endif 1817# endif
1800_GL_CXXALIAS_SYS (logbf, float, (float x)); 1818_GL_CXXALIAS_SYS (logbf, float, (float x));
1801# endif 1819# endif
@@ -1814,11 +1832,11 @@ _GL_WARN_ON_USE (logbf, "logbf is unportable - "
1814# undef logb 1832# undef logb
1815# define logb rpl_logb 1833# define logb rpl_logb
1816# endif 1834# endif
1817_GL_FUNCDECL_RPL (logb, double, (double x)); 1835_GL_FUNCDECL_RPL (logb, double, (double x), );
1818_GL_CXXALIAS_RPL (logb, double, (double x)); 1836_GL_CXXALIAS_RPL (logb, double, (double x));
1819# else 1837# else
1820# if !@HAVE_DECL_LOGB@ 1838# if !@HAVE_DECL_LOGB@
1821_GL_FUNCDECL_SYS (logb, double, (double x)); 1839_GL_FUNCDECL_SYS (logb, double, (double x), );
1822# endif 1840# endif
1823_GL_CXXALIAS_SYS (logb, double, (double x)); 1841_GL_CXXALIAS_SYS (logb, double, (double x));
1824# endif 1842# endif
@@ -1839,11 +1857,11 @@ _GL_WARN_ON_USE (logb, "logb is unportable - "
1839# undef logbl 1857# undef logbl
1840# define logbl rpl_logbl 1858# define logbl rpl_logbl
1841# endif 1859# endif
1842_GL_FUNCDECL_RPL (logbl, long double, (long double x)); 1860_GL_FUNCDECL_RPL (logbl, long double, (long double x), );
1843_GL_CXXALIAS_RPL (logbl, long double, (long double x)); 1861_GL_CXXALIAS_RPL (logbl, long double, (long double x));
1844# else 1862# else
1845# if !@HAVE_LOGBL@ 1863# if !@HAVE_LOGBL@
1846_GL_FUNCDECL_SYS (logbl, long double, (long double x)); 1864_GL_FUNCDECL_SYS (logbl, long double, (long double x), );
1847# endif 1865# endif
1848_GL_CXXALIAS_SYS (logbl, long double, (long double x)); 1866_GL_CXXALIAS_SYS (logbl, long double, (long double x));
1849# endif 1867# endif
@@ -1859,18 +1877,67 @@ _GL_WARN_ON_USE (logbl, "logbl is unportable - "
1859#endif 1877#endif
1860 1878
1861 1879
1880#if @GNULIB_LOGP1F@
1881# if !@HAVE_LOGP1F@
1882_GL_FUNCDECL_SYS (logp1f, float, (float x), );
1883# endif
1884_GL_CXXALIAS_SYS (logp1f, float, (float x));
1885# if __GLIBC__ >= 2
1886_GL_CXXALIASWARN1 (logp1f, float, (float x));
1887# endif
1888#elif defined GNULIB_POSIXCHECK
1889# undef logp1f
1890# if HAVE_RAW_DECL_LOGP1F
1891_GL_WARN_ON_USE (logp1f, "logp1f is unportable - "
1892 "use gnulib module logp1f for portability");
1893# endif
1894#endif
1895
1896#if @GNULIB_LOGP1@
1897# if !@HAVE_LOGP1@
1898_GL_FUNCDECL_SYS (logp1, double, (double x), );
1899# endif
1900_GL_CXXALIAS_SYS (logp1, double, (double x));
1901# if __GLIBC__ >= 2
1902_GL_CXXALIASWARN1 (logp1, double, (double x));
1903# endif
1904#elif defined GNULIB_POSIXCHECK
1905# undef logp1
1906# if HAVE_RAW_DECL_LOGP1
1907_GL_WARN_ON_USE (logp1, "logp1 is unportable - "
1908 "use gnulib module logp1 for portability");
1909# endif
1910#endif
1911
1912#if @GNULIB_LOGP1L@
1913# if !@HAVE_LOGP1L@
1914_GL_FUNCDECL_SYS (logp1l, long double, (long double x), );
1915# endif
1916_GL_CXXALIAS_SYS (logp1l, long double, (long double x));
1917# if __GLIBC__ >= 2
1918_GL_CXXALIASWARN1 (logp1l, long double, (long double x));
1919# endif
1920#elif defined GNULIB_POSIXCHECK
1921# undef logp1l
1922# if HAVE_RAW_DECL_LOGP1L
1923_GL_WARN_ON_USE (logp1l, "logp1l is unportable - "
1924 "use gnulib module logp1l for portability");
1925# endif
1926#endif
1927
1928
1862#if @GNULIB_MODFF@ 1929#if @GNULIB_MODFF@
1863# if @REPLACE_MODFF@ 1930# if @REPLACE_MODFF@
1864# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1931# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1865# undef modff 1932# undef modff
1866# define modff rpl_modff 1933# define modff rpl_modff
1867# endif 1934# endif
1868_GL_FUNCDECL_RPL (modff, float, (float x, float *iptr) _GL_ARG_NONNULL ((2))); 1935_GL_FUNCDECL_RPL (modff, float, (float x, float *iptr), _GL_ARG_NONNULL ((2)));
1869_GL_CXXALIAS_RPL (modff, float, (float x, float *iptr)); 1936_GL_CXXALIAS_RPL (modff, float, (float x, float *iptr));
1870# else 1937# else
1871# if !@HAVE_MODFF@ 1938# if !@HAVE_MODFF@
1872# undef modff 1939# undef modff
1873_GL_FUNCDECL_SYS (modff, float, (float x, float *iptr) _GL_ARG_NONNULL ((2))); 1940_GL_FUNCDECL_SYS (modff, float, (float x, float *iptr), _GL_ARG_NONNULL ((2)));
1874# endif 1941# endif
1875_GL_CXXALIAS_SYS (modff, float, (float x, float *iptr)); 1942_GL_CXXALIAS_SYS (modff, float, (float x, float *iptr));
1876# endif 1943# endif
@@ -1889,7 +1956,8 @@ _GL_WARN_ON_USE (modff, "modff is unportable - "
1889# undef modf 1956# undef modf
1890# define modf rpl_modf 1957# define modf rpl_modf
1891# endif 1958# endif
1892_GL_FUNCDECL_RPL (modf, double, (double x, double *iptr) _GL_ARG_NONNULL ((2))); 1959_GL_FUNCDECL_RPL (modf, double, (double x, double *iptr),
1960 _GL_ARG_NONNULL ((2)));
1893_GL_CXXALIAS_RPL (modf, double, (double x, double *iptr)); 1961_GL_CXXALIAS_RPL (modf, double, (double x, double *iptr));
1894# else 1962# else
1895_GL_CXXALIAS_SYS (modf, double, (double x, double *iptr)); 1963_GL_CXXALIAS_SYS (modf, double, (double x, double *iptr));
@@ -1911,13 +1979,13 @@ _GL_WARN_ON_USE (modf, "modf has portability problems - "
1911# undef modfl 1979# undef modfl
1912# define modfl rpl_modfl 1980# define modfl rpl_modfl
1913# endif 1981# endif
1914_GL_FUNCDECL_RPL (modfl, long double, (long double x, long double *iptr) 1982_GL_FUNCDECL_RPL (modfl, long double, (long double x, long double *iptr),
1915 _GL_ARG_NONNULL ((2))); 1983 _GL_ARG_NONNULL ((2)));
1916_GL_CXXALIAS_RPL (modfl, long double, (long double x, long double *iptr)); 1984_GL_CXXALIAS_RPL (modfl, long double, (long double x, long double *iptr));
1917# else 1985# else
1918# if !@HAVE_MODFL@ 1986# if !@HAVE_MODFL@
1919# undef modfl 1987# undef modfl
1920_GL_FUNCDECL_SYS (modfl, long double, (long double x, long double *iptr) 1988_GL_FUNCDECL_SYS (modfl, long double, (long double x, long double *iptr),
1921 _GL_ARG_NONNULL ((2))); 1989 _GL_ARG_NONNULL ((2)));
1922# endif 1990# endif
1923_GL_CXXALIAS_SYS (modfl, long double, (long double x, long double *iptr)); 1991_GL_CXXALIAS_SYS (modfl, long double, (long double x, long double *iptr));
@@ -1937,7 +2005,7 @@ _GL_WARN_ON_USE (modfl, "modfl is unportable - "
1937#if @GNULIB_POWF@ 2005#if @GNULIB_POWF@
1938# if !@HAVE_POWF@ 2006# if !@HAVE_POWF@
1939# undef powf 2007# undef powf
1940_GL_FUNCDECL_SYS (powf, float, (float x, float y)); 2008_GL_FUNCDECL_SYS (powf, float, (float x, float y), );
1941# endif 2009# endif
1942_GL_CXXALIAS_SYS (powf, float, (float x, float y)); 2010_GL_CXXALIAS_SYS (powf, float, (float x, float y));
1943_GL_CXXALIASWARN (powf); 2011_GL_CXXALIASWARN (powf);
@@ -1956,11 +2024,11 @@ _GL_WARN_ON_USE (powf, "powf is unportable - "
1956# undef remainderf 2024# undef remainderf
1957# define remainderf rpl_remainderf 2025# define remainderf rpl_remainderf
1958# endif 2026# endif
1959_GL_FUNCDECL_RPL (remainderf, float, (float x, float y)); 2027_GL_FUNCDECL_RPL (remainderf, float, (float x, float y), );
1960_GL_CXXALIAS_RPL (remainderf, float, (float x, float y)); 2028_GL_CXXALIAS_RPL (remainderf, float, (float x, float y));
1961# else 2029# else
1962# if !@HAVE_REMAINDERF@ 2030# if !@HAVE_REMAINDERF@
1963_GL_FUNCDECL_SYS (remainderf, float, (float x, float y)); 2031_GL_FUNCDECL_SYS (remainderf, float, (float x, float y), );
1964# endif 2032# endif
1965_GL_CXXALIAS_SYS (remainderf, float, (float x, float y)); 2033_GL_CXXALIAS_SYS (remainderf, float, (float x, float y));
1966# endif 2034# endif
@@ -1979,11 +2047,11 @@ _GL_WARN_ON_USE (remainderf, "remainderf is unportable - "
1979# undef remainder 2047# undef remainder
1980# define remainder rpl_remainder 2048# define remainder rpl_remainder
1981# endif 2049# endif
1982_GL_FUNCDECL_RPL (remainder, double, (double x, double y)); 2050_GL_FUNCDECL_RPL (remainder, double, (double x, double y), );
1983_GL_CXXALIAS_RPL (remainder, double, (double x, double y)); 2051_GL_CXXALIAS_RPL (remainder, double, (double x, double y));
1984# else 2052# else
1985# if !@HAVE_REMAINDER@ || !@HAVE_DECL_REMAINDER@ 2053# if !@HAVE_REMAINDER@ || !@HAVE_DECL_REMAINDER@
1986_GL_FUNCDECL_SYS (remainder, double, (double x, double y)); 2054_GL_FUNCDECL_SYS (remainder, double, (double x, double y), );
1987# endif 2055# endif
1988_GL_CXXALIAS_SYS (remainder, double, (double x, double y)); 2056_GL_CXXALIAS_SYS (remainder, double, (double x, double y));
1989# endif 2057# endif
@@ -2004,13 +2072,13 @@ _GL_WARN_ON_USE (remainder, "remainder is unportable - "
2004# undef remainderl 2072# undef remainderl
2005# define remainderl rpl_remainderl 2073# define remainderl rpl_remainderl
2006# endif 2074# endif
2007_GL_FUNCDECL_RPL (remainderl, long double, (long double x, long double y)); 2075_GL_FUNCDECL_RPL (remainderl, long double, (long double x, long double y), );
2008_GL_CXXALIAS_RPL (remainderl, long double, (long double x, long double y)); 2076_GL_CXXALIAS_RPL (remainderl, long double, (long double x, long double y));
2009# else 2077# else
2010# if !@HAVE_DECL_REMAINDERL@ 2078# if !@HAVE_DECL_REMAINDERL@
2011# undef remainderl 2079# undef remainderl
2012# if !(defined __cplusplus && defined _AIX) 2080# if !(defined __cplusplus && defined _AIX)
2013_GL_FUNCDECL_SYS (remainderl, long double, (long double x, long double y)); 2081_GL_FUNCDECL_SYS (remainderl, long double, (long double x, long double y), );
2014# endif 2082# endif
2015# endif 2083# endif
2016_GL_CXXALIAS_SYS (remainderl, long double, (long double x, long double y)); 2084_GL_CXXALIAS_SYS (remainderl, long double, (long double x, long double y));
@@ -2029,7 +2097,7 @@ _GL_WARN_ON_USE (remainderl, "remainderl is unportable - "
2029 2097
2030#if @GNULIB_RINTF@ 2098#if @GNULIB_RINTF@
2031# if !@HAVE_DECL_RINTF@ 2099# if !@HAVE_DECL_RINTF@
2032_GL_FUNCDECL_SYS (rintf, float, (float x)); 2100_GL_FUNCDECL_SYS (rintf, float, (float x), );
2033# endif 2101# endif
2034_GL_CXXALIAS_SYS (rintf, float, (float x)); 2102_GL_CXXALIAS_SYS (rintf, float, (float x));
2035_GL_CXXALIASWARN (rintf); 2103_GL_CXXALIASWARN (rintf);
@@ -2043,7 +2111,7 @@ _GL_WARN_ON_USE (rintf, "rintf is unportable - "
2043 2111
2044#if @GNULIB_RINT@ 2112#if @GNULIB_RINT@
2045# if !@HAVE_RINT@ 2113# if !@HAVE_RINT@
2046_GL_FUNCDECL_SYS (rint, double, (double x)); 2114_GL_FUNCDECL_SYS (rint, double, (double x), );
2047# endif 2115# endif
2048_GL_CXXALIAS_SYS (rint, double, (double x)); 2116_GL_CXXALIAS_SYS (rint, double, (double x));
2049# if __GLIBC__ >= 2 2117# if __GLIBC__ >= 2
@@ -2063,11 +2131,11 @@ _GL_WARN_ON_USE (rint, "rint is unportable - "
2063# undef rintl 2131# undef rintl
2064# define rintl rpl_rintl 2132# define rintl rpl_rintl
2065# endif 2133# endif
2066_GL_FUNCDECL_RPL (rintl, long double, (long double x)); 2134_GL_FUNCDECL_RPL (rintl, long double, (long double x), );
2067_GL_CXXALIAS_RPL (rintl, long double, (long double x)); 2135_GL_CXXALIAS_RPL (rintl, long double, (long double x));
2068# else 2136# else
2069# if !@HAVE_RINTL@ 2137# if !@HAVE_RINTL@
2070_GL_FUNCDECL_SYS (rintl, long double, (long double x)); 2138_GL_FUNCDECL_SYS (rintl, long double, (long double x), );
2071# endif 2139# endif
2072_GL_CXXALIAS_SYS (rintl, long double, (long double x)); 2140_GL_CXXALIAS_SYS (rintl, long double, (long double x));
2073# endif 2141# endif
@@ -2089,11 +2157,11 @@ _GL_WARN_ON_USE (rintl, "rintl is unportable - "
2089# undef roundf 2157# undef roundf
2090# define roundf rpl_roundf 2158# define roundf rpl_roundf
2091# endif 2159# endif
2092_GL_FUNCDECL_RPL (roundf, float, (float x)); 2160_GL_FUNCDECL_RPL (roundf, float, (float x), );
2093_GL_CXXALIAS_RPL (roundf, float, (float x)); 2161_GL_CXXALIAS_RPL (roundf, float, (float x));
2094# else 2162# else
2095# if !@HAVE_DECL_ROUNDF@ 2163# if !@HAVE_DECL_ROUNDF@
2096_GL_FUNCDECL_SYS (roundf, float, (float x)); 2164_GL_FUNCDECL_SYS (roundf, float, (float x), );
2097# endif 2165# endif
2098_GL_CXXALIAS_SYS (roundf, float, (float x)); 2166_GL_CXXALIAS_SYS (roundf, float, (float x));
2099# endif 2167# endif
@@ -2112,11 +2180,11 @@ _GL_WARN_ON_USE (roundf, "roundf is unportable - "
2112# undef round 2180# undef round
2113# define round rpl_round 2181# define round rpl_round
2114# endif 2182# endif
2115_GL_FUNCDECL_RPL (round, double, (double x)); 2183_GL_FUNCDECL_RPL (round, double, (double x), );
2116_GL_CXXALIAS_RPL (round, double, (double x)); 2184_GL_CXXALIAS_RPL (round, double, (double x));
2117# else 2185# else
2118# if !@HAVE_DECL_ROUND@ 2186# if !@HAVE_DECL_ROUND@
2119_GL_FUNCDECL_SYS (round, double, (double x)); 2187_GL_FUNCDECL_SYS (round, double, (double x), );
2120# endif 2188# endif
2121_GL_CXXALIAS_SYS (round, double, (double x)); 2189_GL_CXXALIAS_SYS (round, double, (double x));
2122# endif 2190# endif
@@ -2137,13 +2205,13 @@ _GL_WARN_ON_USE (round, "round is unportable - "
2137# undef roundl 2205# undef roundl
2138# define roundl rpl_roundl 2206# define roundl rpl_roundl
2139# endif 2207# endif
2140_GL_FUNCDECL_RPL (roundl, long double, (long double x)); 2208_GL_FUNCDECL_RPL (roundl, long double, (long double x), );
2141_GL_CXXALIAS_RPL (roundl, long double, (long double x)); 2209_GL_CXXALIAS_RPL (roundl, long double, (long double x));
2142# else 2210# else
2143# if !@HAVE_DECL_ROUNDL@ 2211# if !@HAVE_DECL_ROUNDL@
2144# undef roundl 2212# undef roundl
2145# if !(defined __cplusplus && defined _AIX) 2213# if !(defined __cplusplus && defined _AIX)
2146_GL_FUNCDECL_SYS (roundl, long double, (long double x)); 2214_GL_FUNCDECL_SYS (roundl, long double, (long double x), );
2147# endif 2215# endif
2148# endif 2216# endif
2149_GL_CXXALIAS_SYS (roundl, long double, (long double x)); 2217_GL_CXXALIAS_SYS (roundl, long double, (long double x));
@@ -2166,12 +2234,12 @@ _GL_WARN_ON_USE (roundl, "roundl is unportable - "
2166# undef sinf 2234# undef sinf
2167# define sinf rpl_sinf 2235# define sinf rpl_sinf
2168# endif 2236# endif
2169_GL_FUNCDECL_RPL (sinf, float, (float x)); 2237_GL_FUNCDECL_RPL (sinf, float, (float x), );
2170_GL_CXXALIAS_RPL (sinf, float, (float x)); 2238_GL_CXXALIAS_RPL (sinf, float, (float x));
2171# else 2239# else
2172# if !@HAVE_SINF@ 2240# if !@HAVE_SINF@
2173# undef sinf 2241# undef sinf
2174_GL_FUNCDECL_SYS (sinf, float, (float x)); 2242_GL_FUNCDECL_SYS (sinf, float, (float x), );
2175# endif 2243# endif
2176_GL_CXXALIAS_SYS (sinf, float, (float x)); 2244_GL_CXXALIAS_SYS (sinf, float, (float x));
2177# endif 2245# endif
@@ -2185,11 +2253,20 @@ _GL_WARN_ON_USE (sinf, "sinf is unportable - "
2185#endif 2253#endif
2186 2254
2187#if @GNULIB_SINL@ 2255#if @GNULIB_SINL@
2188# if !@HAVE_SINL@ || !@HAVE_DECL_SINL@ 2256# if @REPLACE_SINL@
2189# undef sinl 2257# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2190_GL_FUNCDECL_SYS (sinl, long double, (long double x)); 2258# undef sinl
2191# endif 2259# define sinl rpl_sinl
2260# endif
2261_GL_FUNCDECL_RPL (sinl, long double, (long double x), );
2262_GL_CXXALIAS_RPL (sinl, long double, (long double x));
2263# else
2264# if !@HAVE_SINL@ || !@HAVE_DECL_SINL@
2265# undef sinl
2266_GL_FUNCDECL_SYS (sinl, long double, (long double x), );
2267# endif
2192_GL_CXXALIAS_SYS (sinl, long double, (long double x)); 2268_GL_CXXALIAS_SYS (sinl, long double, (long double x));
2269# endif
2193# if __GLIBC__ >= 2 2270# if __GLIBC__ >= 2
2194_GL_CXXALIASWARN (sinl); 2271_GL_CXXALIASWARN (sinl);
2195# endif 2272# endif
@@ -2208,12 +2285,12 @@ _GL_WARN_ON_USE (sinl, "sinl is unportable - "
2208# undef sinhf 2285# undef sinhf
2209# define sinhf rpl_sinhf 2286# define sinhf rpl_sinhf
2210# endif 2287# endif
2211_GL_FUNCDECL_RPL (sinhf, float, (float x)); 2288_GL_FUNCDECL_RPL (sinhf, float, (float x), );
2212_GL_CXXALIAS_RPL (sinhf, float, (float x)); 2289_GL_CXXALIAS_RPL (sinhf, float, (float x));
2213# else 2290# else
2214# if !@HAVE_SINHF@ 2291# if !@HAVE_SINHF@
2215# undef sinhf 2292# undef sinhf
2216_GL_FUNCDECL_SYS (sinhf, float, (float x)); 2293_GL_FUNCDECL_SYS (sinhf, float, (float x), );
2217# endif 2294# endif
2218_GL_CXXALIAS_SYS (sinhf, float, (float x)); 2295_GL_CXXALIAS_SYS (sinhf, float, (float x));
2219# endif 2296# endif
@@ -2233,12 +2310,12 @@ _GL_WARN_ON_USE (sinhf, "sinhf is unportable - "
2233# undef sqrtf 2310# undef sqrtf
2234# define sqrtf rpl_sqrtf 2311# define sqrtf rpl_sqrtf
2235# endif 2312# endif
2236_GL_FUNCDECL_RPL (sqrtf, float, (float x)); 2313_GL_FUNCDECL_RPL (sqrtf, float, (float x), );
2237_GL_CXXALIAS_RPL (sqrtf, float, (float x)); 2314_GL_CXXALIAS_RPL (sqrtf, float, (float x));
2238# else 2315# else
2239# if !@HAVE_SQRTF@ 2316# if !@HAVE_SQRTF@
2240# undef sqrtf 2317# undef sqrtf
2241_GL_FUNCDECL_SYS (sqrtf, float, (float x)); 2318_GL_FUNCDECL_SYS (sqrtf, float, (float x), );
2242# endif 2319# endif
2243_GL_CXXALIAS_SYS (sqrtf, float, (float x)); 2320_GL_CXXALIAS_SYS (sqrtf, float, (float x));
2244# endif 2321# endif
@@ -2257,12 +2334,12 @@ _GL_WARN_ON_USE (sqrtf, "sqrtf is unportable - "
2257# undef sqrtl 2334# undef sqrtl
2258# define sqrtl rpl_sqrtl 2335# define sqrtl rpl_sqrtl
2259# endif 2336# endif
2260_GL_FUNCDECL_RPL (sqrtl, long double, (long double x)); 2337_GL_FUNCDECL_RPL (sqrtl, long double, (long double x), );
2261_GL_CXXALIAS_RPL (sqrtl, long double, (long double x)); 2338_GL_CXXALIAS_RPL (sqrtl, long double, (long double x));
2262# else 2339# else
2263# if !@HAVE_SQRTL@ || !@HAVE_DECL_SQRTL@ 2340# if !@HAVE_SQRTL@ || !@HAVE_DECL_SQRTL@
2264# undef sqrtl 2341# undef sqrtl
2265_GL_FUNCDECL_SYS (sqrtl, long double, (long double x)); 2342_GL_FUNCDECL_SYS (sqrtl, long double, (long double x), );
2266# endif 2343# endif
2267_GL_CXXALIAS_SYS (sqrtl, long double, (long double x)); 2344_GL_CXXALIAS_SYS (sqrtl, long double, (long double x));
2268# endif 2345# endif
@@ -2284,12 +2361,12 @@ _GL_WARN_ON_USE (sqrtl, "sqrtl is unportable - "
2284# undef tanf 2361# undef tanf
2285# define tanf rpl_tanf 2362# define tanf rpl_tanf
2286# endif 2363# endif
2287_GL_FUNCDECL_RPL (tanf, float, (float x)); 2364_GL_FUNCDECL_RPL (tanf, float, (float x), );
2288_GL_CXXALIAS_RPL (tanf, float, (float x)); 2365_GL_CXXALIAS_RPL (tanf, float, (float x));
2289# else 2366# else
2290# if !@HAVE_TANF@ 2367# if !@HAVE_TANF@
2291# undef tanf 2368# undef tanf
2292_GL_FUNCDECL_SYS (tanf, float, (float x)); 2369_GL_FUNCDECL_SYS (tanf, float, (float x), );
2293# endif 2370# endif
2294_GL_CXXALIAS_SYS (tanf, float, (float x)); 2371_GL_CXXALIAS_SYS (tanf, float, (float x));
2295# endif 2372# endif
@@ -2305,7 +2382,7 @@ _GL_WARN_ON_USE (tanf, "tanf is unportable - "
2305#if @GNULIB_TANL@ 2382#if @GNULIB_TANL@
2306# if !@HAVE_TANL@ || !@HAVE_DECL_TANL@ 2383# if !@HAVE_TANL@ || !@HAVE_DECL_TANL@
2307# undef tanl 2384# undef tanl
2308_GL_FUNCDECL_SYS (tanl, long double, (long double x)); 2385_GL_FUNCDECL_SYS (tanl, long double, (long double x), );
2309# endif 2386# endif
2310_GL_CXXALIAS_SYS (tanl, long double, (long double x)); 2387_GL_CXXALIAS_SYS (tanl, long double, (long double x));
2311# if __GLIBC__ >= 2 2388# if __GLIBC__ >= 2
@@ -2326,12 +2403,12 @@ _GL_WARN_ON_USE (tanl, "tanl is unportable - "
2326# undef tanhf 2403# undef tanhf
2327# define tanhf rpl_tanhf 2404# define tanhf rpl_tanhf
2328# endif 2405# endif
2329_GL_FUNCDECL_RPL (tanhf, float, (float x)); 2406_GL_FUNCDECL_RPL (tanhf, float, (float x), );
2330_GL_CXXALIAS_RPL (tanhf, float, (float x)); 2407_GL_CXXALIAS_RPL (tanhf, float, (float x));
2331# else 2408# else
2332# if !@HAVE_TANHF@ 2409# if !@HAVE_TANHF@
2333# undef tanhf 2410# undef tanhf
2334_GL_FUNCDECL_SYS (tanhf, float, (float x)); 2411_GL_FUNCDECL_SYS (tanhf, float, (float x), );
2335# endif 2412# endif
2336_GL_CXXALIAS_SYS (tanhf, float, (float x)); 2413_GL_CXXALIAS_SYS (tanhf, float, (float x));
2337# endif 2414# endif
@@ -2351,11 +2428,11 @@ _GL_WARN_ON_USE (tanhf, "tanhf is unportable - "
2351# undef truncf 2428# undef truncf
2352# define truncf rpl_truncf 2429# define truncf rpl_truncf
2353# endif 2430# endif
2354_GL_FUNCDECL_RPL (truncf, float, (float x)); 2431_GL_FUNCDECL_RPL (truncf, float, (float x), );
2355_GL_CXXALIAS_RPL (truncf, float, (float x)); 2432_GL_CXXALIAS_RPL (truncf, float, (float x));
2356# else 2433# else
2357# if !@HAVE_DECL_TRUNCF@ 2434# if !@HAVE_DECL_TRUNCF@
2358_GL_FUNCDECL_SYS (truncf, float, (float x)); 2435_GL_FUNCDECL_SYS (truncf, float, (float x), );
2359# endif 2436# endif
2360_GL_CXXALIAS_SYS (truncf, float, (float x)); 2437_GL_CXXALIAS_SYS (truncf, float, (float x));
2361# endif 2438# endif
@@ -2374,11 +2451,11 @@ _GL_WARN_ON_USE (truncf, "truncf is unportable - "
2374# undef trunc 2451# undef trunc
2375# define trunc rpl_trunc 2452# define trunc rpl_trunc
2376# endif 2453# endif
2377_GL_FUNCDECL_RPL (trunc, double, (double x)); 2454_GL_FUNCDECL_RPL (trunc, double, (double x), );
2378_GL_CXXALIAS_RPL (trunc, double, (double x)); 2455_GL_CXXALIAS_RPL (trunc, double, (double x));
2379# else 2456# else
2380# if !@HAVE_DECL_TRUNC@ 2457# if !@HAVE_DECL_TRUNC@
2381_GL_FUNCDECL_SYS (trunc, double, (double x)); 2458_GL_FUNCDECL_SYS (trunc, double, (double x), );
2382# endif 2459# endif
2383_GL_CXXALIAS_SYS (trunc, double, (double x)); 2460_GL_CXXALIAS_SYS (trunc, double, (double x));
2384# endif 2461# endif
@@ -2399,11 +2476,11 @@ _GL_WARN_ON_USE (trunc, "trunc is unportable - "
2399# undef truncl 2476# undef truncl
2400# define truncl rpl_truncl 2477# define truncl rpl_truncl
2401# endif 2478# endif
2402_GL_FUNCDECL_RPL (truncl, long double, (long double x)); 2479_GL_FUNCDECL_RPL (truncl, long double, (long double x), );
2403_GL_CXXALIAS_RPL (truncl, long double, (long double x)); 2480_GL_CXXALIAS_RPL (truncl, long double, (long double x));
2404# else 2481# else
2405# if !@HAVE_DECL_TRUNCL@ 2482# if !@HAVE_DECL_TRUNCL@
2406_GL_FUNCDECL_SYS (truncl, long double, (long double x)); 2483_GL_FUNCDECL_SYS (truncl, long double, (long double x), );
2407# endif 2484# endif
2408_GL_CXXALIAS_SYS (truncl, long double, (long double x)); 2485_GL_CXXALIAS_SYS (truncl, long double, (long double x));
2409# endif 2486# endif
@@ -2487,7 +2564,7 @@ _GL_EXTERN_C int gl_isfinitel (long double x);
2487# if defined isfinite || defined GNULIB_NAMESPACE 2564# if defined isfinite || defined GNULIB_NAMESPACE
2488_GL_MATH_CXX_REAL_FLOATING_DECL_1 (isfinite) 2565_GL_MATH_CXX_REAL_FLOATING_DECL_1 (isfinite)
2489# undef isfinite 2566# undef isfinite
2490# if __GNUC__ >= 6 || (defined __clang__ && !((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __OpenBSD__ || defined _AIX || (defined _WIN32 && !defined __CYGWIN__))) 2567# if __GNUC__ >= 6 || (defined __clang__ && (__clang_major__ >= 19 || !((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __OpenBSD__ || defined _AIX || (defined _WIN32 && !defined __CYGWIN__))))
2491 /* This platform's <cmath> possibly defines isfinite through a set of inline 2568 /* This platform's <cmath> possibly defines isfinite through a set of inline
2492 functions. */ 2569 functions. */
2493_GL_MATH_CXX_REAL_FLOATING_DECL_2 (isfinite, rpl_isfinite, bool) 2570_GL_MATH_CXX_REAL_FLOATING_DECL_2 (isfinite, rpl_isfinite, bool)
@@ -2557,7 +2634,7 @@ _GL_EXTERN_C int isnanf (float x);
2557 GCC >= 4.0 also provides __builtin_isnanf, but clang doesn't. */ 2634 GCC >= 4.0 also provides __builtin_isnanf, but clang doesn't. */
2558# undef isnanf 2635# undef isnanf
2559# define isnanf(x) __builtin_isnan ((float)(x)) 2636# define isnanf(x) __builtin_isnan ((float)(x))
2560# elif defined isnan 2637# elif defined isnan && !defined HAVE_ISNANF_NOLIBM
2561# undef isnanf 2638# undef isnanf
2562# define isnanf(x) isnan ((float)(x)) 2639# define isnanf(x) isnan ((float)(x))
2563# endif 2640# endif
@@ -2586,7 +2663,7 @@ _GL_EXTERN_C int isnand (double x);
2586 /* GCC >= 4.0 and clang provide a type-generic built-in for isnan. */ 2663 /* GCC >= 4.0 and clang provide a type-generic built-in for isnan. */
2587# undef isnand 2664# undef isnand
2588# define isnand(x) __builtin_isnan ((double)(x)) 2665# define isnand(x) __builtin_isnan ((double)(x))
2589# else 2666# elif !defined HAVE_ISNAND_NOLIBM
2590# undef isnand 2667# undef isnand
2591# define isnand(x) isnan ((double)(x)) 2668# define isnand(x) isnan ((double)(x))
2592# endif 2669# endif
@@ -2609,7 +2686,7 @@ _GL_EXTERN_C int isnand (double x);
2609 GCC >= 4.0 also provides __builtin_isnanl, but clang doesn't. */ 2686 GCC >= 4.0 also provides __builtin_isnanl, but clang doesn't. */
2610# undef isnanl 2687# undef isnanl
2611# define isnanl(x) __builtin_isnan ((long double)(x)) 2688# define isnanl(x) __builtin_isnan ((long double)(x))
2612# elif defined isnan 2689# elif defined isnan && !defined HAVE_ISNANL_NOLIBM
2613# undef isnanl 2690# undef isnanl
2614# define isnanl(x) isnan ((long double)(x)) 2691# define isnanl(x) isnan ((long double)(x))
2615# endif 2692# endif
@@ -2754,7 +2831,7 @@ _GL_EXTERN_C int gl_signbitl (long double arg);
2754# if defined signbit || defined GNULIB_NAMESPACE 2831# if defined signbit || defined GNULIB_NAMESPACE
2755_GL_MATH_CXX_REAL_FLOATING_DECL_1 (signbit) 2832_GL_MATH_CXX_REAL_FLOATING_DECL_1 (signbit)
2756# undef signbit 2833# undef signbit
2757# if __GNUC__ >= 6 || (defined __clang__ && !((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __OpenBSD__ || defined _AIX || (defined _WIN32 && !defined __CYGWIN__))) 2834# if __cplusplus >= 201103L || __GNUC__ >= 6 || (defined __clang__ && !((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __OpenBSD__ || defined _AIX || (defined _WIN32 && !defined __CYGWIN__)))
2758 /* This platform's <cmath> possibly defines signbit through a set of inline 2835 /* This platform's <cmath> possibly defines signbit through a set of inline
2759 functions. */ 2836 functions. */
2760_GL_MATH_CXX_REAL_FLOATING_DECL_2 (signbit, rpl_signbit, bool) 2837_GL_MATH_CXX_REAL_FLOATING_DECL_2 (signbit, rpl_signbit, bool)
@@ -2780,11 +2857,11 @@ _GL_WARN_REAL_FLOATING_DECL (signbit);
2780# undef getpayloadf 2857# undef getpayloadf
2781# define getpayloadf rpl_getpayloadf 2858# define getpayloadf rpl_getpayloadf
2782# endif 2859# endif
2783_GL_FUNCDECL_RPL (getpayloadf, float, (const float *)); 2860_GL_FUNCDECL_RPL (getpayloadf, float, (const float *), );
2784_GL_CXXALIAS_RPL (getpayloadf, float, (const float *)); 2861_GL_CXXALIAS_RPL (getpayloadf, float, (const float *));
2785# else 2862# else
2786# if !@HAVE_GETPAYLOADF@ 2863# if !@HAVE_GETPAYLOADF@
2787_GL_FUNCDECL_SYS (getpayloadf, float, (const float *)); 2864_GL_FUNCDECL_SYS (getpayloadf, float, (const float *), );
2788# endif 2865# endif
2789_GL_CXXALIAS_SYS (getpayloadf, float, (const float *)); 2866_GL_CXXALIAS_SYS (getpayloadf, float, (const float *));
2790# endif 2867# endif
@@ -2803,11 +2880,11 @@ _GL_WARN_ON_USE (getpayloadf, "getpayloadf is unportable - "
2803# undef getpayload 2880# undef getpayload
2804# define getpayload rpl_getpayload 2881# define getpayload rpl_getpayload
2805# endif 2882# endif
2806_GL_FUNCDECL_RPL (getpayload, double, (const double *)); 2883_GL_FUNCDECL_RPL (getpayload, double, (const double *), );
2807_GL_CXXALIAS_RPL (getpayload, double, (const double *)); 2884_GL_CXXALIAS_RPL (getpayload, double, (const double *));
2808# else 2885# else
2809# if !@HAVE_GETPAYLOAD@ 2886# if !@HAVE_GETPAYLOAD@
2810_GL_FUNCDECL_SYS (getpayload, double, (const double *)); 2887_GL_FUNCDECL_SYS (getpayload, double, (const double *), );
2811# endif 2888# endif
2812_GL_CXXALIAS_SYS (getpayload, double, (const double *)); 2889_GL_CXXALIAS_SYS (getpayload, double, (const double *));
2813# endif 2890# endif
@@ -2826,11 +2903,11 @@ _GL_WARN_ON_USE (getpayload, "getpayload is unportable - "
2826# undef getpayloadl 2903# undef getpayloadl
2827# define getpayloadl rpl_getpayloadl 2904# define getpayloadl rpl_getpayloadl
2828# endif 2905# endif
2829_GL_FUNCDECL_RPL (getpayloadl, long double, (const long double *)); 2906_GL_FUNCDECL_RPL (getpayloadl, long double, (const long double *), );
2830_GL_CXXALIAS_RPL (getpayloadl, long double, (const long double *)); 2907_GL_CXXALIAS_RPL (getpayloadl, long double, (const long double *));
2831# else 2908# else
2832# if !@HAVE_GETPAYLOADL@ 2909# if !@HAVE_GETPAYLOADL@
2833_GL_FUNCDECL_SYS (getpayloadl, long double, (const long double *)); 2910_GL_FUNCDECL_SYS (getpayloadl, long double, (const long double *), );
2834# endif 2911# endif
2835_GL_CXXALIAS_SYS (getpayloadl, long double, (const long double *)); 2912_GL_CXXALIAS_SYS (getpayloadl, long double, (const long double *));
2836# endif 2913# endif
@@ -2846,7 +2923,7 @@ _GL_WARN_ON_USE (getpayloadl, "getpayloadl is unportable - "
2846 2923
2847#if @GNULIB_SETPAYLOADF@ 2924#if @GNULIB_SETPAYLOADF@
2848# if !@HAVE_SETPAYLOADF@ 2925# if !@HAVE_SETPAYLOADF@
2849_GL_FUNCDECL_SYS (setpayloadf, int, (float *, float)); 2926_GL_FUNCDECL_SYS (setpayloadf, int, (float *, float), );
2850# endif 2927# endif
2851_GL_CXXALIAS_SYS (setpayloadf, int, (float *, float)); 2928_GL_CXXALIAS_SYS (setpayloadf, int, (float *, float));
2852_GL_CXXALIASWARN (setpayloadf); 2929_GL_CXXALIASWARN (setpayloadf);
@@ -2860,7 +2937,7 @@ _GL_WARN_ON_USE (setpayloadf, "setpayloadf is unportable - "
2860 2937
2861#if @GNULIB_SETPAYLOAD@ 2938#if @GNULIB_SETPAYLOAD@
2862# if !@HAVE_SETPAYLOAD@ 2939# if !@HAVE_SETPAYLOAD@
2863_GL_FUNCDECL_SYS (setpayload, int, (double *, double)); 2940_GL_FUNCDECL_SYS (setpayload, int, (double *, double), );
2864# endif 2941# endif
2865_GL_CXXALIAS_SYS (setpayload, int, (double *, double)); 2942_GL_CXXALIAS_SYS (setpayload, int, (double *, double));
2866_GL_CXXALIASWARN (setpayload); 2943_GL_CXXALIASWARN (setpayload);
@@ -2874,7 +2951,7 @@ _GL_WARN_ON_USE (setpayload, "setpayload is unportable - "
2874 2951
2875#if @GNULIB_SETPAYLOADL@ 2952#if @GNULIB_SETPAYLOADL@
2876# if !@HAVE_SETPAYLOADL@ 2953# if !@HAVE_SETPAYLOADL@
2877_GL_FUNCDECL_SYS (setpayloadl, int, (long double *, long double)); 2954_GL_FUNCDECL_SYS (setpayloadl, int, (long double *, long double), );
2878# endif 2955# endif
2879_GL_CXXALIAS_SYS (setpayloadl, int, (long double *, long double)); 2956_GL_CXXALIAS_SYS (setpayloadl, int, (long double *, long double));
2880_GL_CXXALIASWARN (setpayloadl); 2957_GL_CXXALIASWARN (setpayloadl);
@@ -2889,7 +2966,7 @@ _GL_WARN_ON_USE (setpayloadl, "setpayloadl is unportable - "
2889 2966
2890#if @GNULIB_SETPAYLOADSIGF@ 2967#if @GNULIB_SETPAYLOADSIGF@
2891# if !@HAVE_SETPAYLOADSIGF@ 2968# if !@HAVE_SETPAYLOADSIGF@
2892_GL_FUNCDECL_SYS (setpayloadsigf, int, (float *, float)); 2969_GL_FUNCDECL_SYS (setpayloadsigf, int, (float *, float), );
2893# endif 2970# endif
2894_GL_CXXALIAS_SYS (setpayloadsigf, int, (float *, float)); 2971_GL_CXXALIAS_SYS (setpayloadsigf, int, (float *, float));
2895_GL_CXXALIASWARN (setpayloadsigf); 2972_GL_CXXALIASWARN (setpayloadsigf);
@@ -2903,7 +2980,7 @@ _GL_WARN_ON_USE (setpayloadsigf, "setpayloadsigf is unportable - "
2903 2980
2904#if @GNULIB_SETPAYLOADSIG@ 2981#if @GNULIB_SETPAYLOADSIG@
2905# if !@HAVE_SETPAYLOADSIG@ 2982# if !@HAVE_SETPAYLOADSIG@
2906_GL_FUNCDECL_SYS (setpayloadsig, int, (double *, double)); 2983_GL_FUNCDECL_SYS (setpayloadsig, int, (double *, double), );
2907# endif 2984# endif
2908_GL_CXXALIAS_SYS (setpayloadsig, int, (double *, double)); 2985_GL_CXXALIAS_SYS (setpayloadsig, int, (double *, double));
2909_GL_CXXALIASWARN (setpayloadsig); 2986_GL_CXXALIASWARN (setpayloadsig);
@@ -2917,7 +2994,7 @@ _GL_WARN_ON_USE (setpayloadsig, "setpayloadsig is unportable - "
2917 2994
2918#if @GNULIB_SETPAYLOADSIGL@ 2995#if @GNULIB_SETPAYLOADSIGL@
2919# if !@HAVE_SETPAYLOADSIGL@ 2996# if !@HAVE_SETPAYLOADSIGL@
2920_GL_FUNCDECL_SYS (setpayloadsigl, int, (long double *, long double)); 2997_GL_FUNCDECL_SYS (setpayloadsigl, int, (long double *, long double), );
2921# endif 2998# endif
2922_GL_CXXALIAS_SYS (setpayloadsigl, int, (long double *, long double)); 2999_GL_CXXALIAS_SYS (setpayloadsigl, int, (long double *, long double));
2923_GL_CXXALIASWARN (setpayloadsigl); 3000_GL_CXXALIASWARN (setpayloadsigl);
@@ -2936,11 +3013,11 @@ _GL_WARN_ON_USE (setpayloadsigl, "setpayloadsigl is unportable - "
2936# undef totalorderf 3013# undef totalorderf
2937# define totalorderf rpl_totalorderf 3014# define totalorderf rpl_totalorderf
2938# endif 3015# endif
2939_GL_FUNCDECL_RPL (totalorderf, int, (float const *, float const *)); 3016_GL_FUNCDECL_RPL (totalorderf, int, (float const *, float const *), );
2940_GL_CXXALIAS_RPL (totalorderf, int, (float const *, float const *)); 3017_GL_CXXALIAS_RPL (totalorderf, int, (float const *, float const *));
2941# else 3018# else
2942# if !@HAVE_TOTALORDERF@ 3019# if !@HAVE_TOTALORDERF@
2943_GL_FUNCDECL_SYS (totalorderf, int, (float const *, float const *)); 3020_GL_FUNCDECL_SYS (totalorderf, int, (float const *, float const *), );
2944# endif 3021# endif
2945_GL_CXXALIAS_SYS (totalorderf, int, (float const *, float const *)); 3022_GL_CXXALIAS_SYS (totalorderf, int, (float const *, float const *));
2946# endif 3023# endif
@@ -2959,11 +3036,11 @@ _GL_WARN_ON_USE (totalorderf, "totalorderf is unportable - "
2959# undef totalorder 3036# undef totalorder
2960# define totalorder rpl_totalorder 3037# define totalorder rpl_totalorder
2961# endif 3038# endif
2962_GL_FUNCDECL_RPL (totalorder, int, (double const *, double const *)); 3039_GL_FUNCDECL_RPL (totalorder, int, (double const *, double const *), );
2963_GL_CXXALIAS_RPL (totalorder, int, (double const *, double const *)); 3040_GL_CXXALIAS_RPL (totalorder, int, (double const *, double const *));
2964# else 3041# else
2965# if !@HAVE_TOTALORDER@ 3042# if !@HAVE_TOTALORDER@
2966_GL_FUNCDECL_SYS (totalorder, int, (double const *, double const *)); 3043_GL_FUNCDECL_SYS (totalorder, int, (double const *, double const *), );
2967# endif 3044# endif
2968_GL_CXXALIAS_SYS (totalorder, int, (double const *, double const *)); 3045_GL_CXXALIAS_SYS (totalorder, int, (double const *, double const *));
2969# endif 3046# endif
@@ -2985,13 +3062,13 @@ _GL_WARN_ON_USE (totalorder, "totalorder is unportable - "
2985# define totalorderl rpl_totalorderl 3062# define totalorderl rpl_totalorderl
2986# endif 3063# endif
2987_GL_FUNCDECL_RPL (totalorderl, int, 3064_GL_FUNCDECL_RPL (totalorderl, int,
2988 (long double const *, long double const *)); 3065 (long double const *, long double const *), );
2989_GL_CXXALIAS_RPL (totalorderl, int, 3066_GL_CXXALIAS_RPL (totalorderl, int,
2990 (long double const *, long double const *)); 3067 (long double const *, long double const *));
2991# else 3068# else
2992# if !@HAVE_TOTALORDERL@ 3069# if !@HAVE_TOTALORDERL@
2993_GL_FUNCDECL_SYS (totalorderl, int, 3070_GL_FUNCDECL_SYS (totalorderl, int,
2994 (long double const *, long double const *)); 3071 (long double const *, long double const *), );
2995# endif 3072# endif
2996_GL_CXXALIAS_SYS (totalorderl, int, 3073_GL_CXXALIAS_SYS (totalorderl, int,
2997 (long double const *, long double const *)); 3074 (long double const *, long double const *));
@@ -3012,11 +3089,11 @@ _GL_WARN_ON_USE (totalorderl, "totalorderl is unportable - "
3012# undef totalordermagf 3089# undef totalordermagf
3013# define totalordermagf rpl_totalordermagf 3090# define totalordermagf rpl_totalordermagf
3014# endif 3091# endif
3015_GL_FUNCDECL_RPL (totalordermagf, int, (float const *, float const *)); 3092_GL_FUNCDECL_RPL (totalordermagf, int, (float const *, float const *), );
3016_GL_CXXALIAS_RPL (totalordermagf, int, (float const *, float const *)); 3093_GL_CXXALIAS_RPL (totalordermagf, int, (float const *, float const *));
3017# else 3094# else
3018# if !@HAVE_TOTALORDERMAGF@ 3095# if !@HAVE_TOTALORDERMAGF@
3019_GL_FUNCDECL_SYS (totalordermagf, int, (float const *, float const *)); 3096_GL_FUNCDECL_SYS (totalordermagf, int, (float const *, float const *), );
3020# endif 3097# endif
3021_GL_CXXALIAS_SYS (totalordermagf, int, (float const *, float const *)); 3098_GL_CXXALIAS_SYS (totalordermagf, int, (float const *, float const *));
3022# endif 3099# endif
@@ -3037,11 +3114,11 @@ _GL_WARN_ON_USE (totalordermagf, "totalordermagf is unportable - "
3037# undef totalordermag 3114# undef totalordermag
3038# define totalordermag rpl_totalordermag 3115# define totalordermag rpl_totalordermag
3039# endif 3116# endif
3040_GL_FUNCDECL_RPL (totalordermag, int, (double const *, double const *)); 3117_GL_FUNCDECL_RPL (totalordermag, int, (double const *, double const *), );
3041_GL_CXXALIAS_RPL (totalordermag, int, (double const *, double const *)); 3118_GL_CXXALIAS_RPL (totalordermag, int, (double const *, double const *));
3042# else 3119# else
3043# if !@HAVE_TOTALORDERMAG@ 3120# if !@HAVE_TOTALORDERMAG@
3044_GL_FUNCDECL_SYS (totalordermag, int, (double const *, double const *)); 3121_GL_FUNCDECL_SYS (totalordermag, int, (double const *, double const *), );
3045# endif 3122# endif
3046_GL_CXXALIAS_SYS (totalordermag, int, (double const *, double const *)); 3123_GL_CXXALIAS_SYS (totalordermag, int, (double const *, double const *));
3047# endif 3124# endif
@@ -3063,13 +3140,13 @@ _GL_WARN_ON_USE (totalordermag, "totalordermag is unportable - "
3063# define totalordermagl rpl_totalordermagl 3140# define totalordermagl rpl_totalordermagl
3064# endif 3141# endif
3065_GL_FUNCDECL_RPL (totalordermagl, int, 3142_GL_FUNCDECL_RPL (totalordermagl, int,
3066 (long double const *, long double const *)); 3143 (long double const *, long double const *), );
3067_GL_CXXALIAS_RPL (totalordermagl, int, 3144_GL_CXXALIAS_RPL (totalordermagl, int,
3068 (long double const *, long double const *)); 3145 (long double const *, long double const *));
3069# else 3146# else
3070# if !@HAVE_TOTALORDERMAGL@ 3147# if !@HAVE_TOTALORDERMAGL@
3071_GL_FUNCDECL_SYS (totalordermagl, int, 3148_GL_FUNCDECL_SYS (totalordermagl, int,
3072 (long double const *, long double const *)); 3149 (long double const *, long double const *), );
3073# endif 3150# endif
3074_GL_CXXALIAS_SYS (totalordermagl, int, 3151_GL_CXXALIAS_SYS (totalordermagl, int,
3075 (long double const *, long double const *)); 3152 (long double const *, long double const *));
diff --git a/gl/mbchar.c b/gl/mbchar.c
new file mode 100644
index 00000000..713c2f74
--- /dev/null
+++ b/gl/mbchar.c
@@ -0,0 +1,23 @@
1/* Copyright (C) 2001, 2006, 2009-2025 Free Software Foundation, Inc.
2
3 This file is free software: you can redistribute it and/or modify
4 it under the terms of the GNU Lesser General Public License as
5 published by the Free Software Foundation; either version 2.1 of the
6 License, or (at your option) any later version.
7
8 This file is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU Lesser General Public License for more details.
12
13 You should have received a copy of the GNU Lesser General Public License
14 along with this program. If not, see <https://www.gnu.org/licenses/>. */
15
16
17#include <config.h>
18
19#define MBCHAR_INLINE _GL_EXTERN_INLINE
20
21#include <limits.h>
22
23#include "mbchar.h"
diff --git a/gl/mbchar.h b/gl/mbchar.h
new file mode 100644
index 00000000..d77168e7
--- /dev/null
+++ b/gl/mbchar.h
@@ -0,0 +1,383 @@
1/* Multibyte character data type.
2 Copyright (C) 2001, 2005-2007, 2009-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17/* Written by Bruno Haible <bruno@clisp.org>. */
18
19/* A multibyte character is a short subsequence of a char* string,
20 representing a single 32-bit wide character.
21
22 We use multibyte characters instead of 32-bit wide characters because
23 of the following goals:
24 1) correct multibyte handling, i.e. operate according to the LC_CTYPE
25 locale,
26 2) ease of maintenance, i.e. the maintainer needs not know all details
27 of the ISO C 99 standard,
28 3) don't fail grossly if the input is not in the encoding set by the
29 locale, because often different encodings are in use in the same
30 countries (ISO-8859-1/UTF-8, EUC-JP/Shift_JIS, ...),
31 4) fast in the case of ASCII characters.
32
33 Multibyte characters are only accessed through the mb* macros.
34
35 mb_ptr (mbc)
36 return a pointer to the beginning of the multibyte sequence.
37
38 mb_len (mbc)
39 returns the number of bytes occupied by the multibyte sequence.
40 Always > 0.
41
42 mb_iseq (mbc, sc)
43 returns true if mbc is the standard ASCII character sc.
44
45 mb_isnul (mbc)
46 returns true if mbc is the nul character.
47
48 mb_cmp (mbc1, mbc2)
49 returns a positive, zero, or negative value depending on whether mbc1
50 sorts after, same or before mbc2.
51
52 mb_casecmp (mbc1, mbc2)
53 returns a positive, zero, or negative value depending on whether mbc1
54 sorts after, same or before mbc2, modulo upper/lowercase conversion.
55
56 mb_equal (mbc1, mbc2)
57 returns true if mbc1 and mbc2 are equal.
58
59 mb_caseequal (mbc1, mbc2)
60 returns true if mbc1 and mbc2 are equal modulo upper/lowercase conversion.
61
62 mb_isalnum (mbc)
63 returns true if mbc is alphanumeric.
64
65 mb_isalpha (mbc)
66 returns true if mbc is alphabetic.
67
68 mb_isascii(mbc)
69 returns true if mbc is plain ASCII.
70
71 mb_isblank (mbc)
72 returns true if mbc is a blank.
73
74 mb_iscntrl (mbc)
75 returns true if mbc is a control character.
76
77 mb_isdigit (mbc)
78 returns true if mbc is a decimal digit.
79
80 mb_isgraph (mbc)
81 returns true if mbc is a graphic character.
82
83 mb_islower (mbc)
84 returns true if mbc is lowercase.
85
86 mb_isprint (mbc)
87 returns true if mbc is a printable character.
88
89 mb_ispunct (mbc)
90 returns true if mbc is a punctuation character.
91
92 mb_isspace (mbc)
93 returns true if mbc is a space character.
94
95 mb_isupper (mbc)
96 returns true if mbc is uppercase.
97
98 mb_isxdigit (mbc)
99 returns true if mbc is a hexadecimal digit.
100
101 mb_width (mbc)
102 returns the number of columns on the output device occupied by mbc.
103 Always >= 0.
104
105 mb_putc (mbc, stream)
106 outputs mbc on stream, a byte oriented FILE stream opened for output.
107
108 mb_setascii (&mbc, sc)
109 assigns the standard ASCII character sc to mbc.
110 (Only available if the 'mbfile' module is in use.)
111
112 mb_copy (&destmbc, &srcmbc)
113 copies srcmbc to destmbc.
114
115 Here are the function prototypes of the macros.
116
117 extern const char * mb_ptr (const mbchar_t mbc);
118 extern size_t mb_len (const mbchar_t mbc);
119 extern bool mb_iseq (const mbchar_t mbc, char sc);
120 extern bool mb_isnul (const mbchar_t mbc);
121 extern int mb_cmp (const mbchar_t mbc1, const mbchar_t mbc2);
122 extern int mb_casecmp (const mbchar_t mbc1, const mbchar_t mbc2);
123 extern bool mb_equal (const mbchar_t mbc1, const mbchar_t mbc2);
124 extern bool mb_caseequal (const mbchar_t mbc1, const mbchar_t mbc2);
125 extern bool mb_isalnum (const mbchar_t mbc);
126 extern bool mb_isalpha (const mbchar_t mbc);
127 extern bool mb_isascii (const mbchar_t mbc);
128 extern bool mb_isblank (const mbchar_t mbc);
129 extern bool mb_iscntrl (const mbchar_t mbc);
130 extern bool mb_isdigit (const mbchar_t mbc);
131 extern bool mb_isgraph (const mbchar_t mbc);
132 extern bool mb_islower (const mbchar_t mbc);
133 extern bool mb_isprint (const mbchar_t mbc);
134 extern bool mb_ispunct (const mbchar_t mbc);
135 extern bool mb_isspace (const mbchar_t mbc);
136 extern bool mb_isupper (const mbchar_t mbc);
137 extern bool mb_isxdigit (const mbchar_t mbc);
138 extern int mb_width (const mbchar_t mbc);
139 extern void mb_putc (const mbchar_t mbc, FILE *stream);
140 extern void mb_setascii (mbchar_t *new, char sc);
141 extern void mb_copy (mbchar_t *new, const mbchar_t *old);
142 */
143
144#ifndef _MBCHAR_H
145#define _MBCHAR_H 1
146
147/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE. */
148#if !_GL_CONFIG_H_INCLUDED
149 #error "Please include config.h first."
150#endif
151
152#include <string.h>
153#include <uchar.h>
154
155_GL_INLINE_HEADER_BEGIN
156#ifndef MBCHAR_INLINE
157# define MBCHAR_INLINE _GL_INLINE
158#endif
159
160#ifdef __cplusplus
161extern "C" {
162#endif
163
164
165/* The longest multibyte characters, nowadays, are 4 bytes long.
166 Regardless of the values of MB_CUR_MAX and MB_LEN_MAX. */
167#define MBCHAR_BUF_SIZE 4
168
169struct mbchar
170{
171 const char *ptr; /* pointer to current character */
172 size_t bytes; /* number of bytes of current character, > 0 */
173 bool wc_valid; /* true if wc is a valid 32-bit wide character */
174 char32_t wc; /* if wc_valid: the current character */
175#if defined GNULIB_MBFILE
176 char buf[MBCHAR_BUF_SIZE]; /* room for the bytes, used for file input only */
177#endif
178};
179
180/* EOF (not a real character) is represented with bytes = 0 and
181 wc_valid = false. */
182
183typedef struct mbchar mbchar_t;
184
185/* Access the current character. */
186#define mb_ptr(mbc) ((mbc).ptr)
187#define mb_len(mbc) ((mbc).bytes)
188
189/* Comparison of characters. */
190#define mb_iseq(mbc, sc) ((mbc).wc_valid && (mbc).wc == (sc))
191#define mb_isnul(mbc) ((mbc).wc_valid && (mbc).wc == 0)
192#define mb_cmp(mbc1, mbc2) \
193 ((mbc1).wc_valid \
194 ? ((mbc2).wc_valid \
195 ? _GL_CMP ((mbc1).wc, (mbc2).wc) \
196 : -1) \
197 : ((mbc2).wc_valid \
198 ? 1 \
199 : (mbc1).bytes == (mbc2).bytes \
200 ? memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) \
201 : (mbc1).bytes < (mbc2).bytes \
202 ? (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) > 0 ? 1 : -1) \
203 : (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc2).bytes) >= 0 ? 1 : -1)))
204#define mb_casecmp(mbc1, mbc2) \
205 ((mbc1).wc_valid \
206 ? ((mbc2).wc_valid \
207 ? _GL_CMP (c32tolower ((mbc1).wc), c32tolower ((mbc2).wc)) \
208 : -1) \
209 : ((mbc2).wc_valid \
210 ? 1 \
211 : (mbc1).bytes == (mbc2).bytes \
212 ? memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) \
213 : (mbc1).bytes < (mbc2).bytes \
214 ? (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) > 0 ? 1 : -1) \
215 : (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc2).bytes) >= 0 ? 1 : -1)))
216#define mb_equal(mbc1, mbc2) \
217 ((mbc1).wc_valid && (mbc2).wc_valid \
218 ? (mbc1).wc == (mbc2).wc \
219 : (mbc1).bytes == (mbc2).bytes \
220 && memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) == 0)
221#define mb_caseequal(mbc1, mbc2) \
222 ((mbc1).wc_valid && (mbc2).wc_valid \
223 ? c32tolower ((mbc1).wc) == c32tolower ((mbc2).wc) \
224 : (mbc1).bytes == (mbc2).bytes \
225 && memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) == 0)
226
227/* <ctype.h>, <wctype.h> classification. */
228#define mb_isascii(mbc) \
229 ((mbc).wc_valid && (mbc).wc >= 0 && (mbc).wc <= 127)
230#define mb_isalnum(mbc) ((mbc).wc_valid && c32isalnum ((mbc).wc))
231#define mb_isalpha(mbc) ((mbc).wc_valid && c32isalpha ((mbc).wc))
232#define mb_isblank(mbc) ((mbc).wc_valid && c32isblank ((mbc).wc))
233#define mb_iscntrl(mbc) ((mbc).wc_valid && c32iscntrl ((mbc).wc))
234#define mb_isdigit(mbc) ((mbc).wc_valid && c32isdigit ((mbc).wc))
235#define mb_isgraph(mbc) ((mbc).wc_valid && c32isgraph ((mbc).wc))
236#define mb_islower(mbc) ((mbc).wc_valid && c32islower ((mbc).wc))
237#define mb_isprint(mbc) ((mbc).wc_valid && c32isprint ((mbc).wc))
238#define mb_ispunct(mbc) ((mbc).wc_valid && c32ispunct ((mbc).wc))
239#define mb_isspace(mbc) ((mbc).wc_valid && c32isspace ((mbc).wc))
240#define mb_isupper(mbc) ((mbc).wc_valid && c32isupper ((mbc).wc))
241#define mb_isxdigit(mbc) ((mbc).wc_valid && c32isxdigit ((mbc).wc))
242
243/* Extra <wchar.h> function. */
244
245/* Unprintable characters appear as a small box of width 1. */
246#define MB_UNPRINTABLE_WIDTH 1
247
248MBCHAR_INLINE int
249mb_width_aux (char32_t wc)
250{
251 int w = c32width (wc);
252 /* For unprintable characters, arbitrarily return 0 for control characters
253 and MB_UNPRINTABLE_WIDTH otherwise. */
254 return (w >= 0 ? w : c32iscntrl (wc) ? 0 : MB_UNPRINTABLE_WIDTH);
255}
256
257#define mb_width(mbc) \
258 ((mbc).wc_valid ? mb_width_aux ((mbc).wc) : MB_UNPRINTABLE_WIDTH)
259
260/* Output. */
261#define mb_putc(mbc, stream) fwrite ((mbc).ptr, 1, (mbc).bytes, (stream))
262
263#if defined GNULIB_MBFILE
264/* Assignment. */
265# define mb_setascii(mbc, sc) \
266 ((mbc)->ptr = (mbc)->buf, (mbc)->bytes = 1, (mbc)->wc_valid = 1, \
267 (mbc)->wc = (mbc)->buf[0] = (sc))
268#endif
269
270/* Copying a character. */
271MBCHAR_INLINE void
272mb_copy (mbchar_t *new_mbc, const mbchar_t *old_mbc)
273{
274#if defined GNULIB_MBFILE
275 if (old_mbc->ptr == &old_mbc->buf[0])
276 {
277 memcpy (&new_mbc->buf[0], &old_mbc->buf[0], old_mbc->bytes);
278 new_mbc->ptr = &new_mbc->buf[0];
279 }
280 else
281#endif
282 new_mbc->ptr = old_mbc->ptr;
283 new_mbc->bytes = old_mbc->bytes;
284 if ((new_mbc->wc_valid = old_mbc->wc_valid))
285 new_mbc->wc = old_mbc->wc;
286}
287
288
289/* is_basic(c) tests whether the single-byte character c is
290 - in the ISO C "basic character set" or is one of '@', '$', and '`'
291 which ISO C 23 § 5.2.1.1.(1) guarantees to be single-byte and in
292 practice are safe to treat as basic in the execution character set,
293 or
294 - in the POSIX "portable character set", which
295 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap06.html>
296 equally guarantees to be single-byte.
297 This is a convenience function, and is in this file only to share code
298 between mbiter.h, mbuiter.h, and mbfile.h. */
299#if (' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
300 && ('$' == 36) && ('%' == 37) && ('&' == 38) && ('\'' == 39) \
301 && ('(' == 40) && (')' == 41) && ('*' == 42) && ('+' == 43) \
302 && (',' == 44) && ('-' == 45) && ('.' == 46) && ('/' == 47) \
303 && ('0' == 48) && ('1' == 49) && ('2' == 50) && ('3' == 51) \
304 && ('4' == 52) && ('5' == 53) && ('6' == 54) && ('7' == 55) \
305 && ('8' == 56) && ('9' == 57) && (':' == 58) && (';' == 59) \
306 && ('<' == 60) && ('=' == 61) && ('>' == 62) && ('?' == 63) \
307 && ('@' == 64) && ('A' == 65) && ('B' == 66) && ('C' == 67) \
308 && ('D' == 68) && ('E' == 69) && ('F' == 70) && ('G' == 71) \
309 && ('H' == 72) && ('I' == 73) && ('J' == 74) && ('K' == 75) \
310 && ('L' == 76) && ('M' == 77) && ('N' == 78) && ('O' == 79) \
311 && ('P' == 80) && ('Q' == 81) && ('R' == 82) && ('S' == 83) \
312 && ('T' == 84) && ('U' == 85) && ('V' == 86) && ('W' == 87) \
313 && ('X' == 88) && ('Y' == 89) && ('Z' == 90) && ('[' == 91) \
314 && ('\\' == 92) && (']' == 93) && ('^' == 94) && ('_' == 95) \
315 && ('`' == 96) && ('a' == 97) && ('b' == 98) && ('c' == 99) \
316 && ('d' == 100) && ('e' == 101) && ('f' == 102) && ('g' == 103) \
317 && ('h' == 104) && ('i' == 105) && ('j' == 106) && ('k' == 107) \
318 && ('l' == 108) && ('m' == 109) && ('n' == 110) && ('o' == 111) \
319 && ('p' == 112) && ('q' == 113) && ('r' == 114) && ('s' == 115) \
320 && ('t' == 116) && ('u' == 117) && ('v' == 118) && ('w' == 119) \
321 && ('x' == 120) && ('y' == 121) && ('z' == 122) && ('{' == 123) \
322 && ('|' == 124) && ('}' == 125) && ('~' == 126)
323/* The character set is ISO-646, not EBCDIC. */
324# define IS_BASIC_ASCII 1
325
326/* All locale encodings (see localcharset.h) map the characters 0x00..0x7F
327 to U+0000..U+007F, like ASCII, except for
328 CP864 different mapping of '%'
329 SHIFT_JIS different mappings of 0x5C, 0x7E
330 JOHAB different mapping of 0x5C
331 However, these characters in the range 0x20..0x7E are in the ISO C
332 "basic character set" and in the POSIX "portable character set", which
333 ISO C and POSIX guarantee to be single-byte. Thus, locales with these
334 encodings are not POSIX compliant. And they are most likely not in use
335 any more (as of 2023). */
336# define is_basic(c) ((unsigned char) (c) < 0x80)
337
338#else
339
340MBCHAR_INLINE bool
341is_basic (char c)
342{
343 switch (c)
344 {
345 case '\0':
346 case '\007': case '\010':
347 case '\t': case '\n': case '\v': case '\f': case '\r':
348 case ' ': case '!': case '"': case '#': case '$': case '%':
349 case '&': case '\'': case '(': case ')': case '*':
350 case '+': case ',': case '-': case '.': case '/':
351 case '0': case '1': case '2': case '3': case '4':
352 case '5': case '6': case '7': case '8': case '9':
353 case ':': case ';': case '<': case '=': case '>':
354 case '?': case '@':
355 case 'A': case 'B': case 'C': case 'D': case 'E':
356 case 'F': case 'G': case 'H': case 'I': case 'J':
357 case 'K': case 'L': case 'M': case 'N': case 'O':
358 case 'P': case 'Q': case 'R': case 'S': case 'T':
359 case 'U': case 'V': case 'W': case 'X': case 'Y':
360 case 'Z':
361 case '[': case '\\': case ']': case '^': case '_': case '`':
362 case 'a': case 'b': case 'c': case 'd': case 'e':
363 case 'f': case 'g': case 'h': case 'i': case 'j':
364 case 'k': case 'l': case 'm': case 'n': case 'o':
365 case 'p': case 'q': case 'r': case 's': case 't':
366 case 'u': case 'v': case 'w': case 'x': case 'y':
367 case 'z': case '{': case '|': case '}': case '~':
368 return 1;
369 default:
370 return 0;
371 }
372}
373
374#endif
375
376
377#ifdef __cplusplus
378}
379#endif
380
381_GL_INLINE_HEADER_END
382
383#endif /* _MBCHAR_H */
diff --git a/gl/mbiterf.c b/gl/mbiterf.c
new file mode 100644
index 00000000..ad354c55
--- /dev/null
+++ b/gl/mbiterf.c
@@ -0,0 +1,21 @@
1/* Iterating through multibyte strings: macros for multi-byte encodings.
2
3 Copyright (C) 2023-2025 Free Software Foundation, Inc.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20#define MBITERF_INLINE _GL_EXTERN_INLINE
21#include "mbiterf.h"
diff --git a/gl/mbiterf.h b/gl/mbiterf.h
new file mode 100644
index 00000000..99d8d11d
--- /dev/null
+++ b/gl/mbiterf.h
@@ -0,0 +1,214 @@
1/* Iterating through multibyte strings, faster: macros for multi-byte encodings.
2 Copyright (C) 2001, 2005, 2007, 2009-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17/* Written by Bruno Haible <bruno@clisp.org>,
18 with insights from Paul Eggert. */
19
20/* The macros in this file implement forward iteration through a
21 multi-byte string.
22
23 With these macros, an iteration loop that looks like
24
25 char *iter;
26 for (iter = buf; iter < buf + buflen; iter++)
27 {
28 do_something (*iter);
29 }
30
31 becomes
32
33 const char *buf_end = buf + buflen;
34 mbif_state_t state;
35 [const] char *iter;
36 for (mbif_init (state), iter = buf; mbif_avail (state, iter, buf_end); )
37 {
38 mbchar_t cur = mbif_next (state, iter, buf_end);
39 // Note: Here always mb_ptr (cur) == iter.
40 do_something (iter, mb_len (cur));
41 iter += mb_len (cur);
42 }
43
44 The benefit of these macros over plain use of mbrtowc or mbrtoc32 is:
45 - Handling of invalid multibyte sequences is possible without
46 making the code more complicated, while still preserving the
47 invalid multibyte sequences.
48
49 The benefit of these macros over those from mbiter.h is that it
50 produces faster code with today's optimizing compilers (because mbif_next
51 returns its result by value).
52
53 mbif_state_t
54 is a type usable for variable declarations.
55
56 mbif_init (state)
57 initializes the state.
58
59 mbif_avail (state, iter, endptr)
60 returns true if another loop round is needed.
61
62 mbif_next (state, iter, endptr)
63 returns the next multibyte character.
64 It asssumes that the state is initialized and that iter < endptr.
65
66 Here are the function prototypes of the macros.
67
68 extern void mbif_init (mbif_state_t state);
69 extern bool mbif_avail (mbif_state_t state, const char *iter, const char *endptr);
70 extern mbchar_t mbif_next (mbif_state_t state, const char *iter, const char *endptr);
71 */
72
73#ifndef _MBITERF_H
74#define _MBITERF_H 1
75
76/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE,
77 _GL_ATTRIBUTE_ALWAYS_INLINE. */
78#if !_GL_CONFIG_H_INCLUDED
79 #error "Please include config.h first."
80#endif
81
82#include <assert.h>
83#include <stddef.h>
84#include <string.h>
85#include <uchar.h>
86#include <wchar.h>
87
88#include "mbchar.h"
89
90_GL_INLINE_HEADER_BEGIN
91#ifndef MBITERF_INLINE
92# define MBITERF_INLINE _GL_INLINE _GL_ATTRIBUTE_ALWAYS_INLINE
93#endif
94
95#ifdef __cplusplus
96extern "C" {
97#endif
98
99
100struct mbif_state
101{
102 #if !GNULIB_MBRTOC32_REGULAR
103 bool in_shift; /* true if next byte may not be interpreted as ASCII */
104 /* If GNULIB_MBRTOC32_REGULAR, it is always false,
105 so optimize it away. */
106 #endif
107 mbstate_t state; /* if in_shift: current shift state */
108 /* If GNULIB_MBRTOC32_REGULAR, it is in an initial state
109 before and after every mbiterf_next invocation.
110 */
111};
112
113MBITERF_INLINE mbchar_t
114mbiterf_next (struct mbif_state *ps, const char *iter, const char *endptr)
115{
116 #if !GNULIB_MBRTOC32_REGULAR
117 if (ps->in_shift)
118 goto with_shift;
119 #endif
120 /* Handle most ASCII characters quickly, without calling mbrtowc(). */
121 if (is_basic (*iter))
122 {
123 /* These characters are part of the POSIX portable character set.
124 For most of them, namely those in the ISO C basic character set,
125 ISO C 99 guarantees that their wide character code is identical to
126 their char code. For the few other ones, this is the case as well,
127 in all locale encodings that are in use. The 32-bit wide character
128 code is the same as well. */
129 return (mbchar_t) { .ptr = iter, .bytes = 1, .wc_valid = true, .wc = *iter };
130 }
131 else
132 {
133 assert (mbsinit (&ps->state));
134 #if !GNULIB_MBRTOC32_REGULAR
135 ps->in_shift = true;
136 with_shift:;
137 #endif
138 size_t bytes;
139 char32_t wc;
140 bytes = mbrtoc32 (&wc, iter, endptr - iter, &ps->state);
141 if (bytes == (size_t) -1)
142 {
143 /* An invalid multibyte sequence was encountered. */
144 /* Allow the next invocation to continue from a sane state. */
145 #if !GNULIB_MBRTOC32_REGULAR
146 ps->in_shift = false;
147 #endif
148 mbszero (&ps->state);
149 return (mbchar_t) { .ptr = iter, .bytes = 1, .wc_valid = false };
150 }
151 else if (bytes == (size_t) -2)
152 {
153 /* An incomplete multibyte character at the end. */
154 #if !GNULIB_MBRTOC32_REGULAR
155 ps->in_shift = false;
156 #endif
157 /* Whether to reset ps->state or not is not important; the string end
158 is reached anyway. */
159 return (mbchar_t) { .ptr = iter, .bytes = endptr - iter, .wc_valid = false };
160 }
161 else
162 {
163 if (bytes == 0)
164 {
165 /* A null wide character was encountered. */
166 bytes = 1;
167 assert (*iter == '\0');
168 assert (wc == 0);
169 }
170 #if !GNULIB_MBRTOC32_REGULAR
171 else if (bytes == (size_t) -3)
172 /* The previous multibyte sequence produced an additional 32-bit
173 wide character. */
174 bytes = 0;
175 #endif
176
177 /* When in an initial state, we can go back treating ASCII
178 characters more quickly. */
179 #if !GNULIB_MBRTOC32_REGULAR
180 if (mbsinit (&ps->state))
181 ps->in_shift = false;
182 #endif
183 return (mbchar_t) { .ptr = iter, .bytes = bytes, .wc_valid = true, .wc = wc };
184 }
185 }
186}
187
188/* Iteration macros. */
189typedef struct mbif_state mbif_state_t;
190#if !GNULIB_MBRTOC32_REGULAR
191#define mbif_init(st) \
192 ((st).in_shift = false, mbszero (&(st).state))
193#else
194/* Optimized: no in_shift. */
195#define mbif_init(st) \
196 (mbszero (&(st).state))
197#endif
198#if !GNULIB_MBRTOC32_REGULAR
199#define mbif_avail(st, iter, endptr) ((st).in_shift || ((iter) < (endptr)))
200#else
201/* Optimized: no in_shift. */
202#define mbif_avail(st, iter, endptr) ((iter) < (endptr))
203#endif
204#define mbif_next(st, iter, endptr) \
205 mbiterf_next (&(st), (iter), (endptr))
206
207
208#ifdef __cplusplus
209}
210#endif
211
212_GL_INLINE_HEADER_END
213
214#endif /* _MBITERF_H */
diff --git a/gl/mbrtoc32.c b/gl/mbrtoc32.c
new file mode 100644
index 00000000..c4625525
--- /dev/null
+++ b/gl/mbrtoc32.c
@@ -0,0 +1,288 @@
1/* Convert multibyte character to 32-bit wide character.
2 Copyright (C) 2020-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17/* Written by Bruno Haible <bruno@clisp.org>, 2020. */
18
19#include <config.h>
20
21/* Specification. */
22#include <uchar.h>
23
24#include "attribute.h"
25
26#include <errno.h>
27#include <stdlib.h>
28
29#if GL_CHAR32_T_IS_UNICODE
30# include "lc-charset-unicode.h"
31#endif
32
33#if GNULIB_defined_mbstate_t /* AIX, IRIX */
34/* Implement mbrtoc32() on top of mbtowc() for the non-UTF-8 locales
35 and directly for the UTF-8 locales. */
36
37/* Note: On AIX (64-bit) we can implement mbrtoc32 in two equivalent ways:
38 - in a way that parallels the override of mbrtowc; this is the code branch
39 here;
40 - in a way that invokes the overridden mbrtowc; this would be the #else
41 branch below.
42 They are equivalent. */
43
44# if AVOID_ANY_THREADS
45
46/* The option '--disable-threads' explicitly requests no locking. */
47
48# elif defined _WIN32 && !defined __CYGWIN__
49
50# define WIN32_LEAN_AND_MEAN /* avoid including junk */
51# include <windows.h>
52
53# elif HAVE_PTHREAD_API
54
55# include <pthread.h>
56# if HAVE_THREADS_H && HAVE_WEAK_SYMBOLS
57# include <threads.h>
58# pragma weak thrd_exit
59# define c11_threads_in_use() (thrd_exit != NULL)
60# else
61# define c11_threads_in_use() 0
62# endif
63
64# elif HAVE_THREADS_H
65
66# include <threads.h>
67
68# endif
69
70# include "lc-charset-dispatch.h"
71# include "mbtowc-lock.h"
72
73static_assert (sizeof (mbstate_t) >= 4);
74static char internal_state[4];
75
76size_t
77mbrtoc32 (char32_t *pwc, const char *s, size_t n, mbstate_t *ps)
78{
79# define FITS_IN_CHAR_TYPE(wc) 1
80# include "mbrtowc-impl.h"
81}
82
83#else /* glibc, macOS, FreeBSD, NetBSD, OpenBSD, HP-UX, Solaris, Cygwin, mingw, MSVC, Minix, Android */
84
85/* Implement mbrtoc32() based on the original mbrtoc32() or on mbrtowc(). */
86
87# include <wchar.h>
88
89# include "localcharset.h"
90# include "streq.h"
91
92# if MBRTOC32_IN_C_LOCALE_MAYBE_EILSEQ
93# include "hard-locale.h"
94# include <locale.h>
95# endif
96
97static mbstate_t internal_state;
98
99size_t
100mbrtoc32 (char32_t *pwc, const char *s, size_t n, mbstate_t *ps)
101# undef mbrtoc32
102{
103 /* It's simpler to handle the case s == NULL upfront, than to worry about
104 this case later, before every test of pwc and n. */
105 if (s == NULL)
106 {
107 pwc = NULL;
108 s = "";
109 n = 1;
110 }
111
112# if MBRTOC32_EMPTY_INPUT_BUG || _GL_SMALL_WCHAR_T
113 if (n == 0)
114 return (size_t) -2;
115# endif
116
117 if (ps == NULL)
118 ps = &internal_state;
119
120# if HAVE_WORKING_MBRTOC32 && HAVE_WORKING_C32RTOMB && !MBRTOC32_MULTIBYTE_LOCALE_BUG
121 /* mbrtoc32() may produce different values for wc than mbrtowc(). Therefore
122 use mbrtoc32(). */
123
124# if defined _WIN32 && !defined __CYGWIN__
125 char32_t wc;
126 size_t ret = mbrtoc32 (&wc, s, n, ps);
127 if (ret < (size_t) -2 && pwc != NULL)
128 *pwc = wc;
129# else
130 size_t ret = mbrtoc32 (pwc, s, n, ps);
131# endif
132
133# if GNULIB_MBRTOC32_REGULAR
134 /* Verify that mbrtoc32 is regular. */
135 if (ret < (size_t) -3 && ! mbsinit (ps))
136 /* This occurs on glibc 2.36. */
137 mbszero (ps);
138 if (ret == (size_t) -3)
139 abort ();
140# endif
141
142# if MBRTOC32_IN_C_LOCALE_MAYBE_EILSEQ
143 if ((size_t) -2 <= ret && n != 0 && ! hard_locale (LC_CTYPE))
144 {
145 if (pwc != NULL)
146 *pwc = (unsigned char) *s;
147 return 1;
148 }
149# endif
150
151 return ret;
152
153# elif _GL_SMALL_WCHAR_T
154
155 /* Special-case all encodings that may produce wide character values
156 > WCHAR_MAX. */
157 const char *encoding = locale_charset ();
158 if (STREQ_OPT (encoding, "UTF-8", 'U', 'T', 'F', '-', '8', 0, 0, 0, 0))
159 {
160 /* Special-case the UTF-8 encoding. Assume that the wide-character
161 encoding in a UTF-8 locale is UCS-2 or, equivalently, UTF-16. */
162 /* Here n > 0. */
163 char *pstate = (char *)ps;
164 size_t nstate = pstate[0];
165 char buf[4];
166 const char *p;
167 size_t m;
168 int res;
169
170 switch (nstate)
171 {
172 case 0:
173 p = s;
174 m = n;
175 break;
176 case 3:
177 buf[2] = pstate[3];
178 FALLTHROUGH;
179 case 2:
180 buf[1] = pstate[2];
181 FALLTHROUGH;
182 case 1:
183 buf[0] = pstate[1];
184 p = buf;
185 m = nstate;
186 buf[m++] = s[0];
187 if (n >= 2 && m < 4)
188 {
189 buf[m++] = s[1];
190 if (n >= 3 && m < 4)
191 buf[m++] = s[2];
192 }
193 break;
194 default:
195 errno = EINVAL;
196 return (size_t)(-1);
197 }
198
199 /* Here m > 0. */
200
201 {
202# define FITS_IN_CHAR_TYPE(wc) 1
203# include "mbrtowc-impl-utf8.h"
204 }
205
206 success:
207 if (nstate >= (res > 0 ? res : 1))
208 abort ();
209 res -= nstate;
210 /* Set *ps to an initial state. */
211# if defined _WIN32 && !defined __CYGWIN__
212 /* Native Windows. */
213 /* MSVC defines 'mbstate_t' as an 8-byte struct; the first 4 bytes matter.
214 On mingw, 'mbstate_t' is sometimes defined as 'int', sometimes defined
215 as an 8-byte struct, of which the first 4 bytes matter. */
216 *(unsigned int *)pstate = 0;
217# elif defined __CYGWIN__
218 /* Cygwin defines 'mbstate_t' as an 8-byte struct; the first 4 bytes
219 matter. */
220 ps->__count = 0;
221# else
222 pstate[0] = 0;
223# endif
224 return res;
225
226 incomplete:
227 {
228 size_t k = nstate;
229 /* Here 0 <= k < m < 4. */
230 pstate[++k] = s[0];
231 if (k < m)
232 {
233 pstate[++k] = s[1];
234 if (k < m)
235 pstate[++k] = s[2];
236 }
237 if (k != m)
238 abort ();
239 }
240 pstate[0] = m;
241 return (size_t)(-2);
242
243 invalid:
244 errno = EILSEQ;
245 /* The conversion state is undefined, says POSIX. */
246 return (size_t)(-1);
247 }
248 else
249 {
250 wchar_t wc;
251 size_t ret = mbrtowc (&wc, s, n, ps);
252 if (ret < (size_t) -2 && pwc != NULL)
253 *pwc = wc;
254 return ret;
255 }
256
257# else
258
259 /* char32_t and wchar_t are equivalent. Use mbrtowc(). */
260 wchar_t wc;
261 size_t ret = mbrtowc (&wc, s, n, ps);
262
263# if GNULIB_MBRTOC32_REGULAR
264 /* Ensure that mbrtoc32 is regular. */
265 if (ret < (size_t) -2 && ! mbsinit (ps))
266 /* This occurs on glibc 2.12. */
267 mbszero (ps);
268# endif
269
270# if GL_CHAR32_T_IS_UNICODE && GL_CHAR32_T_VS_WCHAR_T_NEEDS_CONVERSION
271 if (ret < (size_t) -2 && wc != 0)
272 {
273 wc = locale_encoding_to_unicode (wc);
274 if (wc == 0)
275 {
276 ret = (size_t) -1;
277 errno = EILSEQ;
278 }
279 }
280# endif
281 if (ret < (size_t) -2 && pwc != NULL)
282 *pwc = wc;
283 return ret;
284
285# endif
286}
287
288#endif
diff --git a/gl/mbrtowc-impl-utf8.h b/gl/mbrtowc-impl-utf8.h
index 3a3ba13c..98858e22 100644
--- a/gl/mbrtowc-impl-utf8.h
+++ b/gl/mbrtowc-impl-utf8.h
@@ -1,5 +1,5 @@
1/* Convert multibyte character to wide character. 1/* Convert multibyte character to wide character.
2 Copyright (C) 1999-2002, 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 1999-2002, 2005-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/mbrtowc-impl.h b/gl/mbrtowc-impl.h
index 963631ca..61be6599 100644
--- a/gl/mbrtowc-impl.h
+++ b/gl/mbrtowc-impl.h
@@ -1,5 +1,5 @@
1/* Convert multibyte character to wide character. 1/* Convert multibyte character to wide character.
2 Copyright (C) 1999-2002, 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 1999-2002, 2005-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/mbrtowc.c b/gl/mbrtowc.c
index 8a1646d2..6f0aa129 100644
--- a/gl/mbrtowc.c
+++ b/gl/mbrtowc.c
@@ -1,5 +1,5 @@
1/* Convert multibyte character to wide character. 1/* Convert multibyte character to wide character.
2 Copyright (C) 1999-2002, 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 1999-2002, 2005-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2008. 3 Written by Bruno Haible <bruno@clisp.org>, 2008.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/mbsinit.c b/gl/mbsinit.c
index d1b8475c..2df30b32 100644
--- a/gl/mbsinit.c
+++ b/gl/mbsinit.c
@@ -1,5 +1,5 @@
1/* Test for initial conversion state. 1/* Test for initial conversion state.
2 Copyright (C) 2008-2024 Free Software Foundation, Inc. 2 Copyright (C) 2008-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2008. 3 Written by Bruno Haible <bruno@clisp.org>, 2008.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/mbsnlen.c b/gl/mbsnlen.c
new file mode 100644
index 00000000..9c25465a
--- /dev/null
+++ b/gl/mbsnlen.c
@@ -0,0 +1,60 @@
1/* Counting the multibyte characters in a string.
2 Copyright (C) 2007-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2007.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include <string.h>
22
23#include <stdlib.h>
24
25#if GNULIB_MCEL_PREFER
26# include "mcel.h"
27#else
28# include "mbiterf.h"
29#endif
30
31/* Return the number of multibyte characters in the character string starting
32 at STRING and ending at STRING + LEN. */
33size_t
34mbsnlen (const char *string, size_t len)
35{
36 if (MB_CUR_MAX > 1)
37 {
38 size_t count = 0;
39
40 const char *string_end = string + len;
41
42#if GNULIB_MCEL_PREFER
43 for (; string < string_end; string += mcel_scan (string, string_end).len)
44 count++;
45#else
46 mbif_state_t state;
47 const char *iter;
48 for (mbif_init (state), iter = string; mbif_avail (state, iter, string_end); )
49 {
50 mbchar_t cur = mbif_next (state, iter, string_end);
51 count++;
52 iter += mb_len (cur);
53 }
54#endif
55
56 return count;
57 }
58 else
59 return len;
60}
diff --git a/gl/mbszero.c b/gl/mbszero.c
index 25af2848..36fc9200 100644
--- a/gl/mbszero.c
+++ b/gl/mbszero.c
@@ -1,5 +1,5 @@
1/* Put an mbstate_t into an initial conversion state. 1/* Put an mbstate_t into an initial conversion state.
2 Copyright (C) 2023-2024 Free Software Foundation, Inc. 2 Copyright (C) 2023-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/mbtowc-impl.h b/gl/mbtowc-impl.h
index 92efb4a7..3366c9da 100644
--- a/gl/mbtowc-impl.h
+++ b/gl/mbtowc-impl.h
@@ -1,5 +1,5 @@
1/* Convert multibyte character to wide character. 1/* Convert multibyte character to wide character.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 2 Copyright (C) 2011-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2011. 3 Written by Bruno Haible <bruno@clisp.org>, 2011.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/mbtowc-lock.c b/gl/mbtowc-lock.c
index 9001c5af..e350608b 100644
--- a/gl/mbtowc-lock.c
+++ b/gl/mbtowc-lock.c
@@ -1,5 +1,5 @@
1/* Return the internal lock used by mbrtowc and mbrtoc32. 1/* Return the internal lock used by mbrtowc and mbrtoc32.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc. 2 Copyright (C) 2019-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/mbtowc-lock.h b/gl/mbtowc-lock.h
index 10f7dc7c..500f74cc 100644
--- a/gl/mbtowc-lock.h
+++ b/gl/mbtowc-lock.h
@@ -1,5 +1,5 @@
1/* Use the internal lock used by mbrtowc and mbrtoc32. 1/* Use the internal lock used by mbrtowc and mbrtoc32.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc. 2 Copyright (C) 2019-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/mbtowc.c b/gl/mbtowc.c
index 31a2d635..27ff35c6 100644
--- a/gl/mbtowc.c
+++ b/gl/mbtowc.c
@@ -1,5 +1,5 @@
1/* Convert multibyte character to wide character. 1/* Convert multibyte character to wide character.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 2 Copyright (C) 2011-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2011. 3 Written by Bruno Haible <bruno@clisp.org>, 2011.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/memchr.c b/gl/memchr.c
index 67687a8f..ef0d15f7 100644
--- a/gl/memchr.c
+++ b/gl/memchr.c
@@ -1,4 +1,4 @@
1/* Copyright (C) 1991, 1993, 1996-1997, 1999-2000, 2003-2004, 2006, 2008-2024 1/* Copyright (C) 1991, 1993, 1996-1997, 1999-2000, 2003-2004, 2006, 2008-2025
2 Free Software Foundation, Inc. 2 Free Software Foundation, Inc.
3 3
4 Based on strlen implementation by Torbjorn Granlund (tege@sics.se), 4 Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
diff --git a/gl/memchr.valgrind b/gl/memchr.valgrind
index 0295d7e6..8e55c207 100644
--- a/gl/memchr.valgrind
+++ b/gl/memchr.valgrind
@@ -1,6 +1,6 @@
1# Suppress a valgrind message about use of uninitialized memory in memchr(). 1# Suppress a valgrind message about use of uninitialized memory in memchr().
2 2
3# Copyright (C) 2009-2024 Free Software Foundation, Inc. 3# Copyright (C) 2009-2025 Free Software Foundation, Inc.
4# 4#
5# This file is free software: you can redistribute it and/or modify 5# This file is free software: you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License as 6# it under the terms of the GNU Lesser General Public License as
diff --git a/gl/minmax.h b/gl/minmax.h
index f3df58b0..355de4b1 100644
--- a/gl/minmax.h
+++ b/gl/minmax.h
@@ -1,5 +1,5 @@
1/* MIN, MAX macros. 1/* MIN, MAX macros.
2 Copyright (C) 1995, 1998, 2001, 2003, 2005, 2009-2024 Free Software 2 Copyright (C) 1995, 1998, 2001, 2003, 2005, 2009-2025 Free Software
3 Foundation, Inc. 3 Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/mktime-internal.h b/gl/mktime-internal.h
index 0693aaf1..215be914 100644
--- a/gl/mktime-internal.h
+++ b/gl/mktime-internal.h
@@ -1,5 +1,5 @@
1/* Internals of mktime and related functions 1/* Internals of mktime and related functions
2 Copyright 2016-2024 Free Software Foundation, Inc. 2 Copyright 2016-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 Contributed by Paul Eggert <eggert@cs.ucla.edu>. 4 Contributed by Paul Eggert <eggert@cs.ucla.edu>.
5 5
@@ -19,6 +19,9 @@
19 19
20#ifndef _LIBC 20#ifndef _LIBC
21# include <time.h> 21# include <time.h>
22# define __libc_lock_lock(lock) ((void) 0)
23# define __libc_lock_unlock(lock) ((void) 0)
24# define __tzset_unlocked() tzset ()
22#endif 25#endif
23 26
24/* mktime_offset_t is a signed type wide enough to hold a UTC offset 27/* mktime_offset_t is a signed type wide enough to hold a UTC offset
@@ -71,9 +74,10 @@ typedef int mktime_offset_t;
71#endif 74#endif
72 75
73/* Subroutine of mktime. Return the time_t representation of TP and 76/* Subroutine of mktime. Return the time_t representation of TP and
74 normalize TP, given that a struct tm * maps to a time_t as performed 77 normalize TP, given that a struct tm * maps to a time_t. If
75 by FUNC. Record next guess for localtime-gmtime offset in *OFFSET. */ 78 LOCAL, the mapping is performed by localtime_r, otherwise by gmtime_r.
76extern __time64_t __mktime_internal (struct tm *tp, 79 Record next guess for localtime-gmtime offset in *OFFSET.
77 struct tm *(*func) (__time64_t const *, 80
78 struct tm *), 81 If _LIBC, the caller must lock __tzset_lock. */
82extern __time64_t __mktime_internal (struct tm *tp, bool local,
79 mktime_offset_t *offset) attribute_hidden; 83 mktime_offset_t *offset) attribute_hidden;
diff --git a/gl/mktime.c b/gl/mktime.c
index c704f415..4218fca6 100644
--- a/gl/mktime.c
+++ b/gl/mktime.c
@@ -1,5 +1,5 @@
1/* Convert a 'struct tm' to a time_t value. 1/* Convert a 'struct tm' to a time_t value.
2 Copyright (C) 1993-2024 Free Software Foundation, Inc. 2 Copyright (C) 1993-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 Contributed by Paul Eggert <eggert@twinsun.com>. 4 Contributed by Paul Eggert <eggert@twinsun.com>.
5 5
@@ -51,7 +51,6 @@
51#include <string.h> 51#include <string.h>
52 52
53#include <intprops.h> 53#include <intprops.h>
54#include <verify.h>
55 54
56#ifndef NEED_MKTIME_INTERNAL 55#ifndef NEED_MKTIME_INTERNAL
57# define NEED_MKTIME_INTERNAL 0 56# define NEED_MKTIME_INTERNAL 0
@@ -63,6 +62,9 @@
63# define NEED_MKTIME_WORKING 0 62# define NEED_MKTIME_WORKING 0
64#endif 63#endif
65 64
65#ifdef _LIBC
66# include <tzset.h>
67#endif
66#include "mktime-internal.h" 68#include "mktime-internal.h"
67 69
68#if !defined _LIBC && (NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS) 70#if !defined _LIBC && (NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS)
@@ -99,8 +101,8 @@ my_tzset (void)
99 tzset (); 101 tzset ();
100# endif 102# endif
101} 103}
102# undef __tzset 104# undef tzset
103# define __tzset() my_tzset () 105# define tzset() my_tzset ()
104#endif 106#endif
105 107
106#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL 108#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL
@@ -119,12 +121,12 @@ my_tzset (void)
119 __time64_t values that mktime can generate even on platforms where 121 __time64_t values that mktime can generate even on platforms where
120 __time64_t is wider than the int components of struct tm. */ 122 __time64_t is wider than the int components of struct tm. */
121 123
122#if INT_MAX <= LONG_MAX / 4 / 366 / 24 / 60 / 60 124# if INT_MAX <= LONG_MAX / 4 / 366 / 24 / 60 / 60
123typedef long int long_int; 125typedef long int long_int;
124#else 126# else
125typedef long long int long_int; 127typedef long long int long_int;
126#endif 128# endif
127verify (INT_MAX <= TYPE_MAXIMUM (long_int) / 4 / 366 / 24 / 60 / 60); 129static_assert (INT_MAX <= TYPE_MAXIMUM (long_int) / 4 / 366 / 24 / 60 / 60);
128 130
129/* Shift A right by B bits portably, by dividing A by 2**B and 131/* Shift A right by B bits portably, by dividing A by 2**B and
130 truncating towards minus infinity. B should be in the range 0 <= B 132 truncating towards minus infinity. B should be in the range 0 <= B
@@ -155,9 +157,9 @@ static long_int const mktime_max
155 = (TYPE_MAXIMUM (long_int) < TYPE_MAXIMUM (__time64_t) 157 = (TYPE_MAXIMUM (long_int) < TYPE_MAXIMUM (__time64_t)
156 ? TYPE_MAXIMUM (long_int) : TYPE_MAXIMUM (__time64_t)); 158 ? TYPE_MAXIMUM (long_int) : TYPE_MAXIMUM (__time64_t));
157 159
158#define EPOCH_YEAR 1970 160# define EPOCH_YEAR 1970
159#define TM_YEAR_BASE 1900 161# define TM_YEAR_BASE 1900
160verify (TM_YEAR_BASE % 100 == 0); 162static_assert (TM_YEAR_BASE % 100 == 0);
161 163
162/* Is YEAR + TM_YEAR_BASE a leap year? */ 164/* Is YEAR + TM_YEAR_BASE a leap year? */
163static bool 165static bool
@@ -172,9 +174,9 @@ leapyear (long_int year)
172} 174}
173 175
174/* How many days come before each month (0-12). */ 176/* How many days come before each month (0-12). */
175#ifndef _LIBC 177# ifndef _LIBC
176static 178static
177#endif 179# endif
178const unsigned short int __mon_yday[2][13] = 180const unsigned short int __mon_yday[2][13] =
179 { 181 {
180 /* Normal years. */ 182 /* Normal years. */
@@ -206,7 +208,7 @@ static long_int
206ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1, 208ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1,
207 int year0, int yday0, int hour0, int min0, int sec0) 209 int year0, int yday0, int hour0, int min0, int sec0)
208{ 210{
209 verify (-1 / 2 == 0); 211 static_assert (-1 / 2 == 0);
210 212
211 /* Compute intervening leap days correctly even if year is negative. 213 /* Compute intervening leap days correctly even if year is negative.
212 Take care to avoid integer overflow here. */ 214 Take care to avoid integer overflow here. */
@@ -251,29 +253,34 @@ tm_diff (long_int year, long_int yday, int hour, int min, int sec,
251 tp->tm_hour, tp->tm_min, tp->tm_sec); 253 tp->tm_hour, tp->tm_min, tp->tm_sec);
252} 254}
253 255
254/* Use CONVERT to convert T to a struct tm value in *TM. T must be in 256#ifndef _LIBC
255 range for __time64_t. Return TM if successful, NULL (setting errno) on 257/* Convert T to a struct tm value in *TM. Use localtime64_r if LOCAL,
256 failure. */ 258 otherwise gmtime64_r. T must be in range for __time64_t. Return
259 TM if successful, NULL (setting errno) on failure. */
257static struct tm * 260static struct tm *
258convert_time (struct tm *(*convert) (const __time64_t *, struct tm *), 261convert_time (long_int t, bool local, struct tm *tm)
259 long_int t, struct tm *tm)
260{ 262{
261 __time64_t x = t; 263 __time64_t x = t;
262 return convert (&x, tm); 264 if (local)
265 return __localtime64_r (&x, tm);
266 else
267 return __gmtime64_r (&x, tm);
263} 268}
269# define __tz_convert convert_time
270#endif
264 271
265/* Use CONVERT to convert *T to a broken down time in *TP. 272/* Convert *T to a broken down time in *TP (as if by localtime if
266 If *T is out of range for conversion, adjust it so that 273 LOCAL, otherwise as if by gmtime). If *T is out of range for
267 it is the nearest in-range value and then convert that. 274 conversion, adjust it so that it is the nearest in-range value and
268 A value is in range if it fits in both __time64_t and long_int. 275 then convert that. A value is in range if it fits in both
269 Return TP on success, NULL (setting errno) on failure. */ 276 __time64_t and long_int. Return TP on success, NULL (setting
277 errno) on failure. */
270static struct tm * 278static struct tm *
271ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *), 279ranged_convert (bool local, long_int *t, struct tm *tp)
272 long_int *t, struct tm *tp)
273{ 280{
274 long_int t1 = (*t < mktime_min ? mktime_min 281 long_int t1 = (*t < mktime_min ? mktime_min
275 : *t <= mktime_max ? *t : mktime_max); 282 : *t <= mktime_max ? *t : mktime_max);
276 struct tm *r = convert_time (convert, t1, tp); 283 struct tm *r = __tz_convert (t1, local, tp);
277 if (r) 284 if (r)
278 { 285 {
279 *t = t1; 286 *t = t1;
@@ -294,7 +301,7 @@ ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *),
294 long_int mid = long_int_avg (ok, bad); 301 long_int mid = long_int_avg (ok, bad);
295 if (mid == ok || mid == bad) 302 if (mid == ok || mid == bad)
296 break; 303 break;
297 if (convert_time (convert, mid, tp)) 304 if (__tz_convert (mid, local, tp))
298 ok = mid, oktm = *tp; 305 ok = mid, oktm = *tp;
299 else if (errno != EOVERFLOW) 306 else if (errno != EOVERFLOW)
300 return NULL; 307 return NULL;
@@ -310,29 +317,38 @@ ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *),
310} 317}
311 318
312 319
313/* Convert *TP to a __time64_t value, inverting 320/* Convert *TP to a __time64_t value. If LOCAL, the reverse mapping
314 the monotonic and mostly-unit-linear conversion function CONVERT. 321 is performed as if localtime, otherwise as if by gmtime. Use
315 Use *OFFSET to keep track of a guess at the offset of the result, 322 *OFFSET to keep track of a guess at the offset of the result,
316 compared to what the result would be for UTC without leap seconds. 323 compared to what the result would be for UTC without leap seconds.
317 If *OFFSET's guess is correct, only one CONVERT call is needed. 324 If *OFFSET's guess is correct, only one reverse mapping call is
318 If successful, set *TP to the canonicalized struct tm; 325 needed. If successful, set *TP to the canonicalized struct tm;
319 otherwise leave *TP alone, return ((time_t) -1) and set errno. 326 otherwise leave *TP alone, return ((time_t) -1) and set errno.
320 This function is external because it is used also by timegm.c. */ 327 This function is external because it is used also by timegm.c.
328
329 If _LIBC, the caller must lock __tzset_lock. */
321__time64_t 330__time64_t
322__mktime_internal (struct tm *tp, 331__mktime_internal (struct tm *tp, bool local, mktime_offset_t *offset)
323 struct tm *(*convert) (const __time64_t *, struct tm *),
324 mktime_offset_t *offset)
325{ 332{
326 struct tm tm; 333 struct tm tm;
327 334
328 /* The maximum number of probes (calls to CONVERT) should be enough 335 /* The maximum number of probes should be enough to handle any
329 to handle any combinations of time zone rule changes, solar time, 336 combinations of time zone rule changes, solar time, leap seconds,
330 leap seconds, and oscillations around a spring-forward gap. 337 and oscillations around a spring-forward gap. POSIX.1 prohibits
331 POSIX.1 prohibits leap seconds, but some hosts have them anyway. */ 338 leap seconds, but some hosts have them anyway. */
332 int remaining_probes = 6; 339 int remaining_probes = 6;
333 340
334 /* Time requested. Copy it in case CONVERT modifies *TP; this can 341#ifndef _LIBC
335 occur if TP is localtime's returned value and CONVERT is localtime. */ 342 /* Gnulib mktime doesn't lock the tz state, so it may need to probe
343 more often if some other thread changes local time while
344 __mktime_internal is probing. Double the number of probes; this
345 should suffice for practical cases that are at all likely. */
346 remaining_probes *= 2;
347#endif
348
349 /* Time requested. Copy it in case gmtime/localtime modify *TP;
350 this can occur if TP is localtime's returned value and CONVERT is
351 localtime. */
336 int sec = tp->tm_sec; 352 int sec = tp->tm_sec;
337 int min = tp->tm_min; 353 int min = tp->tm_min;
338 int hour = tp->tm_hour; 354 int hour = tp->tm_hour;
@@ -341,8 +357,8 @@ __mktime_internal (struct tm *tp,
341 int year_requested = tp->tm_year; 357 int year_requested = tp->tm_year;
342 int isdst = tp->tm_isdst; 358 int isdst = tp->tm_isdst;
343 359
344 /* 1 if the previous probe was DST. */ 360 /* True if the previous probe was DST. */
345 int dst2 = 0; 361 bool dst2 = false;
346 362
347 /* Ensure that mon is in range, and set year accordingly. */ 363 /* Ensure that mon is in range, and set year accordingly. */
348 int mon_remainder = mon % 12; 364 int mon_remainder = mon % 12;
@@ -390,7 +406,7 @@ __mktime_internal (struct tm *tp,
390 406
391 while (true) 407 while (true)
392 { 408 {
393 if (! ranged_convert (convert, &t, &tm)) 409 if (! ranged_convert (local, &t, &tm))
394 return -1; 410 return -1;
395 long_int dt = tm_diff (year, yday, hour, min, sec, &tm); 411 long_int dt = tm_diff (year, yday, hour, min, sec, &tm);
396 if (dt == 0) 412 if (dt == 0)
@@ -431,13 +447,10 @@ __mktime_internal (struct tm *tp,
431 447
432 Heuristic: probe the adjacent timestamps in both directions, 448 Heuristic: probe the adjacent timestamps in both directions,
433 looking for the desired isdst. If none is found within a 449 looking for the desired isdst. If none is found within a
434 reasonable duration bound, assume a one-hour DST difference. 450 reasonable duration bound, ignore the disagreement.
435 This should work for all real time zone histories in the tz 451 This should work for all real time zone histories in the tz
436 database. */ 452 database. */
437 453
438 /* +1 if we wanted standard time but got DST, -1 if the reverse. */
439 int dst_difference = (isdst == 0) - (tm.tm_isdst == 0);
440
441 /* Distance between probes when looking for a DST boundary. In 454 /* Distance between probes when looking for a DST boundary. In
442 tzdata2003a, the shortest period of DST is 601200 seconds 455 tzdata2003a, the shortest period of DST is 601200 seconds
443 (e.g., America/Recife starting 2000-10-08 01:00), and the 456 (e.g., America/Recife starting 2000-10-08 01:00), and the
@@ -447,21 +460,17 @@ __mktime_internal (struct tm *tp,
447 periods when probing. */ 460 periods when probing. */
448 int stride = 601200; 461 int stride = 601200;
449 462
450 /* In TZDB 2021e, the longest period of DST (or of non-DST), in 463 /* Do not probe too far away from the requested time,
451 which the DST (or adjacent DST) difference is not one hour, 464 by striding until at least a year has passed, but then giving up.
452 is 457243209 seconds: e.g., America/Cambridge_Bay with leap 465 This helps avoid unexpected results in (for example) Asia/Kolkata,
453 seconds, starting 1965-10-31 00:00 in a switch from 466 for which today's users expect to see no DST even though it
454 double-daylight time (-05) to standard time (-07), and 467 did observe DST long ago. */
455 continuing to 1980-04-27 02:00 in a switch from standard time 468 int year_seconds_bound = 366 * 24 * 60 * 60 + 1;
456 (-07) to daylight time (-06). */ 469 int delta_bound = year_seconds_bound + stride;
457 int duration_max = 457243209;
458
459 /* Search in both directions, so the maximum distance is half
460 the duration; add the stride to avoid off-by-1 problems. */
461 int delta_bound = duration_max / 2 + stride;
462 470
463 int delta, direction; 471 int delta, direction;
464 472
473 /* Search in both directions, closest first. */
465 for (delta = stride; delta < delta_bound; delta += stride) 474 for (delta = stride; delta < delta_bound; delta += stride)
466 for (direction = -1; direction <= 1; direction += 2) 475 for (direction = -1; direction <= 1; direction += 2)
467 { 476 {
@@ -469,7 +478,7 @@ __mktime_internal (struct tm *tp,
469 if (! ckd_add (&ot, t, delta * direction)) 478 if (! ckd_add (&ot, t, delta * direction))
470 { 479 {
471 struct tm otm; 480 struct tm otm;
472 if (! ranged_convert (convert, &ot, &otm)) 481 if (! ranged_convert (local, &ot, &otm))
473 return -1; 482 return -1;
474 if (! isdst_differ (isdst, otm.tm_isdst)) 483 if (! isdst_differ (isdst, otm.tm_isdst))
475 { 484 {
@@ -479,7 +488,7 @@ __mktime_internal (struct tm *tp,
479 &otm); 488 &otm);
480 if (mktime_min <= gt && gt <= mktime_max) 489 if (mktime_min <= gt && gt <= mktime_max)
481 { 490 {
482 if (convert_time (convert, gt, &tm)) 491 if (__tz_convert (gt, local, &tm))
483 { 492 {
484 t = gt; 493 t = gt;
485 goto offset_found; 494 goto offset_found;
@@ -491,13 +500,8 @@ __mktime_internal (struct tm *tp,
491 } 500 }
492 } 501 }
493 502
494 /* No unusual DST offset was found nearby. Assume one-hour DST. */ 503 /* No probe with the requested tm_isdst was found nearby.
495 t += 60 * 60 * dst_difference; 504 Ignore the requested tm_isdst. */
496 if (mktime_min <= t && t <= mktime_max && convert_time (convert, t, &tm))
497 goto offset_found;
498
499 __set_errno (EOVERFLOW);
500 return -1;
501 } 505 }
502 506
503 offset_found: 507 offset_found:
@@ -520,7 +524,7 @@ __mktime_internal (struct tm *tp,
520 __set_errno (EOVERFLOW); 524 __set_errno (EOVERFLOW);
521 return -1; 525 return -1;
522 } 526 }
523 if (! convert_time (convert, t, &tm)) 527 if (! __tz_convert (t, local, &tm))
524 return -1; 528 return -1;
525 } 529 }
526 530
@@ -536,18 +540,19 @@ __mktime_internal (struct tm *tp,
536__time64_t 540__time64_t
537__mktime64 (struct tm *tp) 541__mktime64 (struct tm *tp)
538{ 542{
539 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the 543 __libc_lock_lock (__tzset_lock);
540 time zone names contained in the external variable 'tzname' shall 544 __tzset_unlocked ();
541 be set as if the tzset() function had been called. */
542 __tzset ();
543 545
544# if defined _LIBC || NEED_MKTIME_WORKING 546# if defined _LIBC || NEED_MKTIME_WORKING
545 static mktime_offset_t localtime_offset; 547 static mktime_offset_t localtime_offset;
546 return __mktime_internal (tp, __localtime64_r, &localtime_offset); 548 __time64_t result = __mktime_internal (tp, true, &localtime_offset);
547# else 549# else
548# undef mktime 550# undef mktime
549 return mktime (tp); 551 __time64_t result = mktime (tp);
550# endif 552# endif
553
554 __libc_lock_unlock (__tzset_lock);
555 return result;
551} 556}
552#endif /* _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS */ 557#endif /* _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS */
553 558
diff --git a/gl/mountlist.c b/gl/mountlist.c
index 06300d6b..dcff6f83 100644
--- a/gl/mountlist.c
+++ b/gl/mountlist.c
@@ -1,6 +1,6 @@
1/* mountlist.c -- return a list of mounted file systems 1/* mountlist.c -- return a list of mounted file systems
2 2
3 Copyright (C) 1991-1992, 1997-2024 Free Software Foundation, Inc. 3 Copyright (C) 1991-1992, 1997-2025 Free Software Foundation, Inc.
4 4
5 This program is free software: you can redistribute it and/or modify 5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
@@ -19,20 +19,18 @@
19 19
20#include "mountlist.h" 20#include "mountlist.h"
21 21
22#include <errno.h>
23#include <fcntl.h>
22#include <limits.h> 24#include <limits.h>
23#include <stdio.h> 25#include <stdio.h>
24#include <stdlib.h> 26#include <stdlib.h>
25#include <string.h> 27#include <string.h>
26#include <stdint.h> 28#include <stdint.h>
29#include <unistd.h>
27 30
31#include "c-ctype.h"
28#include "xalloc.h" 32#include "xalloc.h"
29 33
30#include <errno.h>
31
32#include <fcntl.h>
33
34#include <unistd.h>
35
36#if HAVE_SYS_PARAM_H 34#if HAVE_SYS_PARAM_H
37# include <sys/param.h> 35# include <sys/param.h>
38#endif 36#endif
@@ -132,6 +130,10 @@
132# endif 130# endif
133#endif 131#endif
134 132
133#if defined _WIN32 && !defined __CYGWIN__
134# include <windows.h>
135#endif
136
135#ifndef HAVE_HASMNTOPT 137#ifndef HAVE_HASMNTOPT
136# define hasmntopt(mnt, opt) ((char *) 0) 138# define hasmntopt(mnt, opt) ((char *) 0)
137#endif 139#endif
@@ -396,15 +398,18 @@ dev_from_mount_options (char const *mount_options)
396 if (devopt) 398 if (devopt)
397 { 399 {
398 char const *optval = devopt + sizeof dev_pattern - 1; 400 char const *optval = devopt + sizeof dev_pattern - 1;
399 char *optvalend; 401 if (c_isxdigit (*optval))
400 unsigned long int dev; 402 {
401 errno = 0; 403 char *optvalend;
402 dev = strtoul (optval, &optvalend, 16); 404 unsigned long int dev;
403 if (optval != optvalend 405 errno = 0;
404 && (*optvalend == '\0' || *optvalend == ',') 406 dev = strtoul (optval, &optvalend, 16);
405 && ! (dev == ULONG_MAX && errno == ERANGE) 407 if (optval != optvalend
406 && dev == (dev_t) dev) 408 && (*optvalend == '\0' || *optvalend == ',')
407 return dev; 409 && ! (dev == ULONG_MAX && errno == ERANGE)
410 && dev == (dev_t) dev)
411 return dev;
412 }
408 } 413 }
409 414
410# endif 415# endif
@@ -452,12 +457,8 @@ terminate_at_blank (char *str)
452 *s = '\0'; 457 *s = '\0';
453 return s; 458 return s;
454} 459}
455#endif
456 460
457/* Return a list of the currently mounted file systems, or NULL on error. 461#endif
458 Add each entry to the tail of the list so that they stay in order.
459 If NEED_FS_TYPE is true, ensure that the file system type fields in
460 the returned list are valid. Otherwise, they might not be. */
461 462
462struct mount_entry * 463struct mount_entry *
463read_file_system_list (bool need_fs_type) 464read_file_system_list (bool need_fs_type)
@@ -567,7 +568,7 @@ read_file_system_list (bool need_fs_type)
567 goto free_then_fail; 568 goto free_then_fail;
568 } 569 }
569 else /* fallback to /proc/self/mounts (/etc/mtab). */ 570 else /* fallback to /proc/self/mounts (/etc/mtab). */
570# endif /* __linux __ || __ANDROID__ */ 571# endif /* __linux__ || __ANDROID__ */
571 { 572 {
572 struct mntent *mnt; 573 struct mntent *mnt;
573 char const *table = MOUNTED; 574 char const *table = MOUNTED;
@@ -883,7 +884,9 @@ read_file_system_list (bool need_fs_type)
883 me->me_mntroot = NULL; 884 me->me_mntroot = NULL;
884 me->me_type = xstrdup (mnt.mnt_fstype); 885 me->me_type = xstrdup (mnt.mnt_fstype);
885 me->me_type_malloced = 1; 886 me->me_type_malloced = 1;
886 me->me_dummy = MNT_IGNORE (&mnt) != 0; 887 /* The cast from 'struct extmnttab *' to 'struct mnttab *' is OK
888 because 'struct extmnttab' extends 'struct mnttab'. */
889 me->me_dummy = MNT_IGNORE ((struct mnttab *) &mnt) != 0;
887 me->me_remote = ME_REMOTE (me->me_devname, me->me_type); 890 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
888 me->me_dev = makedev (mnt.mnt_major, mnt.mnt_minor); 891 me->me_dev = makedev (mnt.mnt_major, mnt.mnt_minor);
889 892
@@ -1092,6 +1095,201 @@ read_file_system_list (bool need_fs_type)
1092 } 1095 }
1093#endif /* MOUNTED_INTERIX_STATVFS */ 1096#endif /* MOUNTED_INTERIX_STATVFS */
1094 1097
1098#if defined _WIN32 && !defined __CYGWIN__ /* native Windows */
1099/* Don't assume that UNICODE is not defined. */
1100# undef GetDriveType
1101# define GetDriveType GetDriveTypeA
1102# undef GetVolumeInformation
1103# define GetVolumeInformation GetVolumeInformationA
1104 {
1105 /* Windows has drive prefixes which are similar to mount points.
1106 GetLogicalDrives returns a bitmask where the i-th bit is set
1107 if ASCII 'A' + i is an available drive. See:
1108 <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getlogicaldrives>. */
1109 DWORD value = GetLogicalDrives ();
1110 unsigned int i;
1111
1112 for (i = 0; i < 26; ++i)
1113 {
1114 if (value & (1U << i))
1115 {
1116 char mountdir[4];
1117 char fs_name[MAX_PATH + 1];
1118 mountdir[0] = 'A' + i;
1119 mountdir[1] = ':';
1120 mountdir[2] = '\\';
1121 mountdir[3] = '\0';
1122 /* Test whether the drive actually exists, and
1123 get the name of the file system. See:
1124 <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationa>. */
1125 if (GetVolumeInformation (mountdir, NULL, 0, NULL, NULL, NULL,
1126 fs_name, sizeof fs_name))
1127 {
1128 me = xmalloc (sizeof *me);
1129 me->me_mountdir = xstrdup (mountdir);
1130 /* Check if drive is remote. See:
1131 <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdrivetypea>. */
1132 me->me_remote = GetDriveType (mountdir) == DRIVE_REMOTE;
1133 /* Here we could use
1134 QueryDosDeviceW -> returns something like '\Device\HarddiskVolume2'
1135 GetVolumeNameForVolumeMountPointW -> return something like '\\?\Volume{...}'
1136 */
1137 me->me_devname = NULL;
1138 {
1139 /* Find the SUBST or NET USE mapping of the given drive.
1140 <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-querydosdevicew>
1141 For testing of SUBST: <https://ss64.com/nt/subst.html>
1142 For testing of NET USE: <https://ss64.com/nt/net-use.html> */
1143 wchar_t drive[3];
1144 wchar_t mapping[MAX_PATH + 1];
1145 drive[0] = L'A' + i;
1146 drive[1] = L':';
1147 drive[2] = L'\0';
1148 DWORD mapping_len = QueryDosDeviceW (drive, mapping, sizeof (mapping) / sizeof (mapping[0]));
1149 if (mapping_len > 4 && wcsncmp (mapping, L"\\??\\", 4) == 0)
1150 {
1151 /* It's a SUBSTed drive. */
1152 char subst_dir[MAX_PATH + 1];
1153 size_t subst_dir_len = wcstombs (subst_dir, mapping + 4, sizeof (subst_dir));
1154 if (subst_dir_len > 0 && subst_dir_len <= MAX_PATH)
1155 me->me_mntroot = xstrdup (subst_dir);
1156 else
1157 /* mapping is too long or not convertible to the
1158 locale encoding. */
1159 me->me_mntroot = NULL;
1160 }
1161 else if (mapping_len > 26
1162 && wcsncmp (mapping, L"\\Device\\LanmanRedirector\\;", 26) == 0)
1163 {
1164 wchar_t *next_backslash = wcschr (mapping + 26, L'\\');
1165 if (next_backslash != NULL)
1166 {
1167 *--next_backslash = L'\\';
1168 char share_dir[MAX_PATH + 1];
1169 size_t share_dir_len = wcstombs (share_dir, next_backslash, sizeof (share_dir));
1170 if (share_dir_len > 0 && share_dir_len <= MAX_PATH)
1171 me->me_mntroot = xstrdup (share_dir);
1172 else
1173 /* mapping is too long or not convertible to the
1174 locale encoding. */
1175 me->me_mntroot = NULL;
1176 }
1177 else
1178 /* mapping does not have the expected form. */
1179 me->me_mntroot = NULL;
1180 }
1181 else
1182 /* It's neither a SUBSTed nor a NET USEd drive. */
1183 me->me_mntroot = NULL;
1184 }
1185 me->me_dev = (dev_t) -1;
1186 me->me_dummy = 0;
1187 me->me_type = xstrdup (fs_name);
1188 me->me_type_malloced = 1;
1189
1190 /* Add to the linked list. */
1191 *mtail = me;
1192 mtail = &me->me_next;
1193 }
1194 }
1195 }
1196 }
1197 {
1198 /* Windows also has true mount points, called "mounted folders". See
1199 <https://learn.microsoft.com/en-us/windows/win32/fileio/volume-mount-points>
1200 For testing: <https://learn.microsoft.com/en-us/windows-server/storage/disk-management/assign-a-mount-point-folder-path-to-a-drive> */
1201 /* Enumerate the volumes. See
1202 <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstvolumew>
1203 <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findnextvolumew>
1204 <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findvolumeclose> */
1205 wchar_t vol_name[MAX_PATH + 1];
1206 HANDLE h = FindFirstVolumeW (vol_name, sizeof (vol_name) / sizeof (vol_name[0]));
1207 if (h != INVALID_HANDLE_VALUE)
1208 {
1209 do
1210 {
1211 /* Look where the volume vol_name is mounted.
1212 There are two APIs for doing this:
1213 - FindFirstVolumeMountPointW, FindNextVolumeMountPointW,
1214 FindVolumeMountPointClose. This API always fails with
1215 error code ERROR_ACCESS_DENIED.
1216 - GetVolumePathNamesForVolumeNameW. This API works but
1217 may require a significantly larger buffer.
1218 <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumepathnamesforvolumenamew> */
1219 wchar_t stack_buf[MAX_PATH + 2];
1220 wchar_t *malloced_buf = NULL;
1221 wchar_t *buf = stack_buf;
1222 DWORD bufsize = sizeof (stack_buf) / sizeof (wchar_t);
1223 BOOL success;
1224 for (;;)
1225 {
1226 success = GetVolumePathNamesForVolumeNameW (vol_name, buf, bufsize, &bufsize);
1227 if (!success && GetLastError () == ERROR_MORE_DATA)
1228 {
1229 free (malloced_buf);
1230 malloced_buf = (wchar_t *) xmalloc (bufsize * sizeof (wchar_t));
1231 buf = malloced_buf;
1232 }
1233 else
1234 break;
1235 }
1236 if (success)
1237 {
1238 wchar_t *mount_dir = buf;
1239 while (*mount_dir != L'\0')
1240 {
1241 /* Drive mounts are already handled above. */
1242 if (!(mount_dir[0] >= L'A' && mount_dir[0] <= L'Z'
1243 && mount_dir[1] == L':' && mount_dir[2] == L'\\'
1244 && mount_dir[3] == L'\0'))
1245 {
1246 char mountdir[MAX_PATH + 1];
1247 size_t mountdir_len = wcstombs (mountdir, mount_dir, sizeof (mountdir));
1248 if (mountdir_len > 0 && mountdir_len <= MAX_PATH)
1249 {
1250 char fs_name[MAX_PATH + 1];
1251 /* Get the name of the file system. See:
1252 <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationa>. */
1253 if (GetVolumeInformation (mountdir, NULL, 0, NULL, NULL, NULL,
1254 fs_name, sizeof fs_name))
1255 {
1256 me = xmalloc (sizeof *me);
1257 me->me_mountdir = xstrdup (mountdir);
1258 me->me_remote = false;
1259 /* Here we could use vol_name, something like '\\?\Volume{...}'. */
1260 me->me_devname = NULL;
1261 me->me_mntroot = NULL;
1262 me->me_dev = (dev_t) -1;
1263 me->me_dummy = 0;
1264 me->me_type = xstrdup (fs_name);
1265 me->me_type_malloced = 1;
1266
1267 /* Add to the linked list. */
1268 *mtail = me;
1269 mtail = &me->me_next;
1270 }
1271 }
1272 else
1273 {
1274 /* mount_dir is too long or not convertible to the
1275 locale encoding. */
1276 }
1277 }
1278 mount_dir += wcslen (mount_dir) + 1;
1279 }
1280 }
1281 free (malloced_buf);
1282 }
1283 while (FindNextVolumeW (h, vol_name, sizeof (vol_name) / sizeof (vol_name[0])));
1284 FindVolumeClose (h);
1285 }
1286 }
1287#endif
1288
1289#if MOUNTED_NOT_PORTED
1290# error "Please port gnulib mountlist.c to your platform!"
1291#endif
1292
1095 *mtail = NULL; 1293 *mtail = NULL;
1096 return mount_list; 1294 return mount_list;
1097 1295
diff --git a/gl/mountlist.h b/gl/mountlist.h
index 9728e38b..e8ba1d96 100644
--- a/gl/mountlist.h
+++ b/gl/mountlist.h
@@ -1,6 +1,6 @@
1/* mountlist.h -- declarations for list of mounted file systems 1/* mountlist.h -- declarations for list of mounted file systems
2 2
3 Copyright (C) 1991-1992, 1998, 2000-2005, 2009-2024 Free Software 3 Copyright (C) 1991-1992, 1998, 2000-2005, 2009-2025 Free Software
4 Foundation, Inc. 4 Foundation, Inc.
5 5
6 This program is free software: you can redistribute it and/or modify 6 This program is free software: you can redistribute it and/or modify
@@ -46,8 +46,13 @@ struct mount_entry
46 struct mount_entry *me_next; 46 struct mount_entry *me_next;
47}; 47};
48 48
49/* Return a list of the currently mounted file systems, or NULL on error.
50 Add each entry to the tail of the list so that they stay in order.
51 If NEED_FS_TYPE is true, ensure that the file system type fields in
52 the returned list are valid. Otherwise, they might not be. */
49struct mount_entry *read_file_system_list (bool need_fs_type) 53struct mount_entry *read_file_system_list (bool need_fs_type)
50 _GL_ATTRIBUTE_MALLOC; 54 _GL_ATTRIBUTE_MALLOC;
55
51void free_mount_entry (struct mount_entry *entry); 56void free_mount_entry (struct mount_entry *entry);
52 57
53 58
diff --git a/gl/msvc-inval.c b/gl/msvc-inval.c
index da3fc86a..1b51b1b0 100644
--- a/gl/msvc-inval.c
+++ b/gl/msvc-inval.c
@@ -1,5 +1,5 @@
1/* Invalid parameter handler for MSVC runtime libraries. 1/* Invalid parameter handler for MSVC runtime libraries.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 2 Copyright (C) 2011-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/msvc-inval.h b/gl/msvc-inval.h
index 7aee6e5d..9bb8a156 100644
--- a/gl/msvc-inval.h
+++ b/gl/msvc-inval.h
@@ -1,5 +1,5 @@
1/* Invalid parameter handler for MSVC runtime libraries. 1/* Invalid parameter handler for MSVC runtime libraries.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 2 Copyright (C) 2011-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/msvc-nothrow.c b/gl/msvc-nothrow.c
index 06b35a61..7cf7517e 100644
--- a/gl/msvc-nothrow.c
+++ b/gl/msvc-nothrow.c
@@ -1,6 +1,6 @@
1/* Wrappers that don't throw invalid parameter notifications 1/* Wrappers that don't throw invalid parameter notifications
2 with MSVC runtime libraries. 2 with MSVC runtime libraries.
3 Copyright (C) 2011-2024 Free Software Foundation, Inc. 3 Copyright (C) 2011-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/msvc-nothrow.h b/gl/msvc-nothrow.h
index 121773d1..b02f36c4 100644
--- a/gl/msvc-nothrow.h
+++ b/gl/msvc-nothrow.h
@@ -1,6 +1,6 @@
1/* Wrappers that don't throw invalid parameter notifications 1/* Wrappers that don't throw invalid parameter notifications
2 with MSVC runtime libraries. 2 with MSVC runtime libraries.
3 Copyright (C) 2011-2024 Free Software Foundation, Inc. 3 Copyright (C) 2011-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/netdb.in.h b/gl/netdb.in.h
index 43409b2f..22059ea0 100644
--- a/gl/netdb.in.h
+++ b/gl/netdb.in.h
@@ -1,5 +1,5 @@
1/* Provide a netdb.h header file for systems lacking it (read: MinGW). 1/* Provide a netdb.h header file for systems lacking it (read: MinGW).
2 Copyright (C) 2008-2024 Free Software Foundation, Inc. 2 Copyright (C) 2008-2025 Free Software Foundation, Inc.
3 Written by Simon Josefsson. 3 Written by Simon Josefsson.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
@@ -54,6 +54,14 @@
54/* Declarations for a platform that lacks <netdb.h>, or where it is 54/* Declarations for a platform that lacks <netdb.h>, or where it is
55 incomplete. */ 55 incomplete. */
56 56
57/* Maximum length of a fully-qualified domain name. */
58#undef NI_MAXHOST
59#define NI_MAXHOST 1025
60
61/* Maximum length of a service. */
62#undef NI_MAXSERV
63#define NI_MAXSERV 32
64
57#if @GNULIB_GETADDRINFO@ 65#if @GNULIB_GETADDRINFO@
58 66
59# if !@HAVE_STRUCT_ADDRINFO@ 67# if !@HAVE_STRUCT_ADDRINFO@
@@ -91,12 +99,11 @@ struct addrinfo
91# ifndef AI_CANONNAME 99# ifndef AI_CANONNAME
92# define AI_CANONNAME 0x0002 /* Request for canonical name. */ 100# define AI_CANONNAME 0x0002 /* Request for canonical name. */
93# endif 101# endif
94# ifndef AI_NUMERICSERV 102# ifndef AI_NUMERICHOST
95# define AI_NUMERICSERV 0x0400 /* Don't use name resolution. */ 103# define AI_NUMERICHOST 0x0004 /* Return numeric host address as name. */
96# endif 104# endif
97 105# ifndef AI_NUMERICSERV
98# if 0 106# define AI_NUMERICSERV 0x0400 /* Return service number as service name. */
99# define AI_NUMERICHOST 0x0004 /* Don't use name resolution. */
100# endif 107# endif
101 108
102/* These symbolic constants are required to be present by POSIX, but 109/* These symbolic constants are required to be present by POSIX, but
@@ -176,7 +183,7 @@ _GL_FUNCDECL_RPL (getaddrinfo, int,
176 (const char *restrict nodename, 183 (const char *restrict nodename,
177 const char *restrict servname, 184 const char *restrict servname,
178 const struct addrinfo *restrict hints, 185 const struct addrinfo *restrict hints,
179 struct addrinfo **restrict res) 186 struct addrinfo **restrict res),
180 _GL_ARG_NONNULL ((4))); 187 _GL_ARG_NONNULL ((4)));
181_GL_CXXALIAS_RPL (getaddrinfo, int, 188_GL_CXXALIAS_RPL (getaddrinfo, int,
182 (const char *restrict nodename, 189 (const char *restrict nodename,
@@ -189,7 +196,7 @@ _GL_FUNCDECL_SYS (getaddrinfo, int,
189 (const char *restrict nodename, 196 (const char *restrict nodename,
190 const char *restrict servname, 197 const char *restrict servname,
191 const struct addrinfo *restrict hints, 198 const struct addrinfo *restrict hints,
192 struct addrinfo **restrict res) 199 struct addrinfo **restrict res),
193 _GL_ARG_NONNULL ((4))); 200 _GL_ARG_NONNULL ((4)));
194# endif 201# endif
195_GL_CXXALIAS_SYS (getaddrinfo, int, 202_GL_CXXALIAS_SYS (getaddrinfo, int,
@@ -208,12 +215,12 @@ _GL_CXXALIASWARN (getaddrinfo);
208# undef freeaddrinfo 215# undef freeaddrinfo
209# define freeaddrinfo rpl_freeaddrinfo 216# define freeaddrinfo rpl_freeaddrinfo
210# endif 217# endif
211_GL_FUNCDECL_RPL (freeaddrinfo, void, (struct addrinfo *ai) 218_GL_FUNCDECL_RPL (freeaddrinfo, void, (struct addrinfo *ai),
212 _GL_ARG_NONNULL ((1))); 219 _GL_ARG_NONNULL ((1)));
213_GL_CXXALIAS_RPL (freeaddrinfo, void, (struct addrinfo *ai)); 220_GL_CXXALIAS_RPL (freeaddrinfo, void, (struct addrinfo *ai));
214# else 221# else
215# if !@HAVE_DECL_FREEADDRINFO@ 222# if !@HAVE_DECL_FREEADDRINFO@
216_GL_FUNCDECL_SYS (freeaddrinfo, void, (struct addrinfo *ai) 223_GL_FUNCDECL_SYS (freeaddrinfo, void, (struct addrinfo *ai),
217 _GL_ARG_NONNULL ((1))); 224 _GL_ARG_NONNULL ((1)));
218# endif 225# endif
219_GL_CXXALIAS_SYS (freeaddrinfo, void, (struct addrinfo *ai)); 226_GL_CXXALIAS_SYS (freeaddrinfo, void, (struct addrinfo *ai));
@@ -225,14 +232,14 @@ _GL_CXXALIASWARN (freeaddrinfo);
225# undef gai_strerror 232# undef gai_strerror
226# define gai_strerror rpl_gai_strerror 233# define gai_strerror rpl_gai_strerror
227# endif 234# endif
228_GL_FUNCDECL_RPL (gai_strerror, const char *, (int ecode)); 235_GL_FUNCDECL_RPL (gai_strerror, const char *, (int ecode), );
229_GL_CXXALIAS_RPL (gai_strerror, const char *, (int ecode)); 236_GL_CXXALIAS_RPL (gai_strerror, const char *, (int ecode));
230# else 237# else
231# if !@HAVE_DECL_GAI_STRERROR@ 238# if !@HAVE_DECL_GAI_STRERROR@
232/* Convert error return from getaddrinfo() to a string. 239/* Convert error return from getaddrinfo() to a string.
233 For more details, see the POSIX:2008 specification 240 For more details, see the POSIX:2008 specification
234 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/gai_strerror.html>. */ 241 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/gai_strerror.html>. */
235_GL_FUNCDECL_SYS (gai_strerror, const char *, (int ecode)); 242_GL_FUNCDECL_SYS (gai_strerror, const char *, (int ecode), );
236# endif 243# endif
237_GL_CXXALIAS_SYS (gai_strerror, const char *, (int ecode)); 244_GL_CXXALIAS_SYS (gai_strerror, const char *, (int ecode));
238# endif 245# endif
@@ -248,7 +255,7 @@ _GL_FUNCDECL_SYS (getnameinfo, int,
248 (const struct sockaddr *restrict sa, socklen_t salen, 255 (const struct sockaddr *restrict sa, socklen_t salen,
249 char *restrict node, socklen_t nodelen, 256 char *restrict node, socklen_t nodelen,
250 char *restrict service, socklen_t servicelen, 257 char *restrict service, socklen_t servicelen,
251 int flags) 258 int flags),
252 _GL_ARG_NONNULL ((1))); 259 _GL_ARG_NONNULL ((1)));
253# endif 260# endif
254/* Need to cast, because on glibc systems, the seventh parameter is 261/* Need to cast, because on glibc systems, the seventh parameter is
diff --git a/gl/netinet_in.in.h b/gl/netinet_in.in.h
index 4e9f6f2d..402d01a9 100644
--- a/gl/netinet_in.in.h
+++ b/gl/netinet_in.in.h
@@ -1,5 +1,5 @@
1/* Substitute for <netinet/in.h>. 1/* Substitute for <netinet/in.h>.
2 Copyright (C) 2007-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/nl_langinfo-lock.c b/gl/nl_langinfo-lock.c
index 5a248ed8..1ac25515 100644
--- a/gl/nl_langinfo-lock.c
+++ b/gl/nl_langinfo-lock.c
@@ -1,5 +1,5 @@
1/* Return the internal lock used by nl_langinfo. 1/* Return the internal lock used by nl_langinfo.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc. 2 Copyright (C) 2019-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/nl_langinfo.c b/gl/nl_langinfo.c
index 64ff93b0..0180c26a 100644
--- a/gl/nl_langinfo.c
+++ b/gl/nl_langinfo.c
@@ -1,6 +1,6 @@
1/* nl_langinfo() replacement: query locale dependent information. 1/* nl_langinfo() replacement: query locale dependent information.
2 2
3 Copyright (C) 2007-2024 Free Software Foundation, Inc. 3 Copyright (C) 2007-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -154,11 +154,15 @@ ctype_codeset (void)
154 "thread5 disturbed by threadN!", even when threadN invokes only 154 "thread5 disturbed by threadN!", even when threadN invokes only
155 nl_langinfo (CODESET); 155 nl_langinfo (CODESET);
156 nl_langinfo (CRNCYSTR); 156 nl_langinfo (CRNCYSTR);
157 Similarly on Solaris 10. */ 157 Similarly on Solaris 10 and macOS 26. */
158 158
159# if !NL_LANGINFO_MTSAFE /* Solaris */ 159# if !NL_LANGINFO_MTSAFE /* macOS, Solaris */
160 160
161# define ITEMS (MAXSTRMSG + 1) 161# ifdef __sun /* Solaris */
162# define ITEMS (MAXSTRMSG + 1)
163# else /* macOS */
164# define ITEMS (CRNCYSTR + 20)
165# endif
162# define MAX_RESULT_LEN 80 166# define MAX_RESULT_LEN 80
163 167
164static char * 168static char *
@@ -317,6 +321,24 @@ rpl_nl_langinfo (nl_item item)
317 item = item - ALTMON_1 + MON_1; 321 item = item - ALTMON_1 + MON_1;
318 break; 322 break;
319# endif 323# endif
324# if GNULIB_defined_ABALTMON
325 case ABALTMON_1:
326 case ABALTMON_2:
327 case ABALTMON_3:
328 case ABALTMON_4:
329 case ABALTMON_5:
330 case ABALTMON_6:
331 case ABALTMON_7:
332 case ABALTMON_8:
333 case ABALTMON_9:
334 case ABALTMON_10:
335 case ABALTMON_11:
336 case ABALTMON_12:
337 /* We don't ship the appropriate localizations with gnulib. Therefore,
338 treat ABALTMON_i like ABMON_i. */
339 item = item - ABALTMON_1 + ABMON_1;
340 break;
341# endif
320# if GNULIB_defined_ERA 342# if GNULIB_defined_ERA
321 case ERA: 343 case ERA:
322 /* The format is not standardized. In glibc it is a sequence of strings 344 /* The format is not standardized. In glibc it is a sequence of strings
@@ -510,30 +532,57 @@ nl_langinfo (nl_item item)
510 return result[item - ALTMON_1]; 532 return result[item - ALTMON_1];
511 } 533 }
512 } 534 }
513 case ABMON_1: 535 {
514 case ABMON_2: 536 static char const abmonths[][sizeof "Jan"] = {
515 case ABMON_3: 537 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
516 case ABMON_4: 538 "Aug", "Sep", "Oct", "Nov", "Dec"
517 case ABMON_5: 539 };
518 case ABMON_6: 540 case ABMON_1:
519 case ABMON_7: 541 case ABMON_2:
520 case ABMON_8: 542 case ABMON_3:
521 case ABMON_9: 543 case ABMON_4:
522 case ABMON_10: 544 case ABMON_5:
523 case ABMON_11: 545 case ABMON_6:
524 case ABMON_12: 546 case ABMON_7:
525 { 547 case ABMON_8:
526 static char result[12][30]; 548 case ABMON_9:
527 static char const abmonths[][sizeof "Jan"] = { 549 case ABMON_10:
528 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", 550 case ABMON_11:
529 "Aug", "Sep", "Oct", "Nov", "Dec" 551 case ABMON_12:
530 }; 552 {
531 tmm.tm_mon = item - ABMON_1; 553 static char result[12][30];
532 if (!strftime (buf, sizeof result[0], "%b", &tmm)) 554 tmm.tm_mon = item - ABMON_1;
533 return (char *) abmonths[item - ABMON_1]; 555 if (!strftime (buf, sizeof result[0], "%b", &tmm))
534 strcpy (result[item - ABMON_1], buf); 556 return (char *) abmonths[item - ABMON_1];
535 return result[item - ABMON_1]; 557 strcpy (result[item - ABMON_1], buf);
536 } 558 return result[item - ABMON_1];
559 }
560 case ABALTMON_1:
561 case ABALTMON_2:
562 case ABALTMON_3:
563 case ABALTMON_4:
564 case ABALTMON_5:
565 case ABALTMON_6:
566 case ABALTMON_7:
567 case ABALTMON_8:
568 case ABALTMON_9:
569 case ABALTMON_10:
570 case ABALTMON_11:
571 case ABALTMON_12:
572 {
573 static char result[12][50];
574 tmm.tm_mon = item - ABALTMON_1;
575 /* The platforms without nl_langinfo() don't support strftime with
576 %Ob. We don't even need to try. */
577 #if 0
578 if (!strftime (buf, sizeof result[0], "%Ob", &tmm))
579 #endif
580 if (!strftime (buf, sizeof result[0], "%b", &tmm))
581 return (char *) abmonths[item - ABALTMON_1];
582 strcpy (result[item - ABALTMON_1], buf);
583 return result[item - ABALTMON_1];
584 }
585 }
537 case ERA: 586 case ERA:
538 return (char *) ""; 587 return (char *) "";
539 case ALT_DIGITS: 588 case ALT_DIGITS:
diff --git a/gl/open.c b/gl/open.c
index e690c9ea..d76372fd 100644
--- a/gl/open.c
+++ b/gl/open.c
@@ -1,5 +1,5 @@
1/* Open a descriptor to a file. 1/* Open a descriptor to a file.
2 Copyright (C) 2007-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -55,24 +55,29 @@ orig_open (const char *filename, int flags, mode_t mode)
55#include <sys/stat.h> 55#include <sys/stat.h>
56#include <unistd.h> 56#include <unistd.h>
57 57
58#ifndef HAVE_WORKING_O_DIRECTORY
59# define HAVE_WORKING_O_DIRECTORY false
60#endif
61
62#ifndef OPEN_TRAILING_SLASH_BUG
63# define OPEN_TRAILING_SLASH_BUG false
64#endif
65
58#ifndef REPLACE_OPEN_DIRECTORY 66#ifndef REPLACE_OPEN_DIRECTORY
59# define REPLACE_OPEN_DIRECTORY 0 67# define REPLACE_OPEN_DIRECTORY false
60#endif 68#endif
61 69
70static int
71lstatif (char const *filename, struct stat *st, int flags)
72{
73 return flags & O_NOFOLLOW ? lstat (filename, st) : stat (filename, st);
74}
75
62int 76int
63open (const char *filename, int flags, ...) 77open (const char *filename, int flags, ...)
64{ 78{
65 /* 0 = unknown, 1 = yes, -1 = no. */ 79 mode_t mode = 0;
66#if GNULIB_defined_O_CLOEXEC
67 int have_cloexec = -1;
68#else
69 static int have_cloexec;
70#endif
71
72 mode_t mode;
73 int fd;
74 80
75 mode = 0;
76 if (flags & O_CREAT) 81 if (flags & O_CREAT)
77 { 82 {
78 va_list arg; 83 va_list arg;
@@ -99,7 +104,6 @@ open (const char *filename, int flags, ...)
99 filename = "NUL"; 104 filename = "NUL";
100#endif 105#endif
101 106
102#if OPEN_TRAILING_SLASH_BUG
103 /* Fail if one of O_CREAT, O_WRONLY, O_RDWR is specified and the filename 107 /* Fail if one of O_CREAT, O_WRONLY, O_RDWR is specified and the filename
104 ends in a slash, as POSIX says such a filename must name a directory 108 ends in a slash, as POSIX says such a filename must name a directory
105 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>: 109 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>:
@@ -118,21 +122,55 @@ open (const char *filename, int flags, ...)
118 directories, 122 directories,
119 - if O_WRONLY or O_RDWR is specified, open() must fail because the 123 - if O_WRONLY or O_RDWR is specified, open() must fail because the
120 file does not contain a '.' directory. */ 124 file does not contain a '.' directory. */
121 if ((flags & O_CREAT) 125 bool check_for_slash_bug;
122 || (flags & O_ACCMODE) == O_RDWR 126 if (OPEN_TRAILING_SLASH_BUG)
123 || (flags & O_ACCMODE) == O_WRONLY)
124 { 127 {
125 size_t len = strlen (filename); 128 size_t len = strlen (filename);
126 if (len > 0 && filename[len - 1] == '/') 129 check_for_slash_bug = len && filename[len - 1] == '/';
130 }
131 else
132 check_for_slash_bug = false;
133
134 if (check_for_slash_bug
135 && (flags & O_CREAT
136 || (flags & O_ACCMODE) == O_RDWR
137 || (flags & O_ACCMODE) == O_WRONLY))
138 {
139 errno = EISDIR;
140 return -1;
141 }
142
143 /* With the trailing slash bug or without working O_DIRECTORY, check with
144 stat first lest we hang trying to open a fifo. Although there is
145 a race between this and opening the file, we can do no better.
146 After opening the file we will check again with fstat. */
147 bool check_directory =
148 (check_for_slash_bug
149 || (!HAVE_WORKING_O_DIRECTORY && flags & O_DIRECTORY));
150 if (check_directory)
151 {
152 struct stat statbuf;
153 if (lstatif (filename, &statbuf, flags) < 0)
154 {
155 if (! (flags & O_CREAT && errno == ENOENT))
156 return -1;
157 }
158 else if (!S_ISDIR (statbuf.st_mode))
127 { 159 {
128 errno = EISDIR; 160 errno = ENOTDIR;
129 return -1; 161 return -1;
130 } 162 }
131 } 163 }
164
165 /* 0 = unknown, 1 = yes, -1 = no. */
166#if GNULIB_defined_O_CLOEXEC
167 int have_cloexec = -1;
168#else
169 static int have_cloexec;
132#endif 170#endif
133 171
134 fd = orig_open (filename, 172 int fd = orig_open (filename,
135 flags & ~(have_cloexec < 0 ? O_CLOEXEC : 0), mode); 173 flags & ~(have_cloexec < 0 ? O_CLOEXEC : 0), mode);
136 174
137 if (flags & O_CLOEXEC) 175 if (flags & O_CLOEXEC)
138 { 176 {
@@ -154,19 +192,21 @@ open (const char *filename, int flags, ...)
154#if REPLACE_FCHDIR 192#if REPLACE_FCHDIR
155 /* Implementing fchdir and fdopendir requires the ability to open a 193 /* Implementing fchdir and fdopendir requires the ability to open a
156 directory file descriptor. If open doesn't support that (as on 194 directory file descriptor. If open doesn't support that (as on
157 mingw), we use a dummy file that behaves the same as directories 195 mingw), use a dummy file that behaves the same as directories
158 on Linux (ie. always reports EOF on attempts to read()), and 196 on Linux (ie. always reports EOF on attempts to read()), and
159 override fstat() in fchdir.c to hide the fact that we have a 197 override fstat in fchdir.c to hide the dummy. */
160 dummy. */
161 if (REPLACE_OPEN_DIRECTORY && fd < 0 && errno == EACCES 198 if (REPLACE_OPEN_DIRECTORY && fd < 0 && errno == EACCES
162 && ((flags & O_ACCMODE) == O_RDONLY 199 && ((flags & (O_ACCMODE | O_CREAT)) == O_RDONLY
163 || (O_SEARCH != O_RDONLY && (flags & O_ACCMODE) == O_SEARCH))) 200 || (O_SEARCH != O_RDONLY
201 && (flags & (O_ACCMODE | O_CREAT)) == O_SEARCH)))
164 { 202 {
165 struct stat statbuf; 203 struct stat statbuf;
166 if (stat (filename, &statbuf) == 0 && S_ISDIR (statbuf.st_mode)) 204 if (check_directory
205 || (lstatif (filename, &statbuf, flags) == 0
206 && S_ISDIR (statbuf.st_mode)))
167 { 207 {
168 /* Maximum recursion depth of 1. */ 208 /* Maximum recursion depth of 1. */
169 fd = open ("/dev/null", flags, mode); 209 fd = open ("/dev/null", flags & ~O_DIRECTORY, mode);
170 if (0 <= fd) 210 if (0 <= fd)
171 fd = _gl_register_fd (fd, filename); 211 fd = _gl_register_fd (fd, filename);
172 } 212 }
@@ -175,10 +215,8 @@ open (const char *filename, int flags, ...)
175 } 215 }
176#endif 216#endif
177 217
178#if OPEN_TRAILING_SLASH_BUG 218 /* If checking for directories, fail if fd does not refer to a directory.
179 /* If the filename ends in a slash and fd does not refer to a directory, 219 Rationale: A filename ending in slash cannot name a non-directory
180 then fail.
181 Rationale: POSIX says such a filename must name a directory
182 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>: 220 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>:
183 "A pathname that contains at least one non-<slash> character and that 221 "A pathname that contains at least one non-<slash> character and that
184 ends with one or more trailing <slash> characters shall not be resolved 222 ends with one or more trailing <slash> characters shall not be resolved
@@ -186,23 +224,18 @@ open (const char *filename, int flags, ...)
186 <slash> characters names an existing directory" 224 <slash> characters names an existing directory"
187 If the named file without the slash is not a directory, open() must fail 225 If the named file without the slash is not a directory, open() must fail
188 with ENOTDIR. */ 226 with ENOTDIR. */
189 if (fd >= 0) 227 if (check_directory && 0 <= fd)
190 { 228 {
191 /* We know len is positive, since open did not fail with ENOENT. */ 229 struct stat statbuf;
192 size_t len = strlen (filename); 230 int r = fstat (fd, &statbuf);
193 if (filename[len - 1] == '/') 231 if (r < 0 || !S_ISDIR (statbuf.st_mode))
194 { 232 {
195 struct stat statbuf; 233 int err = r < 0 ? errno : ENOTDIR;
196 234 close (fd);
197 if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode)) 235 errno = err;
198 { 236 return -1;
199 close (fd);
200 errno = ENOTDIR;
201 return -1;
202 }
203 } 237 }
204 } 238 }
205#endif
206 239
207#if REPLACE_FCHDIR 240#if REPLACE_FCHDIR
208 if (!REPLACE_OPEN_DIRECTORY && 0 <= fd) 241 if (!REPLACE_OPEN_DIRECTORY && 0 <= fd)
diff --git a/gl/pathmax.h b/gl/pathmax.h
index d6512c6f..5f535517 100644
--- a/gl/pathmax.h
+++ b/gl/pathmax.h
@@ -1,5 +1,5 @@
1/* Define PATH_MAX somehow. Requires sys/types.h. 1/* Define PATH_MAX somehow. Requires sys/types.h.
2 Copyright (C) 1992, 1999, 2001, 2003, 2005, 2009-2024 Free Software 2 Copyright (C) 1992, 1999, 2001, 2003, 2005, 2009-2025 Free Software
3 Foundation, Inc. 3 Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/printf-args.c b/gl/printf-args.c
index eb0d2cdc..b83ec1e8 100644
--- a/gl/printf-args.c
+++ b/gl/printf-args.c
@@ -1,5 +1,5 @@
1/* Decomposed printf argument list. 1/* Decomposed printf argument list.
2 Copyright (C) 1999, 2002-2003, 2005-2007, 2009-2024 Free Software 2 Copyright (C) 1999, 2002-2003, 2005-2007, 2009-2025 Free Software
3 Foundation, Inc. 3 Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
@@ -32,6 +32,9 @@
32/* Get INT_WIDTH. */ 32/* Get INT_WIDTH. */
33#include <limits.h> 33#include <limits.h>
34 34
35/* Get abort(). */
36#include <stdlib.h>
37
35#ifdef STATIC 38#ifdef STATIC
36STATIC 39STATIC
37#endif 40#endif
@@ -198,7 +201,6 @@ PRINTF_FETCHARGS (va_list args, arguments *a)
198 if (ap->a.a_string == NULL) 201 if (ap->a.a_string == NULL)
199 ap->a.a_string = "(NULL)"; 202 ap->a.a_string = "(NULL)";
200 break; 203 break;
201#if HAVE_WCHAR_T
202 case TYPE_WIDE_STRING: 204 case TYPE_WIDE_STRING:
203 ap->a.a_wide_string = va_arg (args, const wchar_t *); 205 ap->a.a_wide_string = va_arg (args, const wchar_t *);
204 /* A null pointer is an invalid argument for "%ls", but in practice 206 /* A null pointer is an invalid argument for "%ls", but in practice
@@ -216,7 +218,6 @@ PRINTF_FETCHARGS (va_list args, arguments *a)
216 ap->a.a_wide_string = wide_null_string; 218 ap->a.a_wide_string = wide_null_string;
217 } 219 }
218 break; 220 break;
219#endif
220 case TYPE_POINTER: 221 case TYPE_POINTER:
221 ap->a.a_pointer = va_arg (args, void *); 222 ap->a.a_pointer = va_arg (args, void *);
222 break; 223 break;
@@ -298,9 +299,19 @@ PRINTF_FETCHARGS (va_list args, arguments *a)
298 } 299 }
299 break; 300 break;
300#endif 301#endif
301 default: 302 case TYPE_NONE:
302 /* Unknown type. */ 303 /* Argument i is not used by any directive, but some argument with
304 number > i is used by a format directive. POSIX says that this
305 is invalid:
306 "When numbered argument specifications are used, specifying the
307 Nth argument requires that all the leading arguments, from the
308 first to the (N-1)th, are specified in the format string."
309 The reason is that we cannot know how many bytes to skip in the
310 va_arg sequence. */
303 return -1; 311 return -1;
312 default:
313 /* Unknown type. Should not happen. */
314 abort ();
304 } 315 }
305 return 0; 316 return 0;
306} 317}
diff --git a/gl/printf-args.h b/gl/printf-args.h
index 9b80bb39..6edc570c 100644
--- a/gl/printf-args.h
+++ b/gl/printf-args.h
@@ -1,5 +1,5 @@
1/* Decomposed printf argument list. 1/* Decomposed printf argument list.
2 Copyright (C) 1999, 2002-2003, 2006-2007, 2011-2024 Free Software 2 Copyright (C) 1999, 2002-2003, 2006-2007, 2011-2025 Free Software
3 Foundation, Inc. 3 Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
@@ -28,14 +28,9 @@
28# define PRINTF_FETCHARGS printf_fetchargs 28# define PRINTF_FETCHARGS printf_fetchargs
29#endif 29#endif
30 30
31/* Get size_t. */ 31/* Get size_t, wchar_t. */
32#include <stddef.h> 32#include <stddef.h>
33 33
34/* Get wchar_t. */
35#if HAVE_WCHAR_T
36# include <stddef.h>
37#endif
38
39/* Get wint_t. */ 34/* Get wint_t. */
40#if HAVE_WINT_T 35#if HAVE_WINT_T
41# include <wchar.h> 36# include <wchar.h>
@@ -89,9 +84,7 @@ typedef enum
89 TYPE_WIDE_CHAR, 84 TYPE_WIDE_CHAR,
90#endif 85#endif
91 TYPE_STRING, 86 TYPE_STRING,
92#if HAVE_WCHAR_T
93 TYPE_WIDE_STRING, 87 TYPE_WIDE_STRING,
94#endif
95 TYPE_POINTER, 88 TYPE_POINTER,
96 TYPE_COUNT_SCHAR_POINTER, 89 TYPE_COUNT_SCHAR_POINTER,
97 TYPE_COUNT_SHORT_POINTER, 90 TYPE_COUNT_SHORT_POINTER,
@@ -154,9 +147,7 @@ typedef struct
154 wint_t a_wide_char; 147 wint_t a_wide_char;
155#endif 148#endif
156 const char* a_string; 149 const char* a_string;
157#if HAVE_WCHAR_T
158 const wchar_t* a_wide_string; 150 const wchar_t* a_wide_string;
159#endif
160 void* a_pointer; 151 void* a_pointer;
161 signed char * a_count_schar_pointer; 152 signed char * a_count_schar_pointer;
162 short * a_count_short_pointer; 153 short * a_count_short_pointer;
diff --git a/gl/printf-parse.c b/gl/printf-parse.c
index a33e27a0..79b35034 100644
--- a/gl/printf-parse.c
+++ b/gl/printf-parse.c
@@ -1,5 +1,5 @@
1/* Formatted output to strings. 1/* Formatted output to strings.
2 Copyright (C) 1999-2000, 2002-2003, 2006-2024 Free Software Foundation, Inc. 2 Copyright (C) 1999-2000, 2002-2003, 2006-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -600,20 +600,14 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
600 if (signed_type == TYPE_LONGINT 600 if (signed_type == TYPE_LONGINT
601 /* For backward compatibility only. */ 601 /* For backward compatibility only. */
602 || signed_type == TYPE_LONGLONGINT) 602 || signed_type == TYPE_LONGLONGINT)
603#if HAVE_WCHAR_T
604 type = TYPE_WIDE_STRING; 603 type = TYPE_WIDE_STRING;
605#else
606 goto error;
607#endif
608 else 604 else
609 type = TYPE_STRING; 605 type = TYPE_STRING;
610 break; 606 break;
611#if HAVE_WCHAR_T
612 case 'S': 607 case 'S':
613 type = TYPE_WIDE_STRING; 608 type = TYPE_WIDE_STRING;
614 c = 's'; 609 c = 's';
615 break; 610 break;
616#endif
617 case 'p': 611 case 'p':
618 type = TYPE_POINTER; 612 type = TYPE_POINTER;
619 break; 613 break;
diff --git a/gl/printf-parse.h b/gl/printf-parse.h
index 949b8754..673053b8 100644
--- a/gl/printf-parse.h
+++ b/gl/printf-parse.h
@@ -1,5 +1,5 @@
1/* Parse printf format string. 1/* Parse printf format string.
2 Copyright (C) 1999, 2002-2003, 2005, 2007, 2010-2024 Free Software 2 Copyright (C) 1999, 2002-2003, 2005, 2007, 2010-2025 Free Software
3 Foundation, Inc. 3 Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/pthread-once.c b/gl/pthread-once.c
new file mode 100644
index 00000000..b19dae50
--- /dev/null
+++ b/gl/pthread-once.c
@@ -0,0 +1,148 @@
1/* POSIX once-only control.
2 Copyright (C) 2019-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17/* Written by Bruno Haible <bruno@clisp.org>, 2019. */
18
19#include <config.h>
20
21/* Specification. */
22#include <pthread.h>
23
24#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
25# include "windows-once.h"
26#endif
27
28#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
29/* Use Windows threads. */
30
31int
32pthread_once (pthread_once_t *once_control, void (*initfunction) (void))
33{
34 glwthread_once (once_control, initfunction);
35 return 0;
36}
37
38#elif HAVE_PTHREAD_H
39/* Provide workarounds for POSIX threads. */
40
41# if defined __CYGWIN__
42
43# include <stdlib.h>
44
45int
46pthread_once (pthread_once_t *once_control, void (*initfunction) (void))
47{
48 /* In this implementation, we reuse the type
49 typedef struct { pthread_mutex_t mutex; int state; } pthread_once_t;
50 #define PTHREAD_ONCE_INIT { PTHREAD_MUTEX_INITIALIZER, 0 }
51 while assigning the following meaning to the state:
52 state = (<number of waiting threads> << 16) + <1 if done>
53 In other words:
54 state = { unsigned int num_threads : 16; unsigned int done : 16; }
55 */
56 struct actual_state
57 {
58 _Atomic unsigned short num_threads;
59 /* done == 0: initial state
60 done == 1: initfunction executed, lock still active
61 done == 2: initfunction executed, lock no longer usable */
62 _Atomic unsigned short done;
63 };
64 struct actual_state *state_p = (struct actual_state *) &once_control->state;
65 /* This test is not necessary. It's only an optimization, to establish
66 a fast path for the common case that the 'done' word is already > 0. */
67 if (state_p->done == 0)
68 {
69 /* Increment num_threads (atomically), to indicate that this thread will
70 possibly take the lock. */
71 state_p->num_threads += 1;
72 /* Test the 'done' word. */
73 if (state_p->done == 0)
74 {
75 /* The 'done' word is still zero. Now take the lock. */
76 pthread_mutex_lock (&once_control->mutex);
77 /* Test the 'done' word again. */
78 if (state_p->done == 0)
79 {
80 /* Execute the initfunction. */
81 (*initfunction) ();
82 /* Set the 'done' word to 1 (atomically). */
83 state_p->done = 1;
84 }
85 /* Now the 'done' word is 1. Release the lock. */
86 pthread_mutex_unlock (&once_control->mutex);
87 }
88 /* Here, done is > 0. */
89 /* Decrement num_threads (atomically). */
90 if ((state_p->num_threads -= 1) == 0)
91 {
92 /* num_threads is now zero, and done is > 0.
93 No other thread will need to use the lock.
94 We can therefore destroy the lock, to free resources. */
95 if (__sync_bool_compare_and_swap (&state_p->done, 1, 2))
96 pthread_mutex_destroy (&once_control->mutex);
97 }
98 }
99 /* Proof of correctness:
100 * num_threads is incremented and then decremented by some threads.
101 Therefore, num_threads always stays >= 0, and is == 0 at the end.
102 * The 'done' word, once > 0, stays > 0 (since it is never assigned 0).
103 * The 'done' word is changed from == 0 to > 0 only while the lock
104 is taken. Therefore, only the first thread that succeeds in taking
105 the lock executes the initfunction and sets the 'done' word to a
106 value > 0; the other threads that take the lock do no side effects
107 between taking and releasing the lock.
108 * The 'done' word does not change any more once it is 2.
109 Therefore, it can be changed from 1 to 2 only once.
110 * pthread_mutex_destroy gets invoked right after 'done' has been changed
111 from 1 to 2. Therefore, pthread_mutex_destroy gets invoked only once.
112 * After a moment where num_threads was 0 and done was > 0, no thread can
113 reach the pthread_mutex_lock invocation. Proof:
114 - At such a moment, no thread is in the code range between
115 state_p->num_threads += 1
116 and
117 state_p->num_threads -= 1
118 - After such a moment, some thread can increment num_threads, but from
119 there they cannot reach the pthread_mutex_lock invocation, because the
120 if (state_p->done == 0)
121 test prevents that.
122 * From this it follows that:
123 - pthread_mutex_destroy cannot be executed while the lock is taken
124 (because pthread_mutex_destroy is only executed after a moment where
125 num_threads was 0 and done was > 0).
126 - Once pthread_mutex_destroy has been executed, the lock is not used any
127 more.
128 */
129 return 0;
130}
131
132# endif
133
134#else
135/* Provide a dummy implementation for single-threaded applications. */
136
137int
138pthread_once (pthread_once_t *once_control, void (*initfunction) (void))
139{
140 if (*once_control == 0)
141 {
142 *once_control = ~ 0;
143 initfunction ();
144 }
145 return 0;
146}
147
148#endif
diff --git a/gl/pthread.h b/gl/pthread.h
new file mode 100644
index 00000000..599f1633
--- /dev/null
+++ b/gl/pthread.h
@@ -0,0 +1,2571 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* Implement the most essential subset of POSIX pthread.h.
3
4 Copyright (C) 2009-2025 Free Software Foundation, Inc.
5
6 This file is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
10
11 This file is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18
19/* Written by Paul Eggert, Glen Lenker, and Bruno Haible. */
20
21#if __GNUC__ >= 3
22#pragma GCC system_header
23#endif
24
25
26#if defined _GL_ALREADY_INCLUDING_PTHREAD_H
27/* Special invocation convention:
28 On Android, we have a sequence of nested includes
29 <pthread.h> -> <time.h> -> <sys/time.h> -> <sys/select.h> ->
30 <signal.h> -> <pthread.h>.
31 In this situation, PTHREAD_COND_INITIALIZER is not yet defined,
32 therefore we should not attempt to define PTHREAD_MUTEX_NORMAL etc. */
33
34#include_next <pthread.h>
35
36#else
37/* Normal invocation convention. */
38
39#ifndef _GL_PTHREAD_H_
40
41#if 1
42
43# define _GL_ALREADY_INCLUDING_PTHREAD_H
44
45/* The include_next requires a split double-inclusion guard. */
46# include_next <pthread.h>
47
48# undef _GL_ALREADY_INCLUDING_PTHREAD_H
49
50#endif
51
52#ifndef _GL_PTHREAD_H_
53#define _GL_PTHREAD_H_
54
55/* This file uses _Noreturn, _GL_ATTRIBUTE_PURE, GNULIB_POSIXCHECK,
56 HAVE_RAW_DECL_*. */
57#if !_GL_CONFIG_H_INCLUDED
58 #error "Please include config.h first."
59#endif
60
61#define __need_system_stdlib_h
62#include <stdlib.h>
63#undef __need_system_stdlib_h
64
65
66/* The pthreads-win32 <pthread.h> defines a couple of broken macros. */
67#undef asctime_r
68#undef ctime_r
69#undef gmtime_r
70#undef localtime_r
71#undef rand_r
72#undef strtok_r
73
74#include <errno.h>
75#include <sched.h>
76#include <sys/types.h>
77#include <time.h>
78
79/* The __attribute__ feature is available in gcc versions 2.5 and later.
80 The attribute __pure__ was added in gcc 2.96. */
81#ifndef _GL_ATTRIBUTE_PURE
82# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) || defined __clang__
83# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
84# else
85# define _GL_ATTRIBUTE_PURE /* empty */
86# endif
87#endif
88
89/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
90/* C++ compatible function declaration macros.
91 Copyright (C) 2010-2025 Free Software Foundation, Inc.
92
93 This program is free software: you can redistribute it and/or modify it
94 under the terms of the GNU Lesser General Public License as published
95 by the Free Software Foundation; either version 2 of the License, or
96 (at your option) any later version.
97
98 This program is distributed in the hope that it will be useful,
99 but WITHOUT ANY WARRANTY; without even the implied warranty of
100 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
101 Lesser General Public License for more details.
102
103 You should have received a copy of the GNU Lesser General Public License
104 along with this program. If not, see <https://www.gnu.org/licenses/>. */
105
106#ifndef _GL_CXXDEFS_H
107#define _GL_CXXDEFS_H
108
109/* Begin/end the GNULIB_NAMESPACE namespace. */
110#if defined __cplusplus && defined GNULIB_NAMESPACE
111# define _GL_BEGIN_NAMESPACE namespace GNULIB_NAMESPACE {
112# define _GL_END_NAMESPACE }
113#else
114# define _GL_BEGIN_NAMESPACE
115# define _GL_END_NAMESPACE
116#endif
117
118/* The three most frequent use cases of these macros are:
119
120 * For providing a substitute for a function that is missing on some
121 platforms, but is declared and works fine on the platforms on which
122 it exists:
123
124 #if @GNULIB_FOO@
125 # if !@HAVE_FOO@
126 _GL_FUNCDECL_SYS (foo, ...);
127 # endif
128 _GL_CXXALIAS_SYS (foo, ...);
129 _GL_CXXALIASWARN (foo);
130 #elif defined GNULIB_POSIXCHECK
131 ...
132 #endif
133
134 * For providing a replacement for a function that exists on all platforms,
135 but is broken/insufficient and needs to be replaced on some platforms:
136
137 #if @GNULIB_FOO@
138 # if @REPLACE_FOO@
139 # if !(defined __cplusplus && defined GNULIB_NAMESPACE)
140 # undef foo
141 # define foo rpl_foo
142 # endif
143 _GL_FUNCDECL_RPL (foo, ...);
144 _GL_CXXALIAS_RPL (foo, ...);
145 # else
146 _GL_CXXALIAS_SYS (foo, ...);
147 # endif
148 _GL_CXXALIASWARN (foo);
149 #elif defined GNULIB_POSIXCHECK
150 ...
151 #endif
152
153 * For providing a replacement for a function that exists on some platforms
154 but is broken/insufficient and needs to be replaced on some of them and
155 is additionally either missing or undeclared on some other platforms:
156
157 #if @GNULIB_FOO@
158 # if @REPLACE_FOO@
159 # if !(defined __cplusplus && defined GNULIB_NAMESPACE)
160 # undef foo
161 # define foo rpl_foo
162 # endif
163 _GL_FUNCDECL_RPL (foo, ...);
164 _GL_CXXALIAS_RPL (foo, ...);
165 # else
166 # if !@HAVE_FOO@ or if !@HAVE_DECL_FOO@
167 _GL_FUNCDECL_SYS (foo, ...);
168 # endif
169 _GL_CXXALIAS_SYS (foo, ...);
170 # endif
171 _GL_CXXALIASWARN (foo);
172 #elif defined GNULIB_POSIXCHECK
173 ...
174 #endif
175*/
176
177/* _GL_EXTERN_C declaration;
178 performs the declaration with C linkage. */
179#if defined __cplusplus
180# define _GL_EXTERN_C extern "C"
181#else
182# define _GL_EXTERN_C extern
183#endif
184
185/* _GL_EXTERN_C_FUNC declaration;
186 performs the declaration of a function with C linkage. */
187#if defined __cplusplus
188# define _GL_EXTERN_C_FUNC extern "C"
189#else
190/* In C mode, omit the 'extern' keyword, because attributes in bracket syntax
191 are not allowed between 'extern' and the return type (see gnulib-common.m4).
192 */
193# define _GL_EXTERN_C_FUNC
194#endif
195
196/* _GL_FUNCDECL_RPL (func, rettype, parameters, [attributes]);
197 declares a replacement function, named rpl_func, with the given prototype,
198 consisting of return type, parameters, and attributes.
199 Although attributes are optional, the comma before them is required
200 for portability to C17 and earlier. The attribute _GL_ATTRIBUTE_NOTHROW,
201 if needed, must be placed after the _GL_FUNCDECL_RPL invocation,
202 at the end of the declaration.
203 Examples:
204 _GL_FUNCDECL_RPL (free, void, (void *ptr), ) _GL_ATTRIBUTE_NOTHROW;
205 _GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...),
206 _GL_ARG_NONNULL ((1)));
207
208 Note: Attributes, such as _GL_ATTRIBUTE_DEPRECATED, are supported in front
209 of a _GL_FUNCDECL_RPL invocation only in C mode, not in C++ mode. (That's
210 because
211 [[...]] extern "C" <declaration>;
212 is invalid syntax in C++.)
213 */
214#define _GL_FUNCDECL_RPL(func,rettype,parameters,...) \
215 _GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters, __VA_ARGS__)
216#define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters,...) \
217 _GL_EXTERN_C_FUNC __VA_ARGS__ rettype rpl_func parameters
218
219/* _GL_FUNCDECL_SYS_NAME (func) expands to plain func if C++, and to
220 parenthesized func otherwise. Parenthesization is needed in C23 if
221 the function is like strchr and so is a qualifier-generic macro
222 that expands to something more complicated. */
223#ifdef __cplusplus
224# define _GL_FUNCDECL_SYS_NAME(func) func
225#else
226# define _GL_FUNCDECL_SYS_NAME(func) (func)
227#endif
228
229/* _GL_FUNCDECL_SYS (func, rettype, parameters, [attributes]);
230 declares the system function, named func, with the given prototype,
231 consisting of return type, parameters, and attributes.
232 Although attributes are optional, the comma before them is required
233 for portability to C17 and earlier. The attribute _GL_ATTRIBUTE_NOTHROW,
234 if needed, must be placed after the _GL_FUNCDECL_RPL invocation,
235 at the end of the declaration.
236 Examples:
237 _GL_FUNCDECL_SYS (getumask, mode_t, (void), ) _GL_ATTRIBUTE_NOTHROW;
238 _GL_FUNCDECL_SYS (posix_openpt, int, (int flags), _GL_ATTRIBUTE_NODISCARD);
239 */
240#define _GL_FUNCDECL_SYS(func,rettype,parameters,...) \
241 _GL_EXTERN_C_FUNC __VA_ARGS__ rettype _GL_FUNCDECL_SYS_NAME (func) parameters
242
243/* _GL_CXXALIAS_RPL (func, rettype, parameters);
244 declares a C++ alias called GNULIB_NAMESPACE::func
245 that redirects to rpl_func, if GNULIB_NAMESPACE is defined.
246 Example:
247 _GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...));
248
249 Wrapping rpl_func in an object with an inline conversion operator
250 avoids a reference to rpl_func unless GNULIB_NAMESPACE::func is
251 actually used in the program. */
252#define _GL_CXXALIAS_RPL(func,rettype,parameters) \
253 _GL_CXXALIAS_RPL_1 (func, rpl_##func, rettype, parameters)
254#if defined __cplusplus && defined GNULIB_NAMESPACE
255# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
256 namespace GNULIB_NAMESPACE \
257 { \
258 static const struct _gl_ ## func ## _wrapper \
259 { \
260 typedef rettype (*type) parameters; \
261 \
262 inline operator type () const \
263 { \
264 return ::rpl_func; \
265 } \
266 } func = {}; \
267 } \
268 _GL_EXTERN_C int _gl_cxxalias_dummy
269#else
270# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
271 _GL_EXTERN_C int _gl_cxxalias_dummy
272#endif
273
274/* _GL_CXXALIAS_MDA (func, rettype, parameters);
275 is to be used when func is a Microsoft deprecated alias, on native Windows.
276 It declares a C++ alias called GNULIB_NAMESPACE::func
277 that redirects to _func, if GNULIB_NAMESPACE is defined.
278 Example:
279 _GL_CXXALIAS_MDA (open, int, (const char *filename, int flags, ...));
280 */
281#define _GL_CXXALIAS_MDA(func,rettype,parameters) \
282 _GL_CXXALIAS_RPL_1 (func, _##func, rettype, parameters)
283
284/* _GL_CXXALIAS_RPL_CAST_1 (func, rpl_func, rettype, parameters);
285 is like _GL_CXXALIAS_RPL_1 (func, rpl_func, rettype, parameters);
286 except that the C function rpl_func may have a slightly different
287 declaration. A cast is used to silence the "invalid conversion" error
288 that would otherwise occur. */
289#if defined __cplusplus && defined GNULIB_NAMESPACE
290# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \
291 namespace GNULIB_NAMESPACE \
292 { \
293 static const struct _gl_ ## func ## _wrapper \
294 { \
295 typedef rettype (*type) parameters; \
296 \
297 inline operator type () const \
298 { \
299 return reinterpret_cast<type>(::rpl_func); \
300 } \
301 } func = {}; \
302 } \
303 _GL_EXTERN_C int _gl_cxxalias_dummy
304#else
305# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \
306 _GL_EXTERN_C int _gl_cxxalias_dummy
307#endif
308
309/* _GL_CXXALIAS_MDA_CAST (func, rettype, parameters);
310 is like _GL_CXXALIAS_MDA (func, rettype, parameters);
311 except that the C function func may have a slightly different declaration.
312 A cast is used to silence the "invalid conversion" error that would
313 otherwise occur. */
314#define _GL_CXXALIAS_MDA_CAST(func,rettype,parameters) \
315 _GL_CXXALIAS_RPL_CAST_1 (func, _##func, rettype, parameters)
316
317/* _GL_CXXALIAS_SYS (func, rettype, parameters);
318 declares a C++ alias called GNULIB_NAMESPACE::func
319 that redirects to the system provided function func, if GNULIB_NAMESPACE
320 is defined.
321 Example:
322 _GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...));
323
324 Wrapping func in an object with an inline conversion operator
325 avoids a reference to func unless GNULIB_NAMESPACE::func is
326 actually used in the program. */
327#if defined __cplusplus && defined GNULIB_NAMESPACE
328# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
329 namespace GNULIB_NAMESPACE \
330 { \
331 static const struct _gl_ ## func ## _wrapper \
332 { \
333 typedef rettype (*type) parameters; \
334 \
335 inline operator type () const \
336 { \
337 return ::func; \
338 } \
339 } func = {}; \
340 } \
341 _GL_EXTERN_C int _gl_cxxalias_dummy
342#else
343# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
344 _GL_EXTERN_C int _gl_cxxalias_dummy
345#endif
346
347/* _GL_CXXALIAS_SYS_CAST (func, rettype, parameters);
348 is like _GL_CXXALIAS_SYS (func, rettype, parameters);
349 except that the C function func may have a slightly different declaration.
350 A cast is used to silence the "invalid conversion" error that would
351 otherwise occur. */
352#if defined __cplusplus && defined GNULIB_NAMESPACE
353# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \
354 namespace GNULIB_NAMESPACE \
355 { \
356 static const struct _gl_ ## func ## _wrapper \
357 { \
358 typedef rettype (*type) parameters; \
359 \
360 inline operator type () const \
361 { \
362 return reinterpret_cast<type>(::func); \
363 } \
364 } func = {}; \
365 } \
366 _GL_EXTERN_C int _gl_cxxalias_dummy
367#else
368# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \
369 _GL_EXTERN_C int _gl_cxxalias_dummy
370#endif
371
372/* _GL_CXXALIAS_SYS_CAST2 (func, rettype, parameters, rettype2, parameters2);
373 is like _GL_CXXALIAS_SYS (func, rettype, parameters);
374 except that the C function is picked among a set of overloaded functions,
375 namely the one with rettype2 and parameters2. Two consecutive casts
376 are used to silence the "cannot find a match" and "invalid conversion"
377 errors that would otherwise occur. */
378#if defined __cplusplus && defined GNULIB_NAMESPACE
379 /* The outer cast must be a reinterpret_cast.
380 The inner cast: When the function is defined as a set of overloaded
381 functions, it works as a static_cast<>, choosing the designated variant.
382 When the function is defined as a single variant, it works as a
383 reinterpret_cast<>. The parenthesized cast syntax works both ways. */
384# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \
385 namespace GNULIB_NAMESPACE \
386 { \
387 static const struct _gl_ ## func ## _wrapper \
388 { \
389 typedef rettype (*type) parameters; \
390 \
391 inline operator type () const \
392 { \
393 return reinterpret_cast<type>((rettype2 (*) parameters2)(::func)); \
394 } \
395 } func = {}; \
396 } \
397 _GL_EXTERN_C int _gl_cxxalias_dummy
398#else
399# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \
400 _GL_EXTERN_C int _gl_cxxalias_dummy
401#endif
402
403/* _GL_CXXALIASWARN (func);
404 causes a warning to be emitted when ::func is used but not when
405 GNULIB_NAMESPACE::func is used. func must be defined without overloaded
406 variants. */
407#if defined __cplusplus && defined GNULIB_NAMESPACE
408# define _GL_CXXALIASWARN(func) \
409 _GL_CXXALIASWARN_1 (func, GNULIB_NAMESPACE)
410# define _GL_CXXALIASWARN_1(func,namespace) \
411 _GL_CXXALIASWARN_2 (func, namespace)
412/* To work around GCC bug <https://gcc.gnu.org/PR43881>,
413 we enable the warning only when not optimizing. */
414# if !(defined __GNUC__ && !defined __clang__ && __OPTIMIZE__)
415# define _GL_CXXALIASWARN_2(func,namespace) \
416 _GL_WARN_ON_USE (func, \
417 "The symbol ::" #func " refers to the system function. " \
418 "Use " #namespace "::" #func " instead.")
419# elif (__GNUC__ >= 3 || defined __clang__) && GNULIB_STRICT_CHECKING
420# define _GL_CXXALIASWARN_2(func,namespace) \
421 extern __typeof__ (func) func
422# else
423# define _GL_CXXALIASWARN_2(func,namespace) \
424 _GL_EXTERN_C int _gl_cxxalias_dummy
425# endif
426#else
427# define _GL_CXXALIASWARN(func) \
428 _GL_EXTERN_C int _gl_cxxalias_dummy
429#endif
430
431/* _GL_CXXALIASWARN1 (func, rettype, parameters_and_attributes);
432 causes a warning to be emitted when the given overloaded variant of ::func
433 is used but not when GNULIB_NAMESPACE::func is used. */
434#if defined __cplusplus && defined GNULIB_NAMESPACE
435# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \
436 _GL_CXXALIASWARN1_1 (func, rettype, parameters_and_attributes, \
437 GNULIB_NAMESPACE)
438# define _GL_CXXALIASWARN1_1(func,rettype,parameters_and_attributes,namespace) \
439 _GL_CXXALIASWARN1_2 (func, rettype, parameters_and_attributes, namespace)
440/* To work around GCC bug <https://gcc.gnu.org/PR43881>,
441 we enable the warning only when not optimizing. */
442# if !(defined __GNUC__ && !defined __clang__ && __OPTIMIZE__)
443# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \
444 _GL_WARN_ON_USE_CXX (func, rettype, rettype, parameters_and_attributes, \
445 "The symbol ::" #func " refers to the system function. " \
446 "Use " #namespace "::" #func " instead.")
447# else
448# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \
449 _GL_EXTERN_C int _gl_cxxalias_dummy
450# endif
451#else
452# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \
453 _GL_EXTERN_C int _gl_cxxalias_dummy
454#endif
455
456#endif /* _GL_CXXDEFS_H */
457
458/* The definition of _Noreturn is copied here. */
459/* A C macro for declaring that a function does not return.
460 Copyright (C) 2011-2025 Free Software Foundation, Inc.
461
462 This program is free software: you can redistribute it and/or modify it
463 under the terms of the GNU Lesser General Public License as published
464 by the Free Software Foundation; either version 2 of the License, or
465 (at your option) any later version.
466
467 This program is distributed in the hope that it will be useful,
468 but WITHOUT ANY WARRANTY; without even the implied warranty of
469 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
470 Lesser General Public License for more details.
471
472 You should have received a copy of the GNU Lesser General Public License
473 along with this program. If not, see <https://www.gnu.org/licenses/>. */
474
475/* The _Noreturn keyword of C11.
476 Do not use [[noreturn]], because with it the syntax
477 extern _Noreturn void func (...);
478 would not be valid; such a declaration would be valid only with 'extern'
479 and '_Noreturn' swapped, or without the 'extern' keyword. However, some
480 AIX system header files and several gnulib header files use precisely
481 this syntax with 'extern'. So even though C23 deprecates _Noreturn,
482 it is currently more portable to prefer it to [[noreturn]].
483
484 Also, do not try to work around LLVM bug 59792 (clang 15 or earlier).
485 This rare bug can be worked around by compiling with 'clang -D_Noreturn=',
486 though the workaround may generate many false-alarm warnings. */
487#ifndef _Noreturn
488# if ((!defined __cplusplus || defined __clang__) \
489 && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0)))
490 /* _Noreturn works as-is. */
491# elif (2 < __GNUC__ + (8 <= __GNUC_MINOR__) || defined __clang__ \
492 || 0x5110 <= __SUNPRO_C)
493 /* Prefer __attribute__ ((__noreturn__)) to plain _Noreturn even if the
494 latter works, as 'gcc -std=gnu99 -Wpedantic' warns about _Noreturn. */
495# define _Noreturn __attribute__ ((__noreturn__))
496# elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0)
497# define _Noreturn __declspec (noreturn)
498# else
499# define _Noreturn
500# endif
501#endif
502
503/* The definition of _GL_ARG_NONNULL is copied here. */
504/* A C macro for declaring that specific arguments must not be NULL.
505 Copyright (C) 2009-2025 Free Software Foundation, Inc.
506
507 This program is free software: you can redistribute it and/or modify it
508 under the terms of the GNU Lesser General Public License as published
509 by the Free Software Foundation; either version 2 of the License, or
510 (at your option) any later version.
511
512 This program is distributed in the hope that it will be useful,
513 but WITHOUT ANY WARRANTY; without even the implied warranty of
514 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
515 Lesser General Public License for more details.
516
517 You should have received a copy of the GNU Lesser General Public License
518 along with this program. If not, see <https://www.gnu.org/licenses/>. */
519
520/* _GL_ARG_NONNULL((n,...,m)) tells the compiler and static analyzer tools
521 that the values passed as arguments n, ..., m must be non-NULL pointers.
522 n = 1 stands for the first argument, n = 2 for the second argument etc. */
523#ifndef _GL_ARG_NONNULL
524# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || defined __clang__
525# define _GL_ARG_NONNULL(params) __attribute__ ((__nonnull__ params))
526# else
527# define _GL_ARG_NONNULL(params)
528# endif
529#endif
530
531/* The definition of _GL_WARN_ON_USE is copied here. */
532/* A C macro for emitting warnings if a function is used.
533 Copyright (C) 2010-2025 Free Software Foundation, Inc.
534
535 This program is free software: you can redistribute it and/or modify it
536 under the terms of the GNU Lesser General Public License as published
537 by the Free Software Foundation; either version 2 of the License, or
538 (at your option) any later version.
539
540 This program is distributed in the hope that it will be useful,
541 but WITHOUT ANY WARRANTY; without even the implied warranty of
542 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
543 Lesser General Public License for more details.
544
545 You should have received a copy of the GNU Lesser General Public License
546 along with this program. If not, see <https://www.gnu.org/licenses/>. */
547
548/* _GL_WARN_ON_USE (function, "literal string") issues a declaration
549 for FUNCTION which will then trigger a compiler warning containing
550 the text of "literal string" anywhere that function is called, if
551 supported by the compiler. If the compiler does not support this
552 feature, the macro expands to an unused extern declaration.
553
554 _GL_WARN_ON_USE_ATTRIBUTE ("literal string") expands to the
555 attribute used in _GL_WARN_ON_USE. If the compiler does not support
556 this feature, it expands to empty.
557
558 These macros are useful for marking a function as a potential
559 portability trap, with the intent that "literal string" include
560 instructions on the replacement function that should be used
561 instead.
562 _GL_WARN_ON_USE is for functions with 'extern' linkage.
563 _GL_WARN_ON_USE_ATTRIBUTE is for functions with 'static' or 'inline'
564 linkage.
565
566 _GL_WARN_ON_USE should not be used more than once for a given function
567 in a given compilation unit (because this may generate a warning even
568 if the function is never called).
569
570 However, one of the reasons that a function is a portability trap is
571 if it has the wrong signature. Declaring FUNCTION with a different
572 signature in C is a compilation error, so this macro must use the
573 same type as any existing declaration so that programs that avoid
574 the problematic FUNCTION do not fail to compile merely because they
575 included a header that poisoned the function. But this implies that
576 _GL_WARN_ON_USE is only safe to use if FUNCTION is known to already
577 have a declaration. Use of this macro implies that there must not
578 be any other macro hiding the declaration of FUNCTION; but
579 undefining FUNCTION first is part of the poisoning process anyway
580 (although for symbols that are provided only via a macro, the result
581 is a compilation error rather than a warning containing
582 "literal string"). Also note that in C++, it is only safe to use if
583 FUNCTION has no overloads.
584
585 For an example, it is possible to poison 'getline' by:
586 - adding a call to gl_WARN_ON_USE_PREPARE([[#include <stdio.h>]],
587 [getline]) in configure.ac, which potentially defines
588 HAVE_RAW_DECL_GETLINE
589 - adding this code to a header that wraps the system <stdio.h>:
590 #undef getline
591 #if HAVE_RAW_DECL_GETLINE
592 _GL_WARN_ON_USE (getline, "getline is required by POSIX 2008, but"
593 "not universally present; use the gnulib module getline");
594 #endif
595
596 It is not possible to directly poison global variables. But it is
597 possible to write a wrapper accessor function, and poison that
598 (less common usage, like &environ, will cause a compilation error
599 rather than issue the nice warning, but the end result of informing
600 the developer about their portability problem is still achieved):
601 #if HAVE_RAW_DECL_ENVIRON
602 static char ***
603 rpl_environ (void) { return &environ; }
604 _GL_WARN_ON_USE (rpl_environ, "environ is not always properly declared");
605 # undef environ
606 # define environ (*rpl_environ ())
607 #endif
608 or better (avoiding contradictory use of 'static' and 'extern'):
609 #if HAVE_RAW_DECL_ENVIRON
610 static char ***
611 _GL_WARN_ON_USE_ATTRIBUTE ("environ is not always properly declared")
612 rpl_environ (void) { return &environ; }
613 # undef environ
614 # define environ (*rpl_environ ())
615 #endif
616 */
617#ifndef _GL_WARN_ON_USE
618
619# if (4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)) && !defined __clang__
620/* A compiler attribute is available in gcc versions 4.3.0 and later. */
621# define _GL_WARN_ON_USE(function, message) \
622_GL_WARN_EXTERN_C __typeof__ (function) function __attribute__ ((__warning__ (message)))
623# define _GL_WARN_ON_USE_ATTRIBUTE(message) \
624 __attribute__ ((__warning__ (message)))
625# elif __clang_major__ >= 4
626/* Another compiler attribute is available in clang. */
627# define _GL_WARN_ON_USE(function, message) \
628_GL_WARN_EXTERN_C __typeof__ (function) function \
629 __attribute__ ((__diagnose_if__ (1, message, "warning")))
630# define _GL_WARN_ON_USE_ATTRIBUTE(message) \
631 __attribute__ ((__diagnose_if__ (1, message, "warning")))
632# elif (__GNUC__ >= 3 || defined __clang__) && GNULIB_STRICT_CHECKING
633/* Verify the existence of the function. */
634# define _GL_WARN_ON_USE(function, message) \
635_GL_WARN_EXTERN_C __typeof__ (function) function
636# define _GL_WARN_ON_USE_ATTRIBUTE(message)
637# else /* Unsupported. */
638# define _GL_WARN_ON_USE(function, message) \
639_GL_WARN_EXTERN_C int _gl_warn_on_use
640# define _GL_WARN_ON_USE_ATTRIBUTE(message)
641# endif
642#endif
643
644/* _GL_WARN_ON_USE_CXX (function, rettype_gcc, rettype_clang, parameters_and_attributes, "message")
645 is like _GL_WARN_ON_USE (function, "message"), except that in C++ mode the
646 function is declared with the given prototype, consisting of return type,
647 parameters, and attributes.
648 This variant is useful for overloaded functions in C++. _GL_WARN_ON_USE does
649 not work in this case. */
650#ifndef _GL_WARN_ON_USE_CXX
651# if !defined __cplusplus
652# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
653 _GL_WARN_ON_USE (function, msg)
654# else
655# if (4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)) && !defined __clang__
656/* A compiler attribute is available in gcc versions 4.3.0 and later. */
657# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
658extern rettype_gcc function parameters_and_attributes \
659 __attribute__ ((__warning__ (msg)))
660# elif __clang_major__ >= 4
661/* Another compiler attribute is available in clang. */
662# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
663extern rettype_clang function parameters_and_attributes \
664 __attribute__ ((__diagnose_if__ (1, msg, "warning")))
665# elif (__GNUC__ >= 3 || defined __clang__) && GNULIB_STRICT_CHECKING
666/* Verify the existence of the function. */
667# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
668extern rettype_gcc function parameters_and_attributes
669# else /* Unsupported. */
670# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
671_GL_WARN_EXTERN_C int _gl_warn_on_use
672# endif
673# endif
674#endif
675
676/* _GL_WARN_EXTERN_C declaration;
677 performs the declaration with C linkage. */
678#ifndef _GL_WARN_EXTERN_C
679# if defined __cplusplus
680# define _GL_WARN_EXTERN_C extern "C"
681# else
682# define _GL_WARN_EXTERN_C extern
683# endif
684#endif
685
686/* =========== Thread types and macros =========== */
687
688#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
689# if 0
690# include "windows-thread.h"
691# if 1
692# define pthread_t rpl_pthread_t
693# define pthread_attr_t rpl_pthread_attr_t
694# endif
695# if !GNULIB_defined_pthread_thread_types
696typedef glwthread_thread_t pthread_t;
697typedef unsigned int pthread_attr_t;
698# define GNULIB_defined_pthread_thread_types 1
699# endif
700# else
701# if 1
702# define pthread_t rpl_pthread_t
703# define pthread_attr_t rpl_pthread_attr_t
704# endif
705# if !GNULIB_defined_pthread_thread_types
706typedef int pthread_t;
707typedef unsigned int pthread_attr_t;
708# define GNULIB_defined_pthread_thread_types 1
709# endif
710# endif
711# undef PTHREAD_CREATE_JOINABLE
712# undef PTHREAD_CREATE_DETACHED
713# define PTHREAD_CREATE_JOINABLE 0
714# define PTHREAD_CREATE_DETACHED 1
715#else
716# if !1
717# if !GNULIB_defined_pthread_thread_types
718typedef int pthread_t;
719typedef unsigned int pthread_attr_t;
720# define GNULIB_defined_pthread_thread_types 1
721# endif
722# endif
723# if !1
724# define PTHREAD_CREATE_JOINABLE 0
725# define PTHREAD_CREATE_DETACHED 1
726# endif
727#endif
728
729/* =========== Once-only control (initialization) types and macros ========== */
730
731#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
732# if 1
733# include "windows-once.h"
734# if 1
735# define pthread_once_t rpl_pthread_once_t
736# endif
737# if !GNULIB_defined_pthread_once_types
738typedef glwthread_once_t pthread_once_t;
739# define GNULIB_defined_pthread_once_types 1
740# endif
741# undef PTHREAD_ONCE_INIT
742# define PTHREAD_ONCE_INIT GLWTHREAD_ONCE_INIT
743# else
744# if 1
745# define pthread_once_t rpl_pthread_once_t
746# endif
747# if !GNULIB_defined_pthread_once_types
748typedef int pthread_once_t;
749# define GNULIB_defined_pthread_once_types 1
750# endif
751# undef PTHREAD_ONCE_INIT
752# define PTHREAD_ONCE_INIT { 0 }
753# endif
754#else
755# if !1
756# if !GNULIB_defined_pthread_once_types
757typedef int pthread_once_t;
758# define GNULIB_defined_pthread_once_types 1
759# endif
760# undef PTHREAD_ONCE_INIT
761# define PTHREAD_ONCE_INIT { 0 }
762# endif
763#endif
764
765/* =========== Mutex types and macros =========== */
766
767#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
768# if 0
769# include "windows-timedmutex.h"
770# include "windows-timedrecmutex.h"
771# if 1
772# define pthread_mutex_t rpl_pthread_mutex_t
773# define pthread_mutexattr_t rpl_pthread_mutexattr_t
774# endif
775# if !GNULIB_defined_pthread_mutex_types
776typedef struct
777 {
778 int type;
779 union
780 {
781 glwthread_timedmutex_t u_timedmutex;
782 glwthread_timedrecmutex_t u_timedrecmutex;
783 }
784 u;
785 }
786 pthread_mutex_t;
787typedef unsigned int pthread_mutexattr_t;
788# define GNULIB_defined_pthread_mutex_types 1
789# endif
790# undef PTHREAD_MUTEX_INITIALIZER
791# define PTHREAD_MUTEX_INITIALIZER { 1, { GLWTHREAD_TIMEDMUTEX_INIT } }
792# else
793# if 1
794# define pthread_mutex_t rpl_pthread_mutex_t
795# define pthread_mutexattr_t rpl_pthread_mutexattr_t
796# endif
797# if !GNULIB_defined_pthread_mutex_types
798typedef int pthread_mutex_t;
799typedef unsigned int pthread_mutexattr_t;
800# define GNULIB_defined_pthread_mutex_types 1
801# endif
802# undef PTHREAD_MUTEX_INITIALIZER
803# define PTHREAD_MUTEX_INITIALIZER { 0 }
804# endif
805# undef PTHREAD_MUTEX_DEFAULT
806# undef PTHREAD_MUTEX_NORMAL
807# undef PTHREAD_MUTEX_ERRORCHECK
808# undef PTHREAD_MUTEX_RECURSIVE
809# define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
810# define PTHREAD_MUTEX_NORMAL 0
811# define PTHREAD_MUTEX_ERRORCHECK 1
812# define PTHREAD_MUTEX_RECURSIVE 2
813# undef PTHREAD_MUTEX_STALLED
814# undef PTHREAD_MUTEX_ROBUST
815# define PTHREAD_MUTEX_STALLED 0
816# define PTHREAD_MUTEX_ROBUST 1
817#else
818# if !1
819# if !GNULIB_defined_pthread_mutex_types
820typedef int pthread_mutex_t;
821typedef unsigned int pthread_mutexattr_t;
822# define GNULIB_defined_pthread_mutex_types 1
823# endif
824# undef PTHREAD_MUTEX_INITIALIZER
825# define PTHREAD_MUTEX_INITIALIZER { 0 }
826# endif
827# if !1
828# define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
829# define PTHREAD_MUTEX_NORMAL 0
830# define PTHREAD_MUTEX_ERRORCHECK 1
831# define PTHREAD_MUTEX_RECURSIVE 2
832# endif
833# if !1
834# define PTHREAD_MUTEX_STALLED 0
835# define PTHREAD_MUTEX_ROBUST 1
836# endif
837#endif
838
839/* =========== Read-write lock types and macros =========== */
840
841#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
842# if 0
843# include "windows-timedrwlock.h"
844# if 1
845# define pthread_rwlock_t rpl_pthread_rwlock_t
846# define pthread_rwlockattr_t rpl_pthread_rwlockattr_t
847# endif
848# if !GNULIB_defined_pthread_rwlock_types
849typedef glwthread_timedrwlock_t pthread_rwlock_t;
850typedef unsigned int pthread_rwlockattr_t;
851# define GNULIB_defined_pthread_rwlock_types 1
852# endif
853# undef PTHREAD_RWLOCK_INITIALIZER
854# define PTHREAD_RWLOCK_INITIALIZER GLWTHREAD_TIMEDRWLOCK_INIT
855# else
856# if 1
857# define pthread_rwlock_t rpl_pthread_rwlock_t
858# define pthread_rwlockattr_t rpl_pthread_rwlockattr_t
859# endif
860# if !GNULIB_defined_pthread_rwlock_types
861typedef int pthread_rwlock_t;
862typedef unsigned int pthread_rwlockattr_t;
863# define GNULIB_defined_pthread_rwlock_types 1
864# endif
865# undef PTHREAD_RWLOCK_INITIALIZER
866# define PTHREAD_RWLOCK_INITIALIZER { 0 }
867# endif
868#elif 0 && 0 /* i.e. PTHREAD_RWLOCK_UNIMPLEMENTED */
869# if 1
870# define pthread_rwlock_t rpl_pthread_rwlock_t
871# define pthread_rwlockattr_t rpl_pthread_rwlockattr_t
872# endif
873# if !GNULIB_defined_pthread_rwlock_types
874typedef struct
875 {
876 pthread_mutex_t lock; /* protects the remaining fields */
877 pthread_cond_t waiting_readers; /* waiting readers */
878 pthread_cond_t waiting_writers; /* waiting writers */
879 unsigned int waiting_writers_count; /* number of waiting writers */
880 int runcount; /* number of readers running, or -1 when a writer runs */
881 }
882 pthread_rwlock_t;
883typedef unsigned int pthread_rwlockattr_t;
884# define GNULIB_defined_pthread_rwlock_types 1
885# endif
886# undef PTHREAD_RWLOCK_INITIALIZER
887# define PTHREAD_RWLOCK_INITIALIZER \
888 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
889#elif 0 && 0 /* i.e. PTHREAD_RWLOCK_BAD_WAITQUEUE */
890/* Use rwlocks of kind PREFER_WRITER or PREFER_WRITER_NONRECURSIVE instead of
891 the DEFAULT. */
892# undef PTHREAD_RWLOCK_INITIALIZER
893# define PTHREAD_RWLOCK_INITIALIZER PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
894#else
895# if 1
896# if !defined PTHREAD_RWLOCK_INITIALIZER && defined PTHREAD_RWLOCK_INITIALIZER_NP /* z/OS */
897# define PTHREAD_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER_NP
898# endif
899# else
900# if !GNULIB_defined_pthread_rwlock_types
901typedef int pthread_rwlock_t;
902typedef unsigned int pthread_rwlockattr_t;
903# define GNULIB_defined_pthread_rwlock_types 1
904# endif
905# undef PTHREAD_RWLOCK_INITIALIZER
906# define PTHREAD_RWLOCK_INITIALIZER { 0 }
907# endif
908#endif
909
910/* =========== Condition variable types and macros =========== */
911
912#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
913# if 0
914# include "windows-cond.h"
915# if 1
916# define pthread_cond_t rpl_pthread_cond_t
917# define pthread_condattr_t rpl_pthread_condattr_t
918# endif
919# if !GNULIB_defined_pthread_cond_types
920typedef glwthread_cond_t pthread_cond_t;
921typedef unsigned int pthread_condattr_t;
922# define GNULIB_defined_pthread_cond_types 1
923# endif
924# undef PTHREAD_COND_INITIALIZER
925# define PTHREAD_COND_INITIALIZER GLWTHREAD_COND_INIT
926# else
927# if 1
928# define pthread_cond_t rpl_pthread_cond_t
929# define pthread_condattr_t rpl_pthread_condattr_t
930# endif
931# if !GNULIB_defined_pthread_cond_types
932typedef int pthread_cond_t;
933typedef unsigned int pthread_condattr_t;
934# define GNULIB_defined_pthread_cond_types 1
935# endif
936# undef PTHREAD_COND_INITIALIZER
937# define PTHREAD_COND_INITIALIZER { 0 }
938# endif
939#else
940# if !1
941# if !GNULIB_defined_pthread_cond_types
942typedef int pthread_cond_t;
943typedef unsigned int pthread_condattr_t;
944# define GNULIB_defined_pthread_cond_types 1
945# endif
946# undef PTHREAD_COND_INITIALIZER
947# define PTHREAD_COND_INITIALIZER { 0 }
948# endif
949#endif
950
951/* =========== Thread-specific storage types and macros =========== */
952
953#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
954# if 0
955# include "windows-tls.h"
956# if 1
957# define pthread_key_t rpl_pthread_key_t
958# endif
959# if !GNULIB_defined_pthread_tss_types
960typedef glwthread_tls_key_t pthread_key_t;
961# define GNULIB_defined_pthread_tss_types 1
962# endif
963# undef PTHREAD_DESTRUCTOR_ITERATIONS
964# define PTHREAD_DESTRUCTOR_ITERATIONS GLWTHREAD_DESTRUCTOR_ITERATIONS
965# else
966# if 1
967# define pthread_key_t rpl_pthread_key_t
968# endif
969# if !GNULIB_defined_pthread_tss_types
970typedef void ** pthread_key_t;
971# define GNULIB_defined_pthread_tss_types 1
972# endif
973# undef PTHREAD_DESTRUCTOR_ITERATIONS
974# define PTHREAD_DESTRUCTOR_ITERATIONS 0
975# endif
976#else
977# if !1
978# if !GNULIB_defined_pthread_tss_types
979typedef void ** pthread_key_t;
980# define GNULIB_defined_pthread_tss_types 1
981# endif
982# undef PTHREAD_DESTRUCTOR_ITERATIONS
983# define PTHREAD_DESTRUCTOR_ITERATIONS 0
984# endif
985#endif
986
987/* =========== Spinlock types and macros =========== */
988
989#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
990# if 0
991# include "windows-spin.h"
992# if 1
993# define pthread_spinlock_t rpl_pthread_spinlock_t
994# endif
995# if !GNULIB_defined_pthread_spin_types
996typedef glwthread_spinlock_t pthread_spinlock_t;
997# define GNULIB_defined_pthread_spin_types 1
998# endif
999# else
1000# if 1
1001# define pthread_spinlock_t rpl_pthread_spinlock_t
1002# endif
1003# if !GNULIB_defined_pthread_spin_types
1004typedef pthread_mutex_t pthread_spinlock_t;
1005# define GNULIB_defined_pthread_spin_types 1
1006# endif
1007# endif
1008# undef PTHREAD_PROCESS_PRIVATE
1009# undef PTHREAD_PROCESS_SHARED
1010# define PTHREAD_PROCESS_PRIVATE 0
1011# define PTHREAD_PROCESS_SHARED 1
1012#else
1013# if 1
1014/* <pthread.h> exists and defines pthread_spinlock_t. */
1015# if !1 || 0
1016/* If the 'pthread-spin' module is in use, it defines all the pthread_spin*
1017 functions. Prepare for it by overriding pthread_spinlock_t if that might
1018 be needed. */
1019# if !(((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) \
1020 || __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 1)) \
1021 || (((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) \
1022 && !defined __ANDROID__) \
1023 || __clang_major__ >= 3)) \
1024 && !defined __ibmxl__)
1025/* We can't use GCC built-ins. Approximate spinlocks with mutexes. */
1026# if !GNULIB_defined_pthread_spin_types
1027# define pthread_spinlock_t pthread_mutex_t
1028# define GNULIB_defined_pthread_spin_types 1
1029# endif
1030# endif
1031# endif
1032# else
1033/* Approximate spinlocks with mutexes. */
1034# if !GNULIB_defined_pthread_spin_types
1035typedef pthread_mutex_t pthread_spinlock_t;
1036# define GNULIB_defined_pthread_spin_types 1
1037# endif
1038# endif
1039# if !1
1040# define PTHREAD_PROCESS_PRIVATE 0
1041# define PTHREAD_PROCESS_SHARED 1
1042# endif
1043#endif
1044
1045/* =========== Other types and macros =========== */
1046
1047#if !1
1048# if !GNULIB_defined_other_pthread_types
1049typedef int pthread_barrier_t;
1050typedef unsigned int pthread_barrierattr_t;
1051# define GNULIB_defined_other_pthread_types 1
1052# endif
1053#endif
1054
1055#if !defined PTHREAD_CANCELED
1056
1057# define PTHREAD_BARRIER_SERIAL_THREAD (-1)
1058
1059# define PTHREAD_CANCEL_DEFERRED 0
1060# define PTHREAD_CANCEL_ASYNCHRONOUS 1
1061
1062# define PTHREAD_CANCEL_ENABLE 0
1063# define PTHREAD_CANCEL_DISABLE 1
1064
1065# define PTHREAD_CANCELED ((void *) -1)
1066
1067# define PTHREAD_INHERIT_SCHED 0
1068# define PTHREAD_EXPLICIT_SCHED 1
1069
1070# define PTHREAD_PRIO_NONE 0
1071# define PTHREAD_PRIO_INHERIT 1
1072# define PTHREAD_PRIO_PROTECT 2
1073
1074# define PTHREAD_SCOPE_SYSTEM 0
1075# define PTHREAD_SCOPE_PROCESS 1
1076
1077#endif
1078
1079/* =========== Thread functions =========== */
1080
1081#if 0
1082/* The 'restrict' qualifier on ARG is nonsense, but POSIX specifies it this way.
1083 Sigh. */
1084# if 0
1085# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1086# undef pthread_create
1087# define pthread_create rpl_pthread_create
1088# endif
1089_GL_FUNCDECL_RPL (pthread_create, int,
1090 (pthread_t *restrict threadp,
1091 const pthread_attr_t *restrict attr,
1092 void * (*mainfunc) (void *), void *restrict arg),
1093 _GL_ARG_NONNULL ((1, 3)));
1094_GL_CXXALIAS_RPL (pthread_create, int,
1095 (pthread_t *restrict threadp,
1096 const pthread_attr_t *restrict attr,
1097 void * (*mainfunc) (void *), void *restrict arg));
1098# else
1099# if !1
1100_GL_FUNCDECL_SYS (pthread_create, int,
1101 (pthread_t *restrict threadp,
1102 const pthread_attr_t *restrict attr,
1103 void * (*mainfunc) (void *), void *restrict arg),
1104 _GL_ARG_NONNULL ((1, 3)));
1105# endif
1106_GL_CXXALIAS_SYS_CAST (pthread_create, int,
1107 (pthread_t *restrict threadp,
1108 const pthread_attr_t *restrict attr,
1109 void * (*mainfunc) (void *), void *restrict arg));
1110# endif
1111# if __GLIBC__ >= 2
1112_GL_CXXALIASWARN (pthread_create);
1113# endif
1114#elif defined GNULIB_POSIXCHECK
1115# if HAVE_RAW_DECL_PTHREAD_CREATE
1116_GL_WARN_ON_USE (pthread_create, "pthread_create is not portable - "
1117 "use gnulib module pthread-thread for portability");
1118# endif
1119#endif
1120
1121#if 0
1122# if 0
1123# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1124# undef pthread_attr_init
1125# define pthread_attr_init rpl_pthread_attr_init
1126# endif
1127_GL_FUNCDECL_RPL (pthread_attr_init, int, (pthread_attr_t *attr),
1128 _GL_ARG_NONNULL ((1)));
1129_GL_CXXALIAS_RPL (pthread_attr_init, int, (pthread_attr_t *attr));
1130# else
1131# if !1
1132_GL_FUNCDECL_SYS (pthread_attr_init, int, (pthread_attr_t *attr),
1133 _GL_ARG_NONNULL ((1)));
1134# endif
1135_GL_CXXALIAS_SYS (pthread_attr_init, int, (pthread_attr_t *attr));
1136# endif
1137# if __GLIBC__ >= 2
1138_GL_CXXALIASWARN (pthread_attr_init);
1139# endif
1140#elif defined GNULIB_POSIXCHECK
1141# if HAVE_RAW_DECL_PTHREAD_ATTR_INIT
1142_GL_WARN_ON_USE (pthread_attr_init, "pthread_attr_init is not portable - "
1143 "use gnulib module pthread-thread for portability");
1144# endif
1145#endif
1146
1147#if 0
1148# if 0
1149# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1150# undef pthread_attr_getdetachstate
1151# define pthread_attr_getdetachstate rpl_pthread_attr_getdetachstate
1152# endif
1153_GL_FUNCDECL_RPL (pthread_attr_getdetachstate, int,
1154 (const pthread_attr_t *attr, int *detachstatep),
1155 _GL_ARG_NONNULL ((1, 2)));
1156_GL_CXXALIAS_RPL (pthread_attr_getdetachstate, int,
1157 (const pthread_attr_t *attr, int *detachstatep));
1158# else
1159# if !1
1160_GL_FUNCDECL_SYS (pthread_attr_getdetachstate, int,
1161 (const pthread_attr_t *attr, int *detachstatep),
1162 _GL_ARG_NONNULL ((1, 2)));
1163# endif
1164_GL_CXXALIAS_SYS (pthread_attr_getdetachstate, int,
1165 (const pthread_attr_t *attr, int *detachstatep));
1166# endif
1167# if __GLIBC__ >= 2
1168_GL_CXXALIASWARN (pthread_attr_getdetachstate);
1169# endif
1170#elif defined GNULIB_POSIXCHECK
1171# if HAVE_RAW_DECL_PTHREAD_ATTR_GETDETACHSTATE
1172_GL_WARN_ON_USE (pthread_attr_getdetachstate, "pthread_attr_getdetachstate is not portable - "
1173 "use gnulib module pthread-thread for portability");
1174# endif
1175#endif
1176
1177#if 0
1178# if 0
1179# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1180# undef pthread_attr_setdetachstate
1181# define pthread_attr_setdetachstate rpl_pthread_attr_setdetachstate
1182# endif
1183_GL_FUNCDECL_RPL (pthread_attr_setdetachstate, int,
1184 (pthread_attr_t *attr, int detachstate),
1185 _GL_ARG_NONNULL ((1)));
1186_GL_CXXALIAS_RPL (pthread_attr_setdetachstate, int,
1187 (pthread_attr_t *attr, int detachstate));
1188# else
1189# if !1
1190_GL_FUNCDECL_SYS (pthread_attr_setdetachstate, int,
1191 (pthread_attr_t *attr, int detachstate),
1192 _GL_ARG_NONNULL ((1)));
1193# endif
1194_GL_CXXALIAS_SYS (pthread_attr_setdetachstate, int,
1195 (pthread_attr_t *attr, int detachstate));
1196# endif
1197# if __GLIBC__ >= 2
1198_GL_CXXALIASWARN (pthread_attr_setdetachstate);
1199# endif
1200#elif defined GNULIB_POSIXCHECK
1201# if HAVE_RAW_DECL_PTHREAD_ATTR_SETDETACHSTATE
1202_GL_WARN_ON_USE (pthread_attr_setdetachstate, "pthread_attr_setdetachstate is not portable - "
1203 "use gnulib module pthread-thread for portability");
1204# endif
1205#endif
1206
1207#if 0
1208# if 0
1209# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1210# undef pthread_attr_destroy
1211# define pthread_attr_destroy rpl_pthread_attr_destroy
1212# endif
1213_GL_FUNCDECL_RPL (pthread_attr_destroy, int, (pthread_attr_t *attr),
1214 _GL_ARG_NONNULL ((1)));
1215_GL_CXXALIAS_RPL (pthread_attr_destroy, int, (pthread_attr_t *attr));
1216# else
1217# if !1
1218_GL_FUNCDECL_SYS (pthread_attr_destroy, int, (pthread_attr_t *attr),
1219 _GL_ARG_NONNULL ((1)));
1220# endif
1221_GL_CXXALIAS_SYS (pthread_attr_destroy, int, (pthread_attr_t *attr));
1222# endif
1223# if __GLIBC__ >= 2
1224_GL_CXXALIASWARN (pthread_attr_destroy);
1225# endif
1226#elif defined GNULIB_POSIXCHECK
1227# if HAVE_RAW_DECL_PTHREAD_ATTR_DESTROY
1228_GL_WARN_ON_USE (pthread_attr_destroy, "pthread_attr_destroy is not portable - "
1229 "use gnulib module pthread-thread for portability");
1230# endif
1231#endif
1232
1233#if 0
1234# if 0
1235# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1236# undef pthread_self
1237# define pthread_self rpl_pthread_self
1238# endif
1239_GL_FUNCDECL_RPL (pthread_self, pthread_t, (void), _GL_ATTRIBUTE_PURE);
1240_GL_CXXALIAS_RPL (pthread_self, pthread_t, (void));
1241# else
1242# if !1
1243_GL_FUNCDECL_SYS (pthread_self, pthread_t, (void), _GL_ATTRIBUTE_PURE);
1244# endif
1245_GL_CXXALIAS_SYS (pthread_self, pthread_t, (void));
1246# endif
1247# if __GLIBC__ >= 2
1248_GL_CXXALIASWARN (pthread_self);
1249# endif
1250#elif defined GNULIB_POSIXCHECK
1251# if HAVE_RAW_DECL_PTHREAD_SELF
1252_GL_WARN_ON_USE (pthread_self, "pthread_self is not portable - "
1253 "use gnulib module pthread-thread for portability");
1254# endif
1255#endif
1256
1257#if 0
1258# if 0
1259# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1260# undef pthread_equal
1261# define pthread_equal rpl_pthread_equal
1262# endif
1263_GL_FUNCDECL_RPL (pthread_equal, int, (pthread_t thread1, pthread_t thread2), );
1264_GL_CXXALIAS_RPL (pthread_equal, int, (pthread_t thread1, pthread_t thread2));
1265# else
1266# if !1
1267_GL_FUNCDECL_SYS (pthread_equal, int, (pthread_t thread1, pthread_t thread2), );
1268# endif
1269_GL_CXXALIAS_SYS (pthread_equal, int, (pthread_t thread1, pthread_t thread2));
1270# endif
1271# if __GLIBC__ >= 2
1272_GL_CXXALIASWARN (pthread_equal);
1273# endif
1274#elif defined GNULIB_POSIXCHECK
1275# if HAVE_RAW_DECL_PTHREAD_EQUAL
1276_GL_WARN_ON_USE (pthread_equal, "pthread_equal is not portable - "
1277 "use gnulib module pthread-thread for portability");
1278# endif
1279#endif
1280
1281#if 0
1282# if 0
1283# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1284# undef pthread_detach
1285# define pthread_detach rpl_pthread_detach
1286# endif
1287_GL_FUNCDECL_RPL (pthread_detach, int, (pthread_t thread), );
1288_GL_CXXALIAS_RPL (pthread_detach, int, (pthread_t thread));
1289# else
1290# if !1
1291_GL_FUNCDECL_SYS (pthread_detach, int, (pthread_t thread), );
1292# endif
1293_GL_CXXALIAS_SYS (pthread_detach, int, (pthread_t thread));
1294# endif
1295# if __GLIBC__ >= 2
1296_GL_CXXALIASWARN (pthread_detach);
1297# endif
1298#elif defined GNULIB_POSIXCHECK
1299# if HAVE_RAW_DECL_PTHREAD_DETACH
1300_GL_WARN_ON_USE (pthread_detach, "pthread_detach is not portable - "
1301 "use gnulib module pthread-thread for portability");
1302# endif
1303#endif
1304
1305#if 0
1306# if 0
1307# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1308# undef pthread_join
1309# define pthread_join rpl_pthread_join
1310# endif
1311_GL_FUNCDECL_RPL (pthread_join, int, (pthread_t thread, void **valuep), );
1312_GL_CXXALIAS_RPL (pthread_join, int, (pthread_t thread, void **valuep));
1313# else
1314# if !1
1315_GL_FUNCDECL_SYS (pthread_join, int, (pthread_t thread, void **valuep), );
1316# endif
1317_GL_CXXALIAS_SYS (pthread_join, int, (pthread_t thread, void **valuep));
1318# endif
1319# if __GLIBC__ >= 2
1320_GL_CXXALIASWARN (pthread_join);
1321# endif
1322#elif defined GNULIB_POSIXCHECK
1323# if HAVE_RAW_DECL_PTHREAD_JOIN
1324_GL_WARN_ON_USE (pthread_join, "pthread_join is not portable - "
1325 "use gnulib module pthread-thread for portability");
1326# endif
1327#endif
1328
1329#if 0
1330# if 0
1331# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1332# undef pthread_exit
1333# define pthread_exit rpl_pthread_exit
1334# endif
1335_GL_FUNCDECL_RPL (pthread_exit, _Noreturn void, (void *value), );
1336_GL_CXXALIAS_RPL (pthread_exit, void, (void *value));
1337# else
1338# if !1
1339_GL_FUNCDECL_SYS (pthread_exit, _Noreturn void, (void *value), );
1340# endif
1341/* Need to cast because of AIX with xlclang++. */
1342_GL_CXXALIAS_SYS_CAST (pthread_exit, void, (void *value));
1343# endif
1344# if __GLIBC__ >= 2
1345_GL_CXXALIASWARN (pthread_exit);
1346# endif
1347#elif defined GNULIB_POSIXCHECK
1348# if HAVE_RAW_DECL_PTHREAD_EXIT
1349_GL_WARN_ON_USE (pthread_exit, "pthread_exit is not portable - "
1350 "use gnulib module pthread-thread for portability");
1351# endif
1352#endif
1353
1354/* =========== Once-only control (initialization) functions =========== */
1355
1356#if 1
1357# if 0
1358# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1359# undef pthread_once
1360# define pthread_once rpl_pthread_once
1361# endif
1362_GL_FUNCDECL_RPL (pthread_once, int,
1363 (pthread_once_t *once_control, void (*initfunction) (void)),
1364 _GL_ARG_NONNULL ((1, 2)));
1365_GL_CXXALIAS_RPL (pthread_once, int,
1366 (pthread_once_t *once_control, void (*initfunction) (void)));
1367# else
1368# if !1
1369_GL_FUNCDECL_SYS (pthread_once, int,
1370 (pthread_once_t *once_control, void (*initfunction) (void)),
1371 _GL_ARG_NONNULL ((1, 2)));
1372# endif
1373_GL_CXXALIAS_SYS_CAST (pthread_once, int,
1374 (pthread_once_t *once_control,
1375 void (*initfunction) (void)));
1376# endif
1377# if __GLIBC__ >= 2
1378_GL_CXXALIASWARN (pthread_once);
1379# endif
1380#elif defined GNULIB_POSIXCHECK
1381# if HAVE_RAW_DECL_PTHREAD_ONCE
1382_GL_WARN_ON_USE (pthread_once, "pthread_once is not portable - "
1383 "use gnulib module pthread-once for portability");
1384# endif
1385#endif
1386
1387/* =========== Mutex functions =========== */
1388
1389#if 0
1390# if 0
1391# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1392# undef pthread_mutex_init
1393# define pthread_mutex_init rpl_pthread_mutex_init
1394# endif
1395_GL_FUNCDECL_RPL (pthread_mutex_init, int,
1396 (pthread_mutex_t *restrict mutex,
1397 const pthread_mutexattr_t *restrict attr),
1398 _GL_ARG_NONNULL ((1)));
1399_GL_CXXALIAS_RPL (pthread_mutex_init, int,
1400 (pthread_mutex_t *restrict mutex,
1401 const pthread_mutexattr_t *restrict attr));
1402# else
1403# if !1
1404_GL_FUNCDECL_SYS (pthread_mutex_init, int,
1405 (pthread_mutex_t *restrict mutex,
1406 const pthread_mutexattr_t *restrict attr),
1407 _GL_ARG_NONNULL ((1)));
1408# endif
1409_GL_CXXALIAS_SYS (pthread_mutex_init, int,
1410 (pthread_mutex_t *restrict mutex,
1411 const pthread_mutexattr_t *restrict attr));
1412# endif
1413# if __GLIBC__ >= 2
1414_GL_CXXALIASWARN (pthread_mutex_init);
1415# endif
1416#elif defined GNULIB_POSIXCHECK
1417# if HAVE_RAW_DECL_PTHREAD_MUTEX_INIT
1418_GL_WARN_ON_USE (pthread_mutex_init, "pthread_mutex_init is not portable - "
1419 "use gnulib module pthread-mutex for portability");
1420# endif
1421#endif
1422
1423#if 0
1424# if 0
1425# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1426# undef pthread_mutexattr_init
1427# define pthread_mutexattr_init rpl_pthread_mutexattr_init
1428# endif
1429_GL_FUNCDECL_RPL (pthread_mutexattr_init, int, (pthread_mutexattr_t *attr),
1430 _GL_ARG_NONNULL ((1)));
1431_GL_CXXALIAS_RPL (pthread_mutexattr_init, int, (pthread_mutexattr_t *attr));
1432# else
1433# if !1
1434_GL_FUNCDECL_SYS (pthread_mutexattr_init, int, (pthread_mutexattr_t *attr),
1435 _GL_ARG_NONNULL ((1)));
1436# endif
1437_GL_CXXALIAS_SYS (pthread_mutexattr_init, int, (pthread_mutexattr_t *attr));
1438# endif
1439# if __GLIBC__ >= 2
1440_GL_CXXALIASWARN (pthread_mutexattr_init);
1441# endif
1442#elif defined GNULIB_POSIXCHECK
1443# if HAVE_RAW_DECL_PTHREAD_MUTEXATTR_INIT
1444_GL_WARN_ON_USE (pthread_mutexattr_init, "pthread_mutexattr_init is not portable - "
1445 "use gnulib module pthread-mutex for portability");
1446# endif
1447#endif
1448
1449#if 0
1450# if 0
1451# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1452# undef pthread_mutexattr_gettype
1453# define pthread_mutexattr_gettype rpl_pthread_mutexattr_gettype
1454# endif
1455_GL_FUNCDECL_RPL (pthread_mutexattr_gettype, int,
1456 (const pthread_mutexattr_t *restrict attr,
1457 int *restrict typep),
1458 _GL_ARG_NONNULL ((1, 2)));
1459_GL_CXXALIAS_RPL (pthread_mutexattr_gettype, int,
1460 (const pthread_mutexattr_t *restrict attr,
1461 int *restrict typep));
1462# else
1463# if !1
1464_GL_FUNCDECL_SYS (pthread_mutexattr_gettype, int,
1465 (const pthread_mutexattr_t *restrict attr,
1466 int *restrict typep),
1467 _GL_ARG_NONNULL ((1, 2)));
1468# endif
1469/* Need to cast, because on FreeBSD the first parameter is
1470 pthread_mutexattr_t *attr. */
1471_GL_CXXALIAS_SYS_CAST (pthread_mutexattr_gettype, int,
1472 (const pthread_mutexattr_t *restrict attr,
1473 int *restrict typep));
1474# endif
1475# if __GLIBC__ >= 2
1476_GL_CXXALIASWARN (pthread_mutexattr_gettype);
1477# endif
1478#elif defined GNULIB_POSIXCHECK
1479# if HAVE_RAW_DECL_PTHREAD_MUTEXATTR_GETTYPE
1480_GL_WARN_ON_USE (pthread_mutexattr_gettype, "pthread_mutexattr_gettype is not portable - "
1481 "use gnulib module pthread-mutex for portability");
1482# endif
1483#endif
1484
1485#if 0
1486# if 0
1487# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1488# undef pthread_mutexattr_settype
1489# define pthread_mutexattr_settype rpl_pthread_mutexattr_settype
1490# endif
1491_GL_FUNCDECL_RPL (pthread_mutexattr_settype, int,
1492 (pthread_mutexattr_t *attr, int type), _GL_ARG_NONNULL ((1)));
1493_GL_CXXALIAS_RPL (pthread_mutexattr_settype, int,
1494 (pthread_mutexattr_t *attr, int type));
1495# else
1496# if !1
1497_GL_FUNCDECL_SYS (pthread_mutexattr_settype, int,
1498 (pthread_mutexattr_t *attr, int type), _GL_ARG_NONNULL ((1)));
1499# endif
1500_GL_CXXALIAS_SYS (pthread_mutexattr_settype, int,
1501 (pthread_mutexattr_t *attr, int type));
1502# endif
1503# if __GLIBC__ >= 2
1504_GL_CXXALIASWARN (pthread_mutexattr_settype);
1505# endif
1506#elif defined GNULIB_POSIXCHECK
1507# if HAVE_RAW_DECL_PTHREAD_MUTEXATTR_SETTYPE
1508_GL_WARN_ON_USE (pthread_mutexattr_settype, "pthread_mutexattr_settype is not portable - "
1509 "use gnulib module pthread-mutex for portability");
1510# endif
1511#endif
1512
1513#if 0
1514# if 0
1515# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1516# undef pthread_mutexattr_getrobust
1517# define pthread_mutexattr_getrobust rpl_pthread_mutexattr_getrobust
1518# endif
1519_GL_FUNCDECL_RPL (pthread_mutexattr_getrobust, int,
1520 (const pthread_mutexattr_t *restrict attr,
1521 int *restrict robustp),
1522 _GL_ARG_NONNULL ((1, 2)));
1523_GL_CXXALIAS_RPL (pthread_mutexattr_getrobust, int,
1524 (const pthread_mutexattr_t *restrict attr,
1525 int *restrict robustp));
1526# else
1527# if !1
1528_GL_FUNCDECL_SYS (pthread_mutexattr_getrobust, int,
1529 (const pthread_mutexattr_t *restrict attr,
1530 int *restrict robustp),
1531 _GL_ARG_NONNULL ((1, 2)));
1532# endif
1533/* Need to cast, because on FreeBSD the first parameter is
1534 pthread_mutexattr_t *attr. */
1535_GL_CXXALIAS_SYS_CAST (pthread_mutexattr_getrobust, int,
1536 (const pthread_mutexattr_t *restrict attr,
1537 int *restrict robustp));
1538# endif
1539# if __GLIBC__ >= 2
1540_GL_CXXALIASWARN (pthread_mutexattr_getrobust);
1541# endif
1542#elif defined GNULIB_POSIXCHECK
1543# if HAVE_RAW_DECL_PTHREAD_MUTEXATTR_GETROBUST
1544_GL_WARN_ON_USE (pthread_mutexattr_getrobust, "pthread_mutexattr_getrobust is not portable - "
1545 "use gnulib module pthread-mutex for portability");
1546# endif
1547#endif
1548
1549#if 0
1550# if 0
1551# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1552# undef pthread_mutexattr_setrobust
1553# define pthread_mutexattr_setrobust rpl_pthread_mutexattr_setrobust
1554# endif
1555_GL_FUNCDECL_RPL (pthread_mutexattr_setrobust, int,
1556 (pthread_mutexattr_t *attr, int robust),
1557 _GL_ARG_NONNULL ((1)));
1558_GL_CXXALIAS_RPL (pthread_mutexattr_setrobust, int,
1559 (pthread_mutexattr_t *attr, int robust));
1560# else
1561# if !1
1562_GL_FUNCDECL_SYS (pthread_mutexattr_setrobust, int,
1563 (pthread_mutexattr_t *attr, int robust),
1564 _GL_ARG_NONNULL ((1)));
1565# endif
1566_GL_CXXALIAS_SYS (pthread_mutexattr_setrobust, int,
1567 (pthread_mutexattr_t *attr, int robust));
1568# endif
1569# if __GLIBC__ >= 2
1570_GL_CXXALIASWARN (pthread_mutexattr_setrobust);
1571# endif
1572#elif defined GNULIB_POSIXCHECK
1573# if HAVE_RAW_DECL_PTHREAD_MUTEXATTR_SETROBUST
1574_GL_WARN_ON_USE (pthread_mutexattr_setrobust, "pthread_mutexattr_setrobust is not portable - "
1575 "use gnulib module pthread-mutex for portability");
1576# endif
1577#endif
1578
1579#if 0
1580# if 0
1581# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1582# undef pthread_mutexattr_destroy
1583# define pthread_mutexattr_destroy rpl_pthread_mutexattr_destroy
1584# endif
1585_GL_FUNCDECL_RPL (pthread_mutexattr_destroy, int, (pthread_mutexattr_t *attr),
1586 _GL_ARG_NONNULL ((1)));
1587_GL_CXXALIAS_RPL (pthread_mutexattr_destroy, int, (pthread_mutexattr_t *attr));
1588# else
1589# if !1
1590_GL_FUNCDECL_SYS (pthread_mutexattr_destroy, int, (pthread_mutexattr_t *attr),
1591 _GL_ARG_NONNULL ((1)));
1592# endif
1593_GL_CXXALIAS_SYS (pthread_mutexattr_destroy, int, (pthread_mutexattr_t *attr));
1594# endif
1595# if __GLIBC__ >= 2
1596_GL_CXXALIASWARN (pthread_mutexattr_destroy);
1597# endif
1598#elif defined GNULIB_POSIXCHECK
1599# if HAVE_RAW_DECL_PTHREAD_MUTEXATTR_DESTROY
1600_GL_WARN_ON_USE (pthread_mutexattr_destroy, "pthread_mutexattr_destroy is not portable - "
1601 "use gnulib module pthread-mutex for portability");
1602# endif
1603#endif
1604
1605#if 0
1606# if 0
1607# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1608# undef pthread_mutex_lock
1609# define pthread_mutex_lock rpl_pthread_mutex_lock
1610# endif
1611_GL_FUNCDECL_RPL (pthread_mutex_lock, int, (pthread_mutex_t *mutex),
1612 _GL_ARG_NONNULL ((1)));
1613_GL_CXXALIAS_RPL (pthread_mutex_lock, int, (pthread_mutex_t *mutex));
1614# else
1615# if !1
1616_GL_FUNCDECL_SYS (pthread_mutex_lock, int, (pthread_mutex_t *mutex),
1617 _GL_ARG_NONNULL ((1)));
1618# endif
1619_GL_CXXALIAS_SYS (pthread_mutex_lock, int, (pthread_mutex_t *mutex));
1620# endif
1621# if __GLIBC__ >= 2
1622_GL_CXXALIASWARN (pthread_mutex_lock);
1623# endif
1624#elif defined GNULIB_POSIXCHECK
1625# if HAVE_RAW_DECL_PTHREAD_MUTEX_LOCK
1626_GL_WARN_ON_USE (pthread_mutex_lock, "pthread_mutex_lock is not portable - "
1627 "use gnulib module pthread-mutex for portability");
1628# endif
1629#endif
1630
1631#if 0
1632# if 0
1633# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1634# undef pthread_mutex_trylock
1635# define pthread_mutex_trylock rpl_pthread_mutex_trylock
1636# endif
1637_GL_FUNCDECL_RPL (pthread_mutex_trylock, int, (pthread_mutex_t *mutex),
1638 _GL_ARG_NONNULL ((1)));
1639_GL_CXXALIAS_RPL (pthread_mutex_trylock, int, (pthread_mutex_t *mutex));
1640# else
1641# if !1
1642_GL_FUNCDECL_SYS (pthread_mutex_trylock, int, (pthread_mutex_t *mutex),
1643 _GL_ARG_NONNULL ((1)));
1644# endif
1645_GL_CXXALIAS_SYS (pthread_mutex_trylock, int, (pthread_mutex_t *mutex));
1646# endif
1647# if __GLIBC__ >= 2
1648_GL_CXXALIASWARN (pthread_mutex_trylock);
1649# endif
1650#elif defined GNULIB_POSIXCHECK
1651# if HAVE_RAW_DECL_PTHREAD_MUTEX_TRYLOCK
1652_GL_WARN_ON_USE (pthread_mutex_trylock, "pthread_mutex_trylock is not portable - "
1653 "use gnulib module pthread-mutex for portability");
1654# endif
1655#endif
1656
1657#if 0
1658# if 0
1659# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1660# undef pthread_mutex_timedlock
1661# define pthread_mutex_timedlock rpl_pthread_mutex_timedlock
1662# endif
1663_GL_FUNCDECL_RPL (pthread_mutex_timedlock, int,
1664 (pthread_mutex_t *restrict mutex,
1665 const struct timespec *restrict abstime),
1666 _GL_ARG_NONNULL ((1, 2)));
1667_GL_CXXALIAS_RPL (pthread_mutex_timedlock, int,
1668 (pthread_mutex_t *restrict mutex,
1669 const struct timespec *restrict abstime));
1670# else
1671# if !1
1672_GL_FUNCDECL_SYS (pthread_mutex_timedlock, int,
1673 (pthread_mutex_t *restrict mutex,
1674 const struct timespec *restrict abstime),
1675 _GL_ARG_NONNULL ((1, 2)));
1676# endif
1677_GL_CXXALIAS_SYS (pthread_mutex_timedlock, int,
1678 (pthread_mutex_t *restrict mutex,
1679 const struct timespec *restrict abstime));
1680# endif
1681# if __GLIBC__ >= 2
1682_GL_CXXALIASWARN (pthread_mutex_timedlock);
1683# endif
1684#elif defined GNULIB_POSIXCHECK
1685# if HAVE_RAW_DECL_PTHREAD_MUTEX_TIMEDLOCK
1686_GL_WARN_ON_USE (pthread_mutex_timedlock, "pthread_mutex_timedlock is not portable - "
1687 "use gnulib module pthread_mutex_timedlock for portability");
1688# endif
1689#endif
1690
1691#if 0
1692# if 0
1693# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1694# undef pthread_mutex_unlock
1695# define pthread_mutex_unlock rpl_pthread_mutex_unlock
1696# endif
1697_GL_FUNCDECL_RPL (pthread_mutex_unlock, int, (pthread_mutex_t *mutex),
1698 _GL_ARG_NONNULL ((1)));
1699_GL_CXXALIAS_RPL (pthread_mutex_unlock, int, (pthread_mutex_t *mutex));
1700# else
1701# if !1
1702_GL_FUNCDECL_SYS (pthread_mutex_unlock, int, (pthread_mutex_t *mutex),
1703 _GL_ARG_NONNULL ((1)));
1704# endif
1705_GL_CXXALIAS_SYS (pthread_mutex_unlock, int, (pthread_mutex_t *mutex));
1706# endif
1707# if __GLIBC__ >= 2
1708_GL_CXXALIASWARN (pthread_mutex_unlock);
1709# endif
1710#elif defined GNULIB_POSIXCHECK
1711# if HAVE_RAW_DECL_PTHREAD_MUTEX_UNLOCK
1712_GL_WARN_ON_USE (pthread_mutex_unlock, "pthread_mutex_unlock is not portable - "
1713 "use gnulib module pthread-mutex for portability");
1714# endif
1715#endif
1716
1717#if 0
1718# if 0
1719# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1720# undef pthread_mutex_destroy
1721# define pthread_mutex_destroy rpl_pthread_mutex_destroy
1722# endif
1723_GL_FUNCDECL_RPL (pthread_mutex_destroy, int, (pthread_mutex_t *mutex),
1724 _GL_ARG_NONNULL ((1)));
1725_GL_CXXALIAS_RPL (pthread_mutex_destroy, int, (pthread_mutex_t *mutex));
1726# else
1727# if !1
1728_GL_FUNCDECL_SYS (pthread_mutex_destroy, int, (pthread_mutex_t *mutex),
1729 _GL_ARG_NONNULL ((1)));
1730# endif
1731_GL_CXXALIAS_SYS (pthread_mutex_destroy, int, (pthread_mutex_t *mutex));
1732# endif
1733# if __GLIBC__ >= 2
1734_GL_CXXALIASWARN (pthread_mutex_destroy);
1735# endif
1736#elif defined GNULIB_POSIXCHECK
1737# if HAVE_RAW_DECL_PTHREAD_MUTEX_DESTROY
1738_GL_WARN_ON_USE (pthread_mutex_destroy, "pthread_mutex_destroy is not portable - "
1739 "use gnulib module pthread-mutex for portability");
1740# endif
1741#endif
1742
1743/* =========== Read-write lock functions =========== */
1744
1745#if 0
1746# if 0
1747# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1748# undef pthread_rwlock_init
1749# define pthread_rwlock_init rpl_pthread_rwlock_init
1750# endif
1751_GL_FUNCDECL_RPL (pthread_rwlock_init, int,
1752 (pthread_rwlock_t *restrict lock,
1753 const pthread_rwlockattr_t *restrict attr),
1754 _GL_ARG_NONNULL ((1)));
1755_GL_CXXALIAS_RPL (pthread_rwlock_init, int,
1756 (pthread_rwlock_t *restrict lock,
1757 const pthread_rwlockattr_t *restrict attr));
1758# else
1759# if !1
1760_GL_FUNCDECL_SYS (pthread_rwlock_init, int,
1761 (pthread_rwlock_t *restrict lock,
1762 const pthread_rwlockattr_t *restrict attr),
1763 _GL_ARG_NONNULL ((1)));
1764# endif
1765_GL_CXXALIAS_SYS (pthread_rwlock_init, int,
1766 (pthread_rwlock_t *restrict lock,
1767 const pthread_rwlockattr_t *restrict attr));
1768# endif
1769# if __GLIBC__ >= 2
1770_GL_CXXALIASWARN (pthread_rwlock_init);
1771# endif
1772#elif defined GNULIB_POSIXCHECK
1773# if HAVE_RAW_DECL_PTHREAD_RWLOCK_INIT
1774_GL_WARN_ON_USE (pthread_rwlock_init, "pthread_rwlock_init is not portable - "
1775 "use gnulib module pthread-rwlock for portability");
1776# endif
1777#endif
1778
1779#if 0
1780# if 0
1781# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1782# undef pthread_rwlockattr_init
1783# define pthread_rwlockattr_init rpl_pthread_rwlockattr_init
1784# endif
1785_GL_FUNCDECL_RPL (pthread_rwlockattr_init, int, (pthread_rwlockattr_t *attr),
1786 _GL_ARG_NONNULL ((1)));
1787_GL_CXXALIAS_RPL (pthread_rwlockattr_init, int, (pthread_rwlockattr_t *attr));
1788# else
1789# if !1
1790_GL_FUNCDECL_SYS (pthread_rwlockattr_init, int, (pthread_rwlockattr_t *attr),
1791 _GL_ARG_NONNULL ((1)));
1792# endif
1793_GL_CXXALIAS_SYS (pthread_rwlockattr_init, int, (pthread_rwlockattr_t *attr));
1794# endif
1795# if __GLIBC__ >= 2
1796_GL_CXXALIASWARN (pthread_rwlockattr_init);
1797# endif
1798#elif defined GNULIB_POSIXCHECK
1799# if HAVE_RAW_DECL_PTHREAD_RWLOCKATTR_INIT
1800_GL_WARN_ON_USE (pthread_rwlockattr_init, "pthread_rwlockattr_init is not portable - "
1801 "use gnulib module pthread-rwlock for portability");
1802# endif
1803#endif
1804
1805#if 0
1806# if 0
1807# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1808# undef pthread_rwlockattr_destroy
1809# define pthread_rwlockattr_destroy rpl_pthread_rwlockattr_destroy
1810# endif
1811_GL_FUNCDECL_RPL (pthread_rwlockattr_destroy, int,
1812 (pthread_rwlockattr_t *attr), _GL_ARG_NONNULL ((1)));
1813_GL_CXXALIAS_RPL (pthread_rwlockattr_destroy, int,
1814 (pthread_rwlockattr_t *attr));
1815# else
1816# if !1
1817_GL_FUNCDECL_SYS (pthread_rwlockattr_destroy, int,
1818 (pthread_rwlockattr_t *attr), _GL_ARG_NONNULL ((1)));
1819# endif
1820_GL_CXXALIAS_SYS (pthread_rwlockattr_destroy, int,
1821 (pthread_rwlockattr_t *attr));
1822# endif
1823# if __GLIBC__ >= 2
1824_GL_CXXALIASWARN (pthread_rwlockattr_destroy);
1825# endif
1826#elif defined GNULIB_POSIXCHECK
1827# if HAVE_RAW_DECL_PTHREAD_RWLOCKATTR_DESTROY
1828_GL_WARN_ON_USE (pthread_rwlockattr_destroy, "pthread_rwlockattr_destroy is not portable - "
1829 "use gnulib module pthread-rwlock for portability");
1830# endif
1831#endif
1832
1833#if 0
1834# if 0
1835# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1836# undef pthread_rwlock_rdlock
1837# define pthread_rwlock_rdlock rpl_pthread_rwlock_rdlock
1838# endif
1839_GL_FUNCDECL_RPL (pthread_rwlock_rdlock, int, (pthread_rwlock_t *lock),
1840 _GL_ARG_NONNULL ((1)));
1841_GL_CXXALIAS_RPL (pthread_rwlock_rdlock, int, (pthread_rwlock_t *lock));
1842# else
1843# if !1
1844_GL_FUNCDECL_SYS (pthread_rwlock_rdlock, int, (pthread_rwlock_t *lock),
1845 _GL_ARG_NONNULL ((1)));
1846# endif
1847_GL_CXXALIAS_SYS (pthread_rwlock_rdlock, int, (pthread_rwlock_t *lock));
1848# endif
1849# if __GLIBC__ >= 2
1850_GL_CXXALIASWARN (pthread_rwlock_rdlock);
1851# endif
1852#elif defined GNULIB_POSIXCHECK
1853# if HAVE_RAW_DECL_PTHREAD_RWLOCK_RDLOCK
1854_GL_WARN_ON_USE (pthread_rwlock_rdlock, "pthread_rwlock_rdlock is not portable - "
1855 "use gnulib module pthread-rwlock for portability");
1856# endif
1857#endif
1858
1859#if 0
1860# if 0
1861# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1862# undef pthread_rwlock_wrlock
1863# define pthread_rwlock_wrlock rpl_pthread_rwlock_wrlock
1864# endif
1865_GL_FUNCDECL_RPL (pthread_rwlock_wrlock, int, (pthread_rwlock_t *lock),
1866 _GL_ARG_NONNULL ((1)));
1867_GL_CXXALIAS_RPL (pthread_rwlock_wrlock, int, (pthread_rwlock_t *lock));
1868# else
1869# if !1
1870_GL_FUNCDECL_SYS (pthread_rwlock_wrlock, int, (pthread_rwlock_t *lock),
1871 _GL_ARG_NONNULL ((1)));
1872# endif
1873_GL_CXXALIAS_SYS (pthread_rwlock_wrlock, int, (pthread_rwlock_t *lock));
1874# endif
1875# if __GLIBC__ >= 2
1876_GL_CXXALIASWARN (pthread_rwlock_wrlock);
1877# endif
1878#elif defined GNULIB_POSIXCHECK
1879# if HAVE_RAW_DECL_PTHREAD_RWLOCK_WRLOCK
1880_GL_WARN_ON_USE (pthread_rwlock_wrlock, "pthread_rwlock_wrlock is not portable - "
1881 "use gnulib module pthread-rwlock for portability");
1882# endif
1883#endif
1884
1885#if 0
1886# if 0
1887# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1888# undef pthread_rwlock_tryrdlock
1889# define pthread_rwlock_tryrdlock rpl_pthread_rwlock_tryrdlock
1890# endif
1891_GL_FUNCDECL_RPL (pthread_rwlock_tryrdlock, int, (pthread_rwlock_t *lock),
1892 _GL_ARG_NONNULL ((1)));
1893_GL_CXXALIAS_RPL (pthread_rwlock_tryrdlock, int, (pthread_rwlock_t *lock));
1894# else
1895# if !1
1896_GL_FUNCDECL_SYS (pthread_rwlock_tryrdlock, int, (pthread_rwlock_t *lock),
1897 _GL_ARG_NONNULL ((1)));
1898# endif
1899_GL_CXXALIAS_SYS (pthread_rwlock_tryrdlock, int, (pthread_rwlock_t *lock));
1900# endif
1901# if __GLIBC__ >= 2
1902_GL_CXXALIASWARN (pthread_rwlock_tryrdlock);
1903# endif
1904#elif defined GNULIB_POSIXCHECK
1905# if HAVE_RAW_DECL_PTHREAD_RWLOCK_TRYRDLOCK
1906_GL_WARN_ON_USE (pthread_rwlock_tryrdlock, "pthread_rwlock_tryrdlock is not portable - "
1907 "use gnulib module pthread-rwlock for portability");
1908# endif
1909#endif
1910
1911#if 0
1912# if 0
1913# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1914# undef pthread_rwlock_trywrlock
1915# define pthread_rwlock_trywrlock rpl_pthread_rwlock_trywrlock
1916# endif
1917_GL_FUNCDECL_RPL (pthread_rwlock_trywrlock, int, (pthread_rwlock_t *lock),
1918 _GL_ARG_NONNULL ((1)));
1919_GL_CXXALIAS_RPL (pthread_rwlock_trywrlock, int, (pthread_rwlock_t *lock));
1920# else
1921# if !1
1922_GL_FUNCDECL_SYS (pthread_rwlock_trywrlock, int, (pthread_rwlock_t *lock),
1923 _GL_ARG_NONNULL ((1)));
1924# endif
1925_GL_CXXALIAS_SYS (pthread_rwlock_trywrlock, int, (pthread_rwlock_t *lock));
1926# endif
1927# if __GLIBC__ >= 2
1928_GL_CXXALIASWARN (pthread_rwlock_trywrlock);
1929# endif
1930#elif defined GNULIB_POSIXCHECK
1931# if HAVE_RAW_DECL_PTHREAD_RWLOCK_TRYWRLOCK
1932_GL_WARN_ON_USE (pthread_rwlock_trywrlock, "pthread_rwlock_trywrlock is not portable - "
1933 "use gnulib module pthread-rwlock for portability");
1934# endif
1935#endif
1936
1937#if 0
1938# if 0
1939# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1940# undef pthread_rwlock_timedrdlock
1941# define pthread_rwlock_timedrdlock rpl_pthread_rwlock_timedrdlock
1942# endif
1943_GL_FUNCDECL_RPL (pthread_rwlock_timedrdlock, int,
1944 (pthread_rwlock_t *restrict lock,
1945 const struct timespec *restrict abstime),
1946 _GL_ARG_NONNULL ((1, 2)));
1947_GL_CXXALIAS_RPL (pthread_rwlock_timedrdlock, int,
1948 (pthread_rwlock_t *restrict lock,
1949 const struct timespec *restrict abstime));
1950# else
1951# if !1
1952_GL_FUNCDECL_SYS (pthread_rwlock_timedrdlock, int,
1953 (pthread_rwlock_t *restrict lock,
1954 const struct timespec *restrict abstime),
1955 _GL_ARG_NONNULL ((1, 2)));
1956# endif
1957_GL_CXXALIAS_SYS (pthread_rwlock_timedrdlock, int,
1958 (pthread_rwlock_t *restrict lock,
1959 const struct timespec *restrict abstime));
1960# endif
1961# if __GLIBC__ >= 2
1962_GL_CXXALIASWARN (pthread_rwlock_timedrdlock);
1963# endif
1964#elif defined GNULIB_POSIXCHECK
1965# if HAVE_RAW_DECL_PTHREAD_RWLOCK_TIMEDRDLOCK
1966_GL_WARN_ON_USE (pthread_rwlock_timedrdlock, "pthread_rwlock_timedrdlock is not portable - "
1967 "use gnulib module pthread-rwlock for portability");
1968# endif
1969#endif
1970
1971#if 0
1972# if 0
1973# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1974# undef pthread_rwlock_timedwrlock
1975# define pthread_rwlock_timedwrlock rpl_pthread_rwlock_timedwrlock
1976# endif
1977_GL_FUNCDECL_RPL (pthread_rwlock_timedwrlock, int,
1978 (pthread_rwlock_t *restrict lock,
1979 const struct timespec *restrict abstime),
1980 _GL_ARG_NONNULL ((1, 2)));
1981_GL_CXXALIAS_RPL (pthread_rwlock_timedwrlock, int,
1982 (pthread_rwlock_t *restrict lock,
1983 const struct timespec *restrict abstime));
1984# else
1985# if !1
1986_GL_FUNCDECL_SYS (pthread_rwlock_timedwrlock, int,
1987 (pthread_rwlock_t *restrict lock,
1988 const struct timespec *restrict abstime),
1989 _GL_ARG_NONNULL ((1, 2)));
1990# endif
1991_GL_CXXALIAS_SYS (pthread_rwlock_timedwrlock, int,
1992 (pthread_rwlock_t *restrict lock,
1993 const struct timespec *restrict abstime));
1994# endif
1995# if __GLIBC__ >= 2
1996_GL_CXXALIASWARN (pthread_rwlock_timedwrlock);
1997# endif
1998#elif defined GNULIB_POSIXCHECK
1999# if HAVE_RAW_DECL_PTHREAD_RWLOCK_TIMEDWRLOCK
2000_GL_WARN_ON_USE (pthread_rwlock_timedwrlock, "pthread_rwlock_timedwrlock is not portable - "
2001 "use gnulib module pthread-rwlock for portability");
2002# endif
2003#endif
2004
2005#if 0
2006# if 0
2007# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2008# undef pthread_rwlock_unlock
2009# define pthread_rwlock_unlock rpl_pthread_rwlock_unlock
2010# endif
2011_GL_FUNCDECL_RPL (pthread_rwlock_unlock, int, (pthread_rwlock_t *lock),
2012 _GL_ARG_NONNULL ((1)));
2013_GL_CXXALIAS_RPL (pthread_rwlock_unlock, int, (pthread_rwlock_t *lock));
2014# else
2015# if !1
2016_GL_FUNCDECL_SYS (pthread_rwlock_unlock, int, (pthread_rwlock_t *lock),
2017 _GL_ARG_NONNULL ((1)));
2018# endif
2019_GL_CXXALIAS_SYS (pthread_rwlock_unlock, int, (pthread_rwlock_t *lock));
2020# endif
2021# if __GLIBC__ >= 2
2022_GL_CXXALIASWARN (pthread_rwlock_unlock);
2023# endif
2024#elif defined GNULIB_POSIXCHECK
2025# if HAVE_RAW_DECL_PTHREAD_RWLOCK_UNLOCK
2026_GL_WARN_ON_USE (pthread_rwlock_unlock, "pthread_rwlock_unlock is not portable - "
2027 "use gnulib module pthread-rwlock for portability");
2028# endif
2029#endif
2030
2031#if 0
2032# if 0
2033# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2034# undef pthread_rwlock_destroy
2035# define pthread_rwlock_destroy rpl_pthread_rwlock_destroy
2036# endif
2037_GL_FUNCDECL_RPL (pthread_rwlock_destroy, int, (pthread_rwlock_t *lock),
2038 _GL_ARG_NONNULL ((1)));
2039_GL_CXXALIAS_RPL (pthread_rwlock_destroy, int, (pthread_rwlock_t *lock));
2040# else
2041# if !1
2042_GL_FUNCDECL_SYS (pthread_rwlock_destroy, int, (pthread_rwlock_t *lock),
2043 _GL_ARG_NONNULL ((1)));
2044# endif
2045_GL_CXXALIAS_SYS (pthread_rwlock_destroy, int, (pthread_rwlock_t *lock));
2046# endif
2047# if __GLIBC__ >= 2
2048_GL_CXXALIASWARN (pthread_rwlock_destroy);
2049# endif
2050#elif defined GNULIB_POSIXCHECK
2051# if HAVE_RAW_DECL_PTHREAD_RWLOCK_DESTROY
2052_GL_WARN_ON_USE (pthread_rwlock_destroy, "pthread_rwlock_destroy is not portable - "
2053 "use gnulib module pthread-rwlock for portability");
2054# endif
2055#endif
2056
2057/* =========== Condition variable functions =========== */
2058
2059#if 0
2060# if 0
2061# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2062# undef pthread_cond_init
2063# define pthread_cond_init rpl_pthread_cond_init
2064# endif
2065_GL_FUNCDECL_RPL (pthread_cond_init, int,
2066 (pthread_cond_t *restrict cond,
2067 const pthread_condattr_t *restrict attr),
2068 _GL_ARG_NONNULL ((1)));
2069_GL_CXXALIAS_RPL (pthread_cond_init, int,
2070 (pthread_cond_t *restrict cond,
2071 const pthread_condattr_t *restrict attr));
2072# else
2073# if !1
2074_GL_FUNCDECL_SYS (pthread_cond_init, int,
2075 (pthread_cond_t *restrict cond,
2076 const pthread_condattr_t *restrict attr),
2077 _GL_ARG_NONNULL ((1)));
2078# endif
2079_GL_CXXALIAS_SYS (pthread_cond_init, int,
2080 (pthread_cond_t *restrict cond,
2081 const pthread_condattr_t *restrict attr));
2082# endif
2083# if __GLIBC__ >= 2
2084_GL_CXXALIASWARN (pthread_cond_init);
2085# endif
2086#elif defined GNULIB_POSIXCHECK
2087# if HAVE_RAW_DECL_PTHREAD_COND_INIT
2088_GL_WARN_ON_USE (pthread_cond_init, "pthread_cond_init is not portable - "
2089 "use gnulib module pthread-cond for portability");
2090# endif
2091#endif
2092
2093#if 0
2094# if 0
2095# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2096# undef pthread_condattr_init
2097# define pthread_condattr_init rpl_pthread_condattr_init
2098# endif
2099_GL_FUNCDECL_RPL (pthread_condattr_init, int, (pthread_condattr_t *attr),
2100 _GL_ARG_NONNULL ((1)));
2101_GL_CXXALIAS_RPL (pthread_condattr_init, int, (pthread_condattr_t *attr));
2102# else
2103# if !1
2104_GL_FUNCDECL_SYS (pthread_condattr_init, int, (pthread_condattr_t *attr),
2105 _GL_ARG_NONNULL ((1)));
2106# endif
2107_GL_CXXALIAS_SYS (pthread_condattr_init, int, (pthread_condattr_t *attr));
2108# endif
2109# if __GLIBC__ >= 2
2110_GL_CXXALIASWARN (pthread_condattr_init);
2111# endif
2112#elif defined GNULIB_POSIXCHECK
2113# if HAVE_RAW_DECL_PTHREAD_CONDATTR_INIT
2114_GL_WARN_ON_USE (pthread_condattr_init, "pthread_condattr_init is not portable - "
2115 "use gnulib module pthread-cond for portability");
2116# endif
2117#endif
2118
2119#if 0
2120# if 0
2121# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2122# undef pthread_condattr_destroy
2123# define pthread_condattr_destroy rpl_pthread_condattr_destroy
2124# endif
2125_GL_FUNCDECL_RPL (pthread_condattr_destroy, int, (pthread_condattr_t *attr),
2126 _GL_ARG_NONNULL ((1)));
2127_GL_CXXALIAS_RPL (pthread_condattr_destroy, int, (pthread_condattr_t *attr));
2128# else
2129# if !1
2130_GL_FUNCDECL_SYS (pthread_condattr_destroy, int, (pthread_condattr_t *attr),
2131 _GL_ARG_NONNULL ((1)));
2132# endif
2133_GL_CXXALIAS_SYS (pthread_condattr_destroy, int, (pthread_condattr_t *attr));
2134# endif
2135# if __GLIBC__ >= 2
2136_GL_CXXALIASWARN (pthread_condattr_destroy);
2137# endif
2138#elif defined GNULIB_POSIXCHECK
2139# if HAVE_RAW_DECL_PTHREAD_CONDATTR_DESTROY
2140_GL_WARN_ON_USE (pthread_condattr_destroy, "pthread_condattr_destroy is not portable - "
2141 "use gnulib module pthread-cond for portability");
2142# endif
2143#endif
2144
2145#if 0
2146# if 0
2147# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2148# undef pthread_cond_wait
2149# define pthread_cond_wait rpl_pthread_cond_wait
2150# endif
2151_GL_FUNCDECL_RPL (pthread_cond_wait, int,
2152 (pthread_cond_t *restrict cond,
2153 pthread_mutex_t *restrict mutex),
2154 _GL_ARG_NONNULL ((1, 2)));
2155_GL_CXXALIAS_RPL (pthread_cond_wait, int,
2156 (pthread_cond_t *restrict cond,
2157 pthread_mutex_t *restrict mutex));
2158# else
2159# if !1
2160_GL_FUNCDECL_SYS (pthread_cond_wait, int,
2161 (pthread_cond_t *restrict cond,
2162 pthread_mutex_t *restrict mutex),
2163 _GL_ARG_NONNULL ((1, 2)));
2164# endif
2165_GL_CXXALIAS_SYS (pthread_cond_wait, int,
2166 (pthread_cond_t *restrict cond,
2167 pthread_mutex_t *restrict mutex));
2168# endif
2169# if __GLIBC__ >= 2
2170_GL_CXXALIASWARN (pthread_cond_wait);
2171# endif
2172#elif defined GNULIB_POSIXCHECK
2173# if HAVE_RAW_DECL_PTHREAD_COND_WAIT
2174_GL_WARN_ON_USE (pthread_cond_wait, "pthread_cond_wait is not portable - "
2175 "use gnulib module pthread-cond for portability");
2176# endif
2177#endif
2178
2179#if 0
2180# if 0
2181# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2182# undef pthread_cond_timedwait
2183# define pthread_cond_timedwait rpl_pthread_cond_timedwait
2184# endif
2185_GL_FUNCDECL_RPL (pthread_cond_timedwait, int,
2186 (pthread_cond_t *restrict cond,
2187 pthread_mutex_t *restrict mutex,
2188 const struct timespec *restrict abstime),
2189 _GL_ARG_NONNULL ((1, 2, 3)));
2190_GL_CXXALIAS_RPL (pthread_cond_timedwait, int,
2191 (pthread_cond_t *restrict cond,
2192 pthread_mutex_t *restrict mutex,
2193 const struct timespec *restrict abstime));
2194# else
2195# if !1
2196_GL_FUNCDECL_SYS (pthread_cond_timedwait, int,
2197 (pthread_cond_t *restrict cond,
2198 pthread_mutex_t *restrict mutex,
2199 const struct timespec *restrict abstime),
2200 _GL_ARG_NONNULL ((1, 2, 3)));
2201# endif
2202_GL_CXXALIAS_SYS (pthread_cond_timedwait, int,
2203 (pthread_cond_t *restrict cond,
2204 pthread_mutex_t *restrict mutex,
2205 const struct timespec *restrict abstime));
2206# endif
2207# if __GLIBC__ >= 2
2208_GL_CXXALIASWARN (pthread_cond_timedwait);
2209# endif
2210#elif defined GNULIB_POSIXCHECK
2211# if HAVE_RAW_DECL_PTHREAD_COND_TIMEDWAIT
2212_GL_WARN_ON_USE (pthread_cond_timedwait, "pthread_cond_timedwait is not portable - "
2213 "use gnulib module pthread-cond for portability");
2214# endif
2215#endif
2216
2217#if 0
2218# if 0
2219# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2220# undef pthread_cond_signal
2221# define pthread_cond_signal rpl_pthread_cond_signal
2222# endif
2223_GL_FUNCDECL_RPL (pthread_cond_signal, int, (pthread_cond_t *cond),
2224 _GL_ARG_NONNULL ((1)));
2225_GL_CXXALIAS_RPL (pthread_cond_signal, int, (pthread_cond_t *cond));
2226# else
2227# if !1
2228_GL_FUNCDECL_SYS (pthread_cond_signal, int, (pthread_cond_t *cond),
2229 _GL_ARG_NONNULL ((1)));
2230# endif
2231_GL_CXXALIAS_SYS (pthread_cond_signal, int, (pthread_cond_t *cond));
2232# endif
2233# if __GLIBC__ >= 2
2234_GL_CXXALIASWARN (pthread_cond_signal);
2235# endif
2236#elif defined GNULIB_POSIXCHECK
2237# if HAVE_RAW_DECL_PTHREAD_COND_SIGNAL
2238_GL_WARN_ON_USE (pthread_cond_signal, "pthread_cond_signal is not portable - "
2239 "use gnulib module pthread-cond for portability");
2240# endif
2241#endif
2242
2243#if 0
2244# if 0
2245# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2246# undef pthread_cond_broadcast
2247# define pthread_cond_broadcast rpl_pthread_cond_broadcast
2248# endif
2249_GL_FUNCDECL_RPL (pthread_cond_broadcast, int, (pthread_cond_t *cond),
2250 _GL_ARG_NONNULL ((1)));
2251_GL_CXXALIAS_RPL (pthread_cond_broadcast, int, (pthread_cond_t *cond));
2252# else
2253# if !1
2254_GL_FUNCDECL_SYS (pthread_cond_broadcast, int, (pthread_cond_t *cond),
2255 _GL_ARG_NONNULL ((1)));
2256# endif
2257_GL_CXXALIAS_SYS (pthread_cond_broadcast, int, (pthread_cond_t *cond));
2258# endif
2259# if __GLIBC__ >= 2
2260_GL_CXXALIASWARN (pthread_cond_broadcast);
2261# endif
2262#elif defined GNULIB_POSIXCHECK
2263# if HAVE_RAW_DECL_PTHREAD_COND_BROADCAST
2264_GL_WARN_ON_USE (pthread_cond_broadcast, "pthread_cond_broadcast is not portable - "
2265 "use gnulib module pthread-cond for portability");
2266# endif
2267#endif
2268
2269#if 0
2270# if 0
2271# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2272# undef pthread_cond_destroy
2273# define pthread_cond_destroy rpl_pthread_cond_destroy
2274# endif
2275_GL_FUNCDECL_RPL (pthread_cond_destroy, int, (pthread_cond_t *cond),
2276 _GL_ARG_NONNULL ((1)));
2277_GL_CXXALIAS_RPL (pthread_cond_destroy, int, (pthread_cond_t *cond));
2278# else
2279# if !1
2280_GL_FUNCDECL_SYS (pthread_cond_destroy, int, (pthread_cond_t *cond),
2281 _GL_ARG_NONNULL ((1)));
2282# endif
2283_GL_CXXALIAS_SYS (pthread_cond_destroy, int, (pthread_cond_t *cond));
2284# endif
2285# if __GLIBC__ >= 2
2286_GL_CXXALIASWARN (pthread_cond_destroy);
2287# endif
2288#elif defined GNULIB_POSIXCHECK
2289# if HAVE_RAW_DECL_PTHREAD_COND_DESTROY
2290_GL_WARN_ON_USE (pthread_cond_destroy, "pthread_cond_destroy is not portable - "
2291 "use gnulib module pthread-cond for portability");
2292# endif
2293#endif
2294
2295/* =========== Thread-specific storage functions =========== */
2296
2297#if 0
2298# if 0
2299# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2300# undef pthread_key_create
2301# define pthread_key_create rpl_pthread_key_create
2302# endif
2303_GL_FUNCDECL_RPL (pthread_key_create, int,
2304 (pthread_key_t *keyp, void (*destructor) (void *)),
2305 _GL_ARG_NONNULL ((1)));
2306_GL_CXXALIAS_RPL (pthread_key_create, int,
2307 (pthread_key_t *keyp, void (*destructor) (void *)));
2308# else
2309# if !1
2310_GL_FUNCDECL_SYS (pthread_key_create, int,
2311 (pthread_key_t *keyp, void (*destructor) (void *)),
2312 _GL_ARG_NONNULL ((1)));
2313# endif
2314_GL_CXXALIAS_SYS_CAST (pthread_key_create, int,
2315 (pthread_key_t *keyp, void (*destructor) (void *)));
2316# endif
2317# if __GLIBC__ >= 2
2318_GL_CXXALIASWARN (pthread_key_create);
2319# endif
2320#elif defined GNULIB_POSIXCHECK
2321# if HAVE_RAW_DECL_PTHREAD_KEY_CREATE
2322_GL_WARN_ON_USE (pthread_key_create, "pthread_key_create is not portable - "
2323 "use gnulib module pthread-tss for portability");
2324# endif
2325#endif
2326
2327#if 0
2328# if 0
2329# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2330# undef pthread_setspecific
2331# define pthread_setspecific rpl_pthread_setspecific
2332# endif
2333_GL_FUNCDECL_RPL (pthread_setspecific, int,
2334 (pthread_key_t key, const void *value), );
2335_GL_CXXALIAS_RPL (pthread_setspecific, int,
2336 (pthread_key_t key, const void *value));
2337# else
2338# if !1
2339_GL_FUNCDECL_SYS (pthread_setspecific, int,
2340 (pthread_key_t key, const void *value), );
2341# endif
2342_GL_CXXALIAS_SYS (pthread_setspecific, int,
2343 (pthread_key_t key, const void *value));
2344# endif
2345# if __GLIBC__ >= 2
2346_GL_CXXALIASWARN (pthread_setspecific);
2347# endif
2348#elif defined GNULIB_POSIXCHECK
2349# if HAVE_RAW_DECL_PTHREAD_SETSPECIFIC
2350_GL_WARN_ON_USE (pthread_setspecific, "pthread_setspecific is not portable - "
2351 "use gnulib module pthread-tss for portability");
2352# endif
2353#endif
2354
2355#if 0
2356# if 0
2357# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2358# undef pthread_getspecific
2359# define pthread_getspecific rpl_pthread_getspecific
2360# endif
2361_GL_FUNCDECL_RPL (pthread_getspecific, void *, (pthread_key_t key), );
2362_GL_CXXALIAS_RPL (pthread_getspecific, void *, (pthread_key_t key));
2363# else
2364# if !1
2365_GL_FUNCDECL_SYS (pthread_getspecific, void *, (pthread_key_t key), );
2366# endif
2367_GL_CXXALIAS_SYS (pthread_getspecific, void *, (pthread_key_t key));
2368# endif
2369# if __GLIBC__ >= 2
2370_GL_CXXALIASWARN (pthread_getspecific);
2371# endif
2372#elif defined GNULIB_POSIXCHECK
2373# if HAVE_RAW_DECL_PTHREAD_GETSPECIFIC
2374_GL_WARN_ON_USE (pthread_getspecific, "pthread_getspecific is not portable - "
2375 "use gnulib module pthread-tss for portability");
2376# endif
2377#endif
2378
2379#if 0
2380# if 0
2381# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2382# undef pthread_key_delete
2383# define pthread_key_delete rpl_pthread_key_delete
2384# endif
2385_GL_FUNCDECL_RPL (pthread_key_delete, int, (pthread_key_t key), );
2386_GL_CXXALIAS_RPL (pthread_key_delete, int, (pthread_key_t key));
2387# else
2388# if !1
2389_GL_FUNCDECL_SYS (pthread_key_delete, int, (pthread_key_t key), );
2390# endif
2391_GL_CXXALIAS_SYS (pthread_key_delete, int, (pthread_key_t key));
2392# endif
2393# if __GLIBC__ >= 2
2394_GL_CXXALIASWARN (pthread_key_delete);
2395# endif
2396#elif defined GNULIB_POSIXCHECK
2397# if HAVE_RAW_DECL_PTHREAD_KEY_DELETE
2398_GL_WARN_ON_USE (pthread_key_delete, "pthread_key_delete is not portable - "
2399 "use gnulib module pthread-tss for portability");
2400# endif
2401#endif
2402
2403/* =========== Spinlock functions =========== */
2404
2405#if 0
2406# if 0
2407# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2408# undef pthread_spin_init
2409# define pthread_spin_init rpl_pthread_spin_init
2410# endif
2411_GL_FUNCDECL_RPL (pthread_spin_init, int,
2412 (pthread_spinlock_t *lock, int shared_across_processes),
2413 _GL_ARG_NONNULL ((1)));
2414_GL_CXXALIAS_RPL (pthread_spin_init, int,
2415 (pthread_spinlock_t *lock, int shared_across_processes));
2416# else
2417# if !1
2418_GL_FUNCDECL_SYS (pthread_spin_init, int,
2419 (pthread_spinlock_t *lock, int shared_across_processes),
2420 _GL_ARG_NONNULL ((1)));
2421# endif
2422_GL_CXXALIAS_SYS (pthread_spin_init, int,
2423 (pthread_spinlock_t *lock, int shared_across_processes));
2424# endif
2425# if __GLIBC__ >= 2
2426_GL_CXXALIASWARN (pthread_spin_init);
2427# endif
2428#elif defined GNULIB_POSIXCHECK
2429# if HAVE_RAW_DECL_PTHREAD_SPIN_INIT
2430_GL_WARN_ON_USE (pthread_spin_init, "pthread_spin_init is not portable - "
2431 "use gnulib module pthread-spin for portability");
2432# endif
2433#endif
2434
2435#if 0
2436# if 0
2437# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2438# undef pthread_spin_lock
2439# define pthread_spin_lock rpl_pthread_spin_lock
2440# endif
2441_GL_FUNCDECL_RPL (pthread_spin_lock, int, (pthread_spinlock_t *lock),
2442 _GL_ARG_NONNULL ((1)));
2443_GL_CXXALIAS_RPL (pthread_spin_lock, int, (pthread_spinlock_t *lock));
2444# else
2445# if !1
2446_GL_FUNCDECL_SYS (pthread_spin_lock, int, (pthread_spinlock_t *lock),
2447 _GL_ARG_NONNULL ((1)));
2448# endif
2449_GL_CXXALIAS_SYS (pthread_spin_lock, int, (pthread_spinlock_t *lock));
2450# endif
2451# if __GLIBC__ >= 2
2452_GL_CXXALIASWARN (pthread_spin_lock);
2453# endif
2454#elif defined GNULIB_POSIXCHECK
2455# if HAVE_RAW_DECL_PTHREAD_SPIN_LOCK
2456_GL_WARN_ON_USE (pthread_spin_lock, "pthread_spin_lock is not portable - "
2457 "use gnulib module pthread-spin for portability");
2458# endif
2459#endif
2460
2461#if 0
2462# if 0
2463# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2464# undef pthread_spin_trylock
2465# define pthread_spin_trylock rpl_pthread_spin_trylock
2466# endif
2467_GL_FUNCDECL_RPL (pthread_spin_trylock, int, (pthread_spinlock_t *lock),
2468 _GL_ARG_NONNULL ((1)));
2469_GL_CXXALIAS_RPL (pthread_spin_trylock, int, (pthread_spinlock_t *lock));
2470# else
2471# if !1
2472_GL_FUNCDECL_SYS (pthread_spin_trylock, int, (pthread_spinlock_t *lock),
2473 _GL_ARG_NONNULL ((1)));
2474# endif
2475_GL_CXXALIAS_SYS (pthread_spin_trylock, int, (pthread_spinlock_t *lock));
2476# endif
2477# if __GLIBC__ >= 2
2478_GL_CXXALIASWARN (pthread_spin_trylock);
2479# endif
2480#elif defined GNULIB_POSIXCHECK
2481# if HAVE_RAW_DECL_PTHREAD_SPIN_TRYLOCK
2482_GL_WARN_ON_USE (pthread_spin_trylock, "pthread_spin_trylock is not portable - "
2483 "use gnulib module pthread-spin for portability");
2484# endif
2485#endif
2486
2487#if 0
2488# if 0
2489# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2490# undef pthread_spin_unlock
2491# define pthread_spin_unlock rpl_pthread_spin_unlock
2492# endif
2493_GL_FUNCDECL_RPL (pthread_spin_unlock, int, (pthread_spinlock_t *lock),
2494 _GL_ARG_NONNULL ((1)));
2495_GL_CXXALIAS_RPL (pthread_spin_unlock, int, (pthread_spinlock_t *lock));
2496# else
2497# if !1
2498_GL_FUNCDECL_SYS (pthread_spin_unlock, int, (pthread_spinlock_t *lock),
2499 _GL_ARG_NONNULL ((1)));
2500# endif
2501_GL_CXXALIAS_SYS (pthread_spin_unlock, int, (pthread_spinlock_t *lock));
2502# endif
2503# if __GLIBC__ >= 2
2504_GL_CXXALIASWARN (pthread_spin_unlock);
2505# endif
2506#elif defined GNULIB_POSIXCHECK
2507# if HAVE_RAW_DECL_PTHREAD_SPIN_UNLOCK
2508_GL_WARN_ON_USE (pthread_spin_unlock, "pthread_spin_unlock is not portable - "
2509 "use gnulib module pthread-spin for portability");
2510# endif
2511#endif
2512
2513#if 0
2514# if 0
2515# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2516# undef pthread_spin_destroy
2517# define pthread_spin_destroy rpl_pthread_spin_destroy
2518# endif
2519_GL_FUNCDECL_RPL (pthread_spin_destroy, int, (pthread_spinlock_t *lock),
2520 _GL_ARG_NONNULL ((1)));
2521_GL_CXXALIAS_RPL (pthread_spin_destroy, int, (pthread_spinlock_t *lock));
2522# else
2523# if !1
2524_GL_FUNCDECL_SYS (pthread_spin_destroy, int, (pthread_spinlock_t *lock),
2525 _GL_ARG_NONNULL ((1)));
2526# endif
2527_GL_CXXALIAS_SYS (pthread_spin_destroy, int, (pthread_spinlock_t *lock));
2528# endif
2529# if __GLIBC__ >= 2
2530_GL_CXXALIASWARN (pthread_spin_destroy);
2531# endif
2532#elif defined GNULIB_POSIXCHECK
2533# if HAVE_RAW_DECL_PTHREAD_SPIN_DESTROY
2534_GL_WARN_ON_USE (pthread_spin_destroy, "pthread_spin_destroy is not portable - "
2535 "use gnulib module pthread-spin for portability");
2536# endif
2537#endif
2538
2539
2540#if defined __cplusplus && defined GNULIB_NAMESPACE && !1 && defined __MINGW32__
2541/* Provide the symbols required by mingw's <bits/gthr-default.h>. */
2542using GNULIB_NAMESPACE::pthread_create;
2543using GNULIB_NAMESPACE::pthread_self;
2544using GNULIB_NAMESPACE::pthread_equal;
2545using GNULIB_NAMESPACE::pthread_detach;
2546using GNULIB_NAMESPACE::pthread_join;
2547using GNULIB_NAMESPACE::pthread_once;
2548using GNULIB_NAMESPACE::pthread_mutex_init;
2549using GNULIB_NAMESPACE::pthread_mutexattr_init;
2550using GNULIB_NAMESPACE::pthread_mutexattr_settype;
2551using GNULIB_NAMESPACE::pthread_mutexattr_destroy;
2552using GNULIB_NAMESPACE::pthread_mutex_lock;
2553using GNULIB_NAMESPACE::pthread_mutex_trylock;
2554using GNULIB_NAMESPACE::pthread_mutex_timedlock;
2555using GNULIB_NAMESPACE::pthread_mutex_unlock;
2556using GNULIB_NAMESPACE::pthread_mutex_destroy;
2557using GNULIB_NAMESPACE::pthread_cond_wait;
2558using GNULIB_NAMESPACE::pthread_cond_timedwait;
2559using GNULIB_NAMESPACE::pthread_cond_signal;
2560using GNULIB_NAMESPACE::pthread_cond_broadcast;
2561using GNULIB_NAMESPACE::pthread_cond_destroy;
2562using GNULIB_NAMESPACE::pthread_key_create;
2563using GNULIB_NAMESPACE::pthread_setspecific;
2564using GNULIB_NAMESPACE::pthread_getspecific;
2565using GNULIB_NAMESPACE::pthread_key_delete;
2566#endif
2567
2568
2569#endif /* _GL_PTHREAD_H_ */
2570#endif /* _GL_PTHREAD_H_ */
2571#endif
diff --git a/gl/pthread.in.h b/gl/pthread.in.h
new file mode 100644
index 00000000..28592cfc
--- /dev/null
+++ b/gl/pthread.in.h
@@ -0,0 +1,2032 @@
1/* Implement the most essential subset of POSIX pthread.h.
2
3 Copyright (C) 2009-2025 Free Software Foundation, Inc.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18/* Written by Paul Eggert, Glen Lenker, and Bruno Haible. */
19
20#if __GNUC__ >= 3
21@PRAGMA_SYSTEM_HEADER@
22#endif
23@PRAGMA_COLUMNS@
24
25#if defined _@GUARD_PREFIX@_ALREADY_INCLUDING_PTHREAD_H
26/* Special invocation convention:
27 On Android, we have a sequence of nested includes
28 <pthread.h> -> <time.h> -> <sys/time.h> -> <sys/select.h> ->
29 <signal.h> -> <pthread.h>.
30 In this situation, PTHREAD_COND_INITIALIZER is not yet defined,
31 therefore we should not attempt to define PTHREAD_MUTEX_NORMAL etc. */
32
33#@INCLUDE_NEXT@ @NEXT_PTHREAD_H@
34
35#else
36/* Normal invocation convention. */
37
38#ifndef _@GUARD_PREFIX@_PTHREAD_H_
39
40#if @HAVE_PTHREAD_H@
41
42# define _@GUARD_PREFIX@_ALREADY_INCLUDING_PTHREAD_H
43
44/* The include_next requires a split double-inclusion guard. */
45# @INCLUDE_NEXT@ @NEXT_PTHREAD_H@
46
47# undef _@GUARD_PREFIX@_ALREADY_INCLUDING_PTHREAD_H
48
49#endif
50
51#ifndef _@GUARD_PREFIX@_PTHREAD_H_
52#define _@GUARD_PREFIX@_PTHREAD_H_
53
54/* This file uses _Noreturn, _GL_ATTRIBUTE_PURE, GNULIB_POSIXCHECK,
55 HAVE_RAW_DECL_*. */
56#if !_GL_CONFIG_H_INCLUDED
57 #error "Please include config.h first."
58#endif
59
60#define __need_system_stdlib_h
61#include <stdlib.h>
62#undef __need_system_stdlib_h
63
64
65/* The pthreads-win32 <pthread.h> defines a couple of broken macros. */
66#undef asctime_r
67#undef ctime_r
68#undef gmtime_r
69#undef localtime_r
70#undef rand_r
71#undef strtok_r
72
73#include <errno.h>
74#include <sched.h>
75#include <sys/types.h>
76#include <time.h>
77
78/* The __attribute__ feature is available in gcc versions 2.5 and later.
79 The attribute __pure__ was added in gcc 2.96. */
80#ifndef _GL_ATTRIBUTE_PURE
81# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) || defined __clang__
82# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
83# else
84# define _GL_ATTRIBUTE_PURE /* empty */
85# endif
86#endif
87
88/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
89
90/* The definition of _Noreturn is copied here. */
91
92/* The definition of _GL_ARG_NONNULL is copied here. */
93
94/* The definition of _GL_WARN_ON_USE is copied here. */
95
96/* =========== Thread types and macros =========== */
97
98#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
99# if @GNULIB_PTHREAD_THREAD@
100# include "windows-thread.h"
101# if @HAVE_PTHREAD_T@
102# define pthread_t rpl_pthread_t
103# define pthread_attr_t rpl_pthread_attr_t
104# endif
105# if !GNULIB_defined_pthread_thread_types
106typedef glwthread_thread_t pthread_t;
107typedef unsigned int pthread_attr_t;
108# define GNULIB_defined_pthread_thread_types 1
109# endif
110# else
111# if @HAVE_PTHREAD_T@
112# define pthread_t rpl_pthread_t
113# define pthread_attr_t rpl_pthread_attr_t
114# endif
115# if !GNULIB_defined_pthread_thread_types
116typedef int pthread_t;
117typedef unsigned int pthread_attr_t;
118# define GNULIB_defined_pthread_thread_types 1
119# endif
120# endif
121# undef PTHREAD_CREATE_JOINABLE
122# undef PTHREAD_CREATE_DETACHED
123# define PTHREAD_CREATE_JOINABLE 0
124# define PTHREAD_CREATE_DETACHED 1
125#else
126# if !@HAVE_PTHREAD_T@
127# if !GNULIB_defined_pthread_thread_types
128typedef int pthread_t;
129typedef unsigned int pthread_attr_t;
130# define GNULIB_defined_pthread_thread_types 1
131# endif
132# endif
133# if !@HAVE_PTHREAD_CREATE_DETACHED@
134# define PTHREAD_CREATE_JOINABLE 0
135# define PTHREAD_CREATE_DETACHED 1
136# endif
137#endif
138
139/* =========== Once-only control (initialization) types and macros ========== */
140
141#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
142# if @GNULIB_PTHREAD_ONCE@
143# include "windows-once.h"
144# if @HAVE_PTHREAD_T@
145# define pthread_once_t rpl_pthread_once_t
146# endif
147# if !GNULIB_defined_pthread_once_types
148typedef glwthread_once_t pthread_once_t;
149# define GNULIB_defined_pthread_once_types 1
150# endif
151# undef PTHREAD_ONCE_INIT
152# define PTHREAD_ONCE_INIT GLWTHREAD_ONCE_INIT
153# else
154# if @HAVE_PTHREAD_T@
155# define pthread_once_t rpl_pthread_once_t
156# endif
157# if !GNULIB_defined_pthread_once_types
158typedef int pthread_once_t;
159# define GNULIB_defined_pthread_once_types 1
160# endif
161# undef PTHREAD_ONCE_INIT
162# define PTHREAD_ONCE_INIT { 0 }
163# endif
164#else
165# if !@HAVE_PTHREAD_T@
166# if !GNULIB_defined_pthread_once_types
167typedef int pthread_once_t;
168# define GNULIB_defined_pthread_once_types 1
169# endif
170# undef PTHREAD_ONCE_INIT
171# define PTHREAD_ONCE_INIT { 0 }
172# endif
173#endif
174
175/* =========== Mutex types and macros =========== */
176
177#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
178# if @GNULIB_PTHREAD_MUTEX@
179# include "windows-timedmutex.h"
180# include "windows-timedrecmutex.h"
181# if @HAVE_PTHREAD_T@
182# define pthread_mutex_t rpl_pthread_mutex_t
183# define pthread_mutexattr_t rpl_pthread_mutexattr_t
184# endif
185# if !GNULIB_defined_pthread_mutex_types
186typedef struct
187 {
188 int type;
189 union
190 {
191 glwthread_timedmutex_t u_timedmutex;
192 glwthread_timedrecmutex_t u_timedrecmutex;
193 }
194 u;
195 }
196 pthread_mutex_t;
197typedef unsigned int pthread_mutexattr_t;
198# define GNULIB_defined_pthread_mutex_types 1
199# endif
200# undef PTHREAD_MUTEX_INITIALIZER
201# define PTHREAD_MUTEX_INITIALIZER { 1, { GLWTHREAD_TIMEDMUTEX_INIT } }
202# else
203# if @HAVE_PTHREAD_T@
204# define pthread_mutex_t rpl_pthread_mutex_t
205# define pthread_mutexattr_t rpl_pthread_mutexattr_t
206# endif
207# if !GNULIB_defined_pthread_mutex_types
208typedef int pthread_mutex_t;
209typedef unsigned int pthread_mutexattr_t;
210# define GNULIB_defined_pthread_mutex_types 1
211# endif
212# undef PTHREAD_MUTEX_INITIALIZER
213# define PTHREAD_MUTEX_INITIALIZER { 0 }
214# endif
215# undef PTHREAD_MUTEX_DEFAULT
216# undef PTHREAD_MUTEX_NORMAL
217# undef PTHREAD_MUTEX_ERRORCHECK
218# undef PTHREAD_MUTEX_RECURSIVE
219# define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
220# define PTHREAD_MUTEX_NORMAL 0
221# define PTHREAD_MUTEX_ERRORCHECK 1
222# define PTHREAD_MUTEX_RECURSIVE 2
223# undef PTHREAD_MUTEX_STALLED
224# undef PTHREAD_MUTEX_ROBUST
225# define PTHREAD_MUTEX_STALLED 0
226# define PTHREAD_MUTEX_ROBUST 1
227#else
228# if !@HAVE_PTHREAD_T@
229# if !GNULIB_defined_pthread_mutex_types
230typedef int pthread_mutex_t;
231typedef unsigned int pthread_mutexattr_t;
232# define GNULIB_defined_pthread_mutex_types 1
233# endif
234# undef PTHREAD_MUTEX_INITIALIZER
235# define PTHREAD_MUTEX_INITIALIZER { 0 }
236# endif
237# if !@HAVE_PTHREAD_MUTEX_RECURSIVE@
238# define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
239# define PTHREAD_MUTEX_NORMAL 0
240# define PTHREAD_MUTEX_ERRORCHECK 1
241# define PTHREAD_MUTEX_RECURSIVE 2
242# endif
243# if !@HAVE_PTHREAD_MUTEX_ROBUST@
244# define PTHREAD_MUTEX_STALLED 0
245# define PTHREAD_MUTEX_ROBUST 1
246# endif
247#endif
248
249/* =========== Read-write lock types and macros =========== */
250
251#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
252# if @GNULIB_PTHREAD_RWLOCK@
253# include "windows-timedrwlock.h"
254# if @HAVE_PTHREAD_T@
255# define pthread_rwlock_t rpl_pthread_rwlock_t
256# define pthread_rwlockattr_t rpl_pthread_rwlockattr_t
257# endif
258# if !GNULIB_defined_pthread_rwlock_types
259typedef glwthread_timedrwlock_t pthread_rwlock_t;
260typedef unsigned int pthread_rwlockattr_t;
261# define GNULIB_defined_pthread_rwlock_types 1
262# endif
263# undef PTHREAD_RWLOCK_INITIALIZER
264# define PTHREAD_RWLOCK_INITIALIZER GLWTHREAD_TIMEDRWLOCK_INIT
265# else
266# if @HAVE_PTHREAD_T@
267# define pthread_rwlock_t rpl_pthread_rwlock_t
268# define pthread_rwlockattr_t rpl_pthread_rwlockattr_t
269# endif
270# if !GNULIB_defined_pthread_rwlock_types
271typedef int pthread_rwlock_t;
272typedef unsigned int pthread_rwlockattr_t;
273# define GNULIB_defined_pthread_rwlock_types 1
274# endif
275# undef PTHREAD_RWLOCK_INITIALIZER
276# define PTHREAD_RWLOCK_INITIALIZER { 0 }
277# endif
278#elif @GNULIB_PTHREAD_RWLOCK@ && @REPLACE_PTHREAD_RWLOCK_DESTROY@ /* i.e. PTHREAD_RWLOCK_UNIMPLEMENTED */
279# if @HAVE_PTHREAD_T@
280# define pthread_rwlock_t rpl_pthread_rwlock_t
281# define pthread_rwlockattr_t rpl_pthread_rwlockattr_t
282# endif
283# if !GNULIB_defined_pthread_rwlock_types
284typedef struct
285 {
286 pthread_mutex_t lock; /* protects the remaining fields */
287 pthread_cond_t waiting_readers; /* waiting readers */
288 pthread_cond_t waiting_writers; /* waiting writers */
289 unsigned int waiting_writers_count; /* number of waiting writers */
290 int runcount; /* number of readers running, or -1 when a writer runs */
291 }
292 pthread_rwlock_t;
293typedef unsigned int pthread_rwlockattr_t;
294# define GNULIB_defined_pthread_rwlock_types 1
295# endif
296# undef PTHREAD_RWLOCK_INITIALIZER
297# define PTHREAD_RWLOCK_INITIALIZER \
298 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
299#elif @GNULIB_PTHREAD_RWLOCK@ && @REPLACE_PTHREAD_RWLOCK_INIT@ /* i.e. PTHREAD_RWLOCK_BAD_WAITQUEUE */
300/* Use rwlocks of kind PREFER_WRITER or PREFER_WRITER_NONRECURSIVE instead of
301 the DEFAULT. */
302# undef PTHREAD_RWLOCK_INITIALIZER
303# define PTHREAD_RWLOCK_INITIALIZER PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
304#else
305# if @HAVE_PTHREAD_T@
306# if !defined PTHREAD_RWLOCK_INITIALIZER && defined PTHREAD_RWLOCK_INITIALIZER_NP /* z/OS */
307# define PTHREAD_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER_NP
308# endif
309# else
310# if !GNULIB_defined_pthread_rwlock_types
311typedef int pthread_rwlock_t;
312typedef unsigned int pthread_rwlockattr_t;
313# define GNULIB_defined_pthread_rwlock_types 1
314# endif
315# undef PTHREAD_RWLOCK_INITIALIZER
316# define PTHREAD_RWLOCK_INITIALIZER { 0 }
317# endif
318#endif
319
320/* =========== Condition variable types and macros =========== */
321
322#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
323# if @GNULIB_PTHREAD_COND@
324# include "windows-cond.h"
325# if @HAVE_PTHREAD_T@
326# define pthread_cond_t rpl_pthread_cond_t
327# define pthread_condattr_t rpl_pthread_condattr_t
328# endif
329# if !GNULIB_defined_pthread_cond_types
330typedef glwthread_cond_t pthread_cond_t;
331typedef unsigned int pthread_condattr_t;
332# define GNULIB_defined_pthread_cond_types 1
333# endif
334# undef PTHREAD_COND_INITIALIZER
335# define PTHREAD_COND_INITIALIZER GLWTHREAD_COND_INIT
336# else
337# if @HAVE_PTHREAD_T@
338# define pthread_cond_t rpl_pthread_cond_t
339# define pthread_condattr_t rpl_pthread_condattr_t
340# endif
341# if !GNULIB_defined_pthread_cond_types
342typedef int pthread_cond_t;
343typedef unsigned int pthread_condattr_t;
344# define GNULIB_defined_pthread_cond_types 1
345# endif
346# undef PTHREAD_COND_INITIALIZER
347# define PTHREAD_COND_INITIALIZER { 0 }
348# endif
349#else
350# if !@HAVE_PTHREAD_T@
351# if !GNULIB_defined_pthread_cond_types
352typedef int pthread_cond_t;
353typedef unsigned int pthread_condattr_t;
354# define GNULIB_defined_pthread_cond_types 1
355# endif
356# undef PTHREAD_COND_INITIALIZER
357# define PTHREAD_COND_INITIALIZER { 0 }
358# endif
359#endif
360
361/* =========== Thread-specific storage types and macros =========== */
362
363#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
364# if @GNULIB_PTHREAD_TSS@
365# include "windows-tls.h"
366# if @HAVE_PTHREAD_T@
367# define pthread_key_t rpl_pthread_key_t
368# endif
369# if !GNULIB_defined_pthread_tss_types
370typedef glwthread_tls_key_t pthread_key_t;
371# define GNULIB_defined_pthread_tss_types 1
372# endif
373# undef PTHREAD_DESTRUCTOR_ITERATIONS
374# define PTHREAD_DESTRUCTOR_ITERATIONS GLWTHREAD_DESTRUCTOR_ITERATIONS
375# else
376# if @HAVE_PTHREAD_T@
377# define pthread_key_t rpl_pthread_key_t
378# endif
379# if !GNULIB_defined_pthread_tss_types
380typedef void ** pthread_key_t;
381# define GNULIB_defined_pthread_tss_types 1
382# endif
383# undef PTHREAD_DESTRUCTOR_ITERATIONS
384# define PTHREAD_DESTRUCTOR_ITERATIONS 0
385# endif
386#else
387# if !@HAVE_PTHREAD_T@
388# if !GNULIB_defined_pthread_tss_types
389typedef void ** pthread_key_t;
390# define GNULIB_defined_pthread_tss_types 1
391# endif
392# undef PTHREAD_DESTRUCTOR_ITERATIONS
393# define PTHREAD_DESTRUCTOR_ITERATIONS 0
394# endif
395#endif
396
397/* =========== Spinlock types and macros =========== */
398
399#if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
400# if @GNULIB_PTHREAD_SPIN@
401# include "windows-spin.h"
402# if @HAVE_PTHREAD_T@
403# define pthread_spinlock_t rpl_pthread_spinlock_t
404# endif
405# if !GNULIB_defined_pthread_spin_types
406typedef glwthread_spinlock_t pthread_spinlock_t;
407# define GNULIB_defined_pthread_spin_types 1
408# endif
409# else
410# if @HAVE_PTHREAD_T@
411# define pthread_spinlock_t rpl_pthread_spinlock_t
412# endif
413# if !GNULIB_defined_pthread_spin_types
414typedef pthread_mutex_t pthread_spinlock_t;
415# define GNULIB_defined_pthread_spin_types 1
416# endif
417# endif
418# undef PTHREAD_PROCESS_PRIVATE
419# undef PTHREAD_PROCESS_SHARED
420# define PTHREAD_PROCESS_PRIVATE 0
421# define PTHREAD_PROCESS_SHARED 1
422#else
423# if @HAVE_PTHREAD_SPINLOCK_T@
424/* <pthread.h> exists and defines pthread_spinlock_t. */
425# if !@HAVE_PTHREAD_SPIN_INIT@ || @REPLACE_PTHREAD_SPIN_INIT@
426/* If the 'pthread-spin' module is in use, it defines all the pthread_spin*
427 functions. Prepare for it by overriding pthread_spinlock_t if that might
428 be needed. */
429# if !(((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) \
430 || __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 1)) \
431 || (((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) \
432 && !defined __ANDROID__) \
433 || __clang_major__ >= 3)) \
434 && !defined __ibmxl__)
435/* We can't use GCC built-ins. Approximate spinlocks with mutexes. */
436# if !GNULIB_defined_pthread_spin_types
437# define pthread_spinlock_t pthread_mutex_t
438# define GNULIB_defined_pthread_spin_types 1
439# endif
440# endif
441# endif
442# else
443/* Approximate spinlocks with mutexes. */
444# if !GNULIB_defined_pthread_spin_types
445typedef pthread_mutex_t pthread_spinlock_t;
446# define GNULIB_defined_pthread_spin_types 1
447# endif
448# endif
449# if !@HAVE_PTHREAD_PROCESS_SHARED@
450# define PTHREAD_PROCESS_PRIVATE 0
451# define PTHREAD_PROCESS_SHARED 1
452# endif
453#endif
454
455/* =========== Other types and macros =========== */
456
457#if !@HAVE_PTHREAD_T@
458# if !GNULIB_defined_other_pthread_types
459typedef int pthread_barrier_t;
460typedef unsigned int pthread_barrierattr_t;
461# define GNULIB_defined_other_pthread_types 1
462# endif
463#endif
464
465#if !defined PTHREAD_CANCELED
466
467# define PTHREAD_BARRIER_SERIAL_THREAD (-1)
468
469# define PTHREAD_CANCEL_DEFERRED 0
470# define PTHREAD_CANCEL_ASYNCHRONOUS 1
471
472# define PTHREAD_CANCEL_ENABLE 0
473# define PTHREAD_CANCEL_DISABLE 1
474
475# define PTHREAD_CANCELED ((void *) -1)
476
477# define PTHREAD_INHERIT_SCHED 0
478# define PTHREAD_EXPLICIT_SCHED 1
479
480# define PTHREAD_PRIO_NONE 0
481# define PTHREAD_PRIO_INHERIT 1
482# define PTHREAD_PRIO_PROTECT 2
483
484# define PTHREAD_SCOPE_SYSTEM 0
485# define PTHREAD_SCOPE_PROCESS 1
486
487#endif
488
489/* =========== Thread functions =========== */
490
491#if @GNULIB_PTHREAD_THREAD@
492/* The 'restrict' qualifier on ARG is nonsense, but POSIX specifies it this way.
493 Sigh. */
494# if @REPLACE_PTHREAD_CREATE@
495# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
496# undef pthread_create
497# define pthread_create rpl_pthread_create
498# endif
499_GL_FUNCDECL_RPL (pthread_create, int,
500 (pthread_t *restrict threadp,
501 const pthread_attr_t *restrict attr,
502 void * (*mainfunc) (void *), void *restrict arg),
503 _GL_ARG_NONNULL ((1, 3)));
504_GL_CXXALIAS_RPL (pthread_create, int,
505 (pthread_t *restrict threadp,
506 const pthread_attr_t *restrict attr,
507 void * (*mainfunc) (void *), void *restrict arg));
508# else
509# if !@HAVE_PTHREAD_CREATE@
510_GL_FUNCDECL_SYS (pthread_create, int,
511 (pthread_t *restrict threadp,
512 const pthread_attr_t *restrict attr,
513 void * (*mainfunc) (void *), void *restrict arg),
514 _GL_ARG_NONNULL ((1, 3)));
515# endif
516_GL_CXXALIAS_SYS_CAST (pthread_create, int,
517 (pthread_t *restrict threadp,
518 const pthread_attr_t *restrict attr,
519 void * (*mainfunc) (void *), void *restrict arg));
520# endif
521# if __GLIBC__ >= 2
522_GL_CXXALIASWARN (pthread_create);
523# endif
524#elif defined GNULIB_POSIXCHECK
525# undef pthread_create
526# if HAVE_RAW_DECL_PTHREAD_CREATE
527_GL_WARN_ON_USE (pthread_create, "pthread_create is not portable - "
528 "use gnulib module pthread-thread for portability");
529# endif
530#endif
531
532#if @GNULIB_PTHREAD_THREAD@
533# if @REPLACE_PTHREAD_ATTR_INIT@
534# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
535# undef pthread_attr_init
536# define pthread_attr_init rpl_pthread_attr_init
537# endif
538_GL_FUNCDECL_RPL (pthread_attr_init, int, (pthread_attr_t *attr),
539 _GL_ARG_NONNULL ((1)));
540_GL_CXXALIAS_RPL (pthread_attr_init, int, (pthread_attr_t *attr));
541# else
542# if !@HAVE_PTHREAD_ATTR_INIT@
543_GL_FUNCDECL_SYS (pthread_attr_init, int, (pthread_attr_t *attr),
544 _GL_ARG_NONNULL ((1)));
545# endif
546_GL_CXXALIAS_SYS (pthread_attr_init, int, (pthread_attr_t *attr));
547# endif
548# if __GLIBC__ >= 2
549_GL_CXXALIASWARN (pthread_attr_init);
550# endif
551#elif defined GNULIB_POSIXCHECK
552# undef pthread_attr_init
553# if HAVE_RAW_DECL_PTHREAD_ATTR_INIT
554_GL_WARN_ON_USE (pthread_attr_init, "pthread_attr_init is not portable - "
555 "use gnulib module pthread-thread for portability");
556# endif
557#endif
558
559#if @GNULIB_PTHREAD_THREAD@
560# if @REPLACE_PTHREAD_ATTR_GETDETACHSTATE@
561# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
562# undef pthread_attr_getdetachstate
563# define pthread_attr_getdetachstate rpl_pthread_attr_getdetachstate
564# endif
565_GL_FUNCDECL_RPL (pthread_attr_getdetachstate, int,
566 (const pthread_attr_t *attr, int *detachstatep),
567 _GL_ARG_NONNULL ((1, 2)));
568_GL_CXXALIAS_RPL (pthread_attr_getdetachstate, int,
569 (const pthread_attr_t *attr, int *detachstatep));
570# else
571# if !@HAVE_PTHREAD_ATTR_GETDETACHSTATE@
572_GL_FUNCDECL_SYS (pthread_attr_getdetachstate, int,
573 (const pthread_attr_t *attr, int *detachstatep),
574 _GL_ARG_NONNULL ((1, 2)));
575# endif
576_GL_CXXALIAS_SYS (pthread_attr_getdetachstate, int,
577 (const pthread_attr_t *attr, int *detachstatep));
578# endif
579# if __GLIBC__ >= 2
580_GL_CXXALIASWARN (pthread_attr_getdetachstate);
581# endif
582#elif defined GNULIB_POSIXCHECK
583# undef pthread_attr_getdetachstate
584# if HAVE_RAW_DECL_PTHREAD_ATTR_GETDETACHSTATE
585_GL_WARN_ON_USE (pthread_attr_getdetachstate, "pthread_attr_getdetachstate is not portable - "
586 "use gnulib module pthread-thread for portability");
587# endif
588#endif
589
590#if @GNULIB_PTHREAD_THREAD@
591# if @REPLACE_PTHREAD_ATTR_SETDETACHSTATE@
592# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
593# undef pthread_attr_setdetachstate
594# define pthread_attr_setdetachstate rpl_pthread_attr_setdetachstate
595# endif
596_GL_FUNCDECL_RPL (pthread_attr_setdetachstate, int,
597 (pthread_attr_t *attr, int detachstate),
598 _GL_ARG_NONNULL ((1)));
599_GL_CXXALIAS_RPL (pthread_attr_setdetachstate, int,
600 (pthread_attr_t *attr, int detachstate));
601# else
602# if !@HAVE_PTHREAD_ATTR_SETDETACHSTATE@
603_GL_FUNCDECL_SYS (pthread_attr_setdetachstate, int,
604 (pthread_attr_t *attr, int detachstate),
605 _GL_ARG_NONNULL ((1)));
606# endif
607_GL_CXXALIAS_SYS (pthread_attr_setdetachstate, int,
608 (pthread_attr_t *attr, int detachstate));
609# endif
610# if __GLIBC__ >= 2
611_GL_CXXALIASWARN (pthread_attr_setdetachstate);
612# endif
613#elif defined GNULIB_POSIXCHECK
614# undef pthread_attr_setdetachstate
615# if HAVE_RAW_DECL_PTHREAD_ATTR_SETDETACHSTATE
616_GL_WARN_ON_USE (pthread_attr_setdetachstate, "pthread_attr_setdetachstate is not portable - "
617 "use gnulib module pthread-thread for portability");
618# endif
619#endif
620
621#if @GNULIB_PTHREAD_THREAD@
622# if @REPLACE_PTHREAD_ATTR_DESTROY@
623# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
624# undef pthread_attr_destroy
625# define pthread_attr_destroy rpl_pthread_attr_destroy
626# endif
627_GL_FUNCDECL_RPL (pthread_attr_destroy, int, (pthread_attr_t *attr),
628 _GL_ARG_NONNULL ((1)));
629_GL_CXXALIAS_RPL (pthread_attr_destroy, int, (pthread_attr_t *attr));
630# else
631# if !@HAVE_PTHREAD_ATTR_DESTROY@
632_GL_FUNCDECL_SYS (pthread_attr_destroy, int, (pthread_attr_t *attr),
633 _GL_ARG_NONNULL ((1)));
634# endif
635_GL_CXXALIAS_SYS (pthread_attr_destroy, int, (pthread_attr_t *attr));
636# endif
637# if __GLIBC__ >= 2
638_GL_CXXALIASWARN (pthread_attr_destroy);
639# endif
640#elif defined GNULIB_POSIXCHECK
641# undef pthread_attr_destroy
642# if HAVE_RAW_DECL_PTHREAD_ATTR_DESTROY
643_GL_WARN_ON_USE (pthread_attr_destroy, "pthread_attr_destroy is not portable - "
644 "use gnulib module pthread-thread for portability");
645# endif
646#endif
647
648#if @GNULIB_PTHREAD_THREAD@
649# if @REPLACE_PTHREAD_SELF@
650# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
651# undef pthread_self
652# define pthread_self rpl_pthread_self
653# endif
654_GL_FUNCDECL_RPL (pthread_self, pthread_t, (void), _GL_ATTRIBUTE_PURE);
655_GL_CXXALIAS_RPL (pthread_self, pthread_t, (void));
656# else
657# if !@HAVE_PTHREAD_SELF@
658_GL_FUNCDECL_SYS (pthread_self, pthread_t, (void), _GL_ATTRIBUTE_PURE);
659# endif
660_GL_CXXALIAS_SYS (pthread_self, pthread_t, (void));
661# endif
662# if __GLIBC__ >= 2
663_GL_CXXALIASWARN (pthread_self);
664# endif
665#elif defined GNULIB_POSIXCHECK
666# undef pthread_self
667# if HAVE_RAW_DECL_PTHREAD_SELF
668_GL_WARN_ON_USE (pthread_self, "pthread_self is not portable - "
669 "use gnulib module pthread-thread for portability");
670# endif
671#endif
672
673#if @GNULIB_PTHREAD_THREAD@
674# if @REPLACE_PTHREAD_EQUAL@
675# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
676# undef pthread_equal
677# define pthread_equal rpl_pthread_equal
678# endif
679_GL_FUNCDECL_RPL (pthread_equal, int, (pthread_t thread1, pthread_t thread2), );
680_GL_CXXALIAS_RPL (pthread_equal, int, (pthread_t thread1, pthread_t thread2));
681# else
682# if !@HAVE_PTHREAD_EQUAL@
683_GL_FUNCDECL_SYS (pthread_equal, int, (pthread_t thread1, pthread_t thread2), );
684# endif
685_GL_CXXALIAS_SYS (pthread_equal, int, (pthread_t thread1, pthread_t thread2));
686# endif
687# if __GLIBC__ >= 2
688_GL_CXXALIASWARN (pthread_equal);
689# endif
690#elif defined GNULIB_POSIXCHECK
691# undef pthread_equal
692# if HAVE_RAW_DECL_PTHREAD_EQUAL
693_GL_WARN_ON_USE (pthread_equal, "pthread_equal is not portable - "
694 "use gnulib module pthread-thread for portability");
695# endif
696#endif
697
698#if @GNULIB_PTHREAD_THREAD@
699# if @REPLACE_PTHREAD_DETACH@
700# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
701# undef pthread_detach
702# define pthread_detach rpl_pthread_detach
703# endif
704_GL_FUNCDECL_RPL (pthread_detach, int, (pthread_t thread), );
705_GL_CXXALIAS_RPL (pthread_detach, int, (pthread_t thread));
706# else
707# if !@HAVE_PTHREAD_DETACH@
708_GL_FUNCDECL_SYS (pthread_detach, int, (pthread_t thread), );
709# endif
710_GL_CXXALIAS_SYS (pthread_detach, int, (pthread_t thread));
711# endif
712# if __GLIBC__ >= 2
713_GL_CXXALIASWARN (pthread_detach);
714# endif
715#elif defined GNULIB_POSIXCHECK
716# undef pthread_detach
717# if HAVE_RAW_DECL_PTHREAD_DETACH
718_GL_WARN_ON_USE (pthread_detach, "pthread_detach is not portable - "
719 "use gnulib module pthread-thread for portability");
720# endif
721#endif
722
723#if @GNULIB_PTHREAD_THREAD@
724# if @REPLACE_PTHREAD_JOIN@
725# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
726# undef pthread_join
727# define pthread_join rpl_pthread_join
728# endif
729_GL_FUNCDECL_RPL (pthread_join, int, (pthread_t thread, void **valuep), );
730_GL_CXXALIAS_RPL (pthread_join, int, (pthread_t thread, void **valuep));
731# else
732# if !@HAVE_PTHREAD_JOIN@
733_GL_FUNCDECL_SYS (pthread_join, int, (pthread_t thread, void **valuep), );
734# endif
735_GL_CXXALIAS_SYS (pthread_join, int, (pthread_t thread, void **valuep));
736# endif
737# if __GLIBC__ >= 2
738_GL_CXXALIASWARN (pthread_join);
739# endif
740#elif defined GNULIB_POSIXCHECK
741# undef pthread_join
742# if HAVE_RAW_DECL_PTHREAD_JOIN
743_GL_WARN_ON_USE (pthread_join, "pthread_join is not portable - "
744 "use gnulib module pthread-thread for portability");
745# endif
746#endif
747
748#if @GNULIB_PTHREAD_THREAD@
749# if @REPLACE_PTHREAD_EXIT@
750# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
751# undef pthread_exit
752# define pthread_exit rpl_pthread_exit
753# endif
754_GL_FUNCDECL_RPL (pthread_exit, _Noreturn void, (void *value), );
755_GL_CXXALIAS_RPL (pthread_exit, void, (void *value));
756# else
757# if !@HAVE_PTHREAD_EXIT@
758_GL_FUNCDECL_SYS (pthread_exit, _Noreturn void, (void *value), );
759# endif
760/* Need to cast because of AIX with xlclang++. */
761_GL_CXXALIAS_SYS_CAST (pthread_exit, void, (void *value));
762# endif
763# if __GLIBC__ >= 2
764_GL_CXXALIASWARN (pthread_exit);
765# endif
766#elif defined GNULIB_POSIXCHECK
767# undef pthread_exit
768# if HAVE_RAW_DECL_PTHREAD_EXIT
769_GL_WARN_ON_USE (pthread_exit, "pthread_exit is not portable - "
770 "use gnulib module pthread-thread for portability");
771# endif
772#endif
773
774/* =========== Once-only control (initialization) functions =========== */
775
776#if @GNULIB_PTHREAD_ONCE@
777# if @REPLACE_PTHREAD_ONCE@
778# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
779# undef pthread_once
780# define pthread_once rpl_pthread_once
781# endif
782_GL_FUNCDECL_RPL (pthread_once, int,
783 (pthread_once_t *once_control, void (*initfunction) (void)),
784 _GL_ARG_NONNULL ((1, 2)));
785_GL_CXXALIAS_RPL (pthread_once, int,
786 (pthread_once_t *once_control, void (*initfunction) (void)));
787# else
788# if !@HAVE_PTHREAD_ONCE@
789_GL_FUNCDECL_SYS (pthread_once, int,
790 (pthread_once_t *once_control, void (*initfunction) (void)),
791 _GL_ARG_NONNULL ((1, 2)));
792# endif
793_GL_CXXALIAS_SYS_CAST (pthread_once, int,
794 (pthread_once_t *once_control,
795 void (*initfunction) (void)));
796# endif
797# if __GLIBC__ >= 2
798_GL_CXXALIASWARN (pthread_once);
799# endif
800#elif defined GNULIB_POSIXCHECK
801# undef pthread_once
802# if HAVE_RAW_DECL_PTHREAD_ONCE
803_GL_WARN_ON_USE (pthread_once, "pthread_once is not portable - "
804 "use gnulib module pthread-once for portability");
805# endif
806#endif
807
808/* =========== Mutex functions =========== */
809
810#if @GNULIB_PTHREAD_MUTEX@
811# if @REPLACE_PTHREAD_MUTEX_INIT@
812# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
813# undef pthread_mutex_init
814# define pthread_mutex_init rpl_pthread_mutex_init
815# endif
816_GL_FUNCDECL_RPL (pthread_mutex_init, int,
817 (pthread_mutex_t *restrict mutex,
818 const pthread_mutexattr_t *restrict attr),
819 _GL_ARG_NONNULL ((1)));
820_GL_CXXALIAS_RPL (pthread_mutex_init, int,
821 (pthread_mutex_t *restrict mutex,
822 const pthread_mutexattr_t *restrict attr));
823# else
824# if !@HAVE_PTHREAD_MUTEX_INIT@
825_GL_FUNCDECL_SYS (pthread_mutex_init, int,
826 (pthread_mutex_t *restrict mutex,
827 const pthread_mutexattr_t *restrict attr),
828 _GL_ARG_NONNULL ((1)));
829# endif
830_GL_CXXALIAS_SYS (pthread_mutex_init, int,
831 (pthread_mutex_t *restrict mutex,
832 const pthread_mutexattr_t *restrict attr));
833# endif
834# if __GLIBC__ >= 2
835_GL_CXXALIASWARN (pthread_mutex_init);
836# endif
837#elif defined GNULIB_POSIXCHECK
838# undef pthread_mutex_init
839# if HAVE_RAW_DECL_PTHREAD_MUTEX_INIT
840_GL_WARN_ON_USE (pthread_mutex_init, "pthread_mutex_init is not portable - "
841 "use gnulib module pthread-mutex for portability");
842# endif
843#endif
844
845#if @GNULIB_PTHREAD_MUTEX@
846# if @REPLACE_PTHREAD_MUTEXATTR_INIT@
847# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
848# undef pthread_mutexattr_init
849# define pthread_mutexattr_init rpl_pthread_mutexattr_init
850# endif
851_GL_FUNCDECL_RPL (pthread_mutexattr_init, int, (pthread_mutexattr_t *attr),
852 _GL_ARG_NONNULL ((1)));
853_GL_CXXALIAS_RPL (pthread_mutexattr_init, int, (pthread_mutexattr_t *attr));
854# else
855# if !@HAVE_PTHREAD_MUTEXATTR_INIT@
856_GL_FUNCDECL_SYS (pthread_mutexattr_init, int, (pthread_mutexattr_t *attr),
857 _GL_ARG_NONNULL ((1)));
858# endif
859_GL_CXXALIAS_SYS (pthread_mutexattr_init, int, (pthread_mutexattr_t *attr));
860# endif
861# if __GLIBC__ >= 2
862_GL_CXXALIASWARN (pthread_mutexattr_init);
863# endif
864#elif defined GNULIB_POSIXCHECK
865# undef pthread_mutexattr_init
866# if HAVE_RAW_DECL_PTHREAD_MUTEXATTR_INIT
867_GL_WARN_ON_USE (pthread_mutexattr_init, "pthread_mutexattr_init is not portable - "
868 "use gnulib module pthread-mutex for portability");
869# endif
870#endif
871
872#if @GNULIB_PTHREAD_MUTEX@
873# if @REPLACE_PTHREAD_MUTEXATTR_GETTYPE@
874# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
875# undef pthread_mutexattr_gettype
876# define pthread_mutexattr_gettype rpl_pthread_mutexattr_gettype
877# endif
878_GL_FUNCDECL_RPL (pthread_mutexattr_gettype, int,
879 (const pthread_mutexattr_t *restrict attr,
880 int *restrict typep),
881 _GL_ARG_NONNULL ((1, 2)));
882_GL_CXXALIAS_RPL (pthread_mutexattr_gettype, int,
883 (const pthread_mutexattr_t *restrict attr,
884 int *restrict typep));
885# else
886# if !@HAVE_PTHREAD_MUTEXATTR_GETTYPE@
887_GL_FUNCDECL_SYS (pthread_mutexattr_gettype, int,
888 (const pthread_mutexattr_t *restrict attr,
889 int *restrict typep),
890 _GL_ARG_NONNULL ((1, 2)));
891# endif
892/* Need to cast, because on FreeBSD the first parameter is
893 pthread_mutexattr_t *attr. */
894_GL_CXXALIAS_SYS_CAST (pthread_mutexattr_gettype, int,
895 (const pthread_mutexattr_t *restrict attr,
896 int *restrict typep));
897# endif
898# if __GLIBC__ >= 2
899_GL_CXXALIASWARN (pthread_mutexattr_gettype);
900# endif
901#elif defined GNULIB_POSIXCHECK
902# undef pthread_mutexattr_gettype
903# if HAVE_RAW_DECL_PTHREAD_MUTEXATTR_GETTYPE
904_GL_WARN_ON_USE (pthread_mutexattr_gettype, "pthread_mutexattr_gettype is not portable - "
905 "use gnulib module pthread-mutex for portability");
906# endif
907#endif
908
909#if @GNULIB_PTHREAD_MUTEX@
910# if @REPLACE_PTHREAD_MUTEXATTR_SETTYPE@
911# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
912# undef pthread_mutexattr_settype
913# define pthread_mutexattr_settype rpl_pthread_mutexattr_settype
914# endif
915_GL_FUNCDECL_RPL (pthread_mutexattr_settype, int,
916 (pthread_mutexattr_t *attr, int type), _GL_ARG_NONNULL ((1)));
917_GL_CXXALIAS_RPL (pthread_mutexattr_settype, int,
918 (pthread_mutexattr_t *attr, int type));
919# else
920# if !@HAVE_PTHREAD_MUTEXATTR_SETTYPE@
921_GL_FUNCDECL_SYS (pthread_mutexattr_settype, int,
922 (pthread_mutexattr_t *attr, int type), _GL_ARG_NONNULL ((1)));
923# endif
924_GL_CXXALIAS_SYS (pthread_mutexattr_settype, int,
925 (pthread_mutexattr_t *attr, int type));
926# endif
927# if __GLIBC__ >= 2
928_GL_CXXALIASWARN (pthread_mutexattr_settype);
929# endif
930#elif defined GNULIB_POSIXCHECK
931# undef pthread_mutexattr_settype
932# if HAVE_RAW_DECL_PTHREAD_MUTEXATTR_SETTYPE
933_GL_WARN_ON_USE (pthread_mutexattr_settype, "pthread_mutexattr_settype is not portable - "
934 "use gnulib module pthread-mutex for portability");
935# endif
936#endif
937
938#if @GNULIB_PTHREAD_MUTEX@
939# if @REPLACE_PTHREAD_MUTEXATTR_GETROBUST@
940# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
941# undef pthread_mutexattr_getrobust
942# define pthread_mutexattr_getrobust rpl_pthread_mutexattr_getrobust
943# endif
944_GL_FUNCDECL_RPL (pthread_mutexattr_getrobust, int,
945 (const pthread_mutexattr_t *restrict attr,
946 int *restrict robustp),
947 _GL_ARG_NONNULL ((1, 2)));
948_GL_CXXALIAS_RPL (pthread_mutexattr_getrobust, int,
949 (const pthread_mutexattr_t *restrict attr,
950 int *restrict robustp));
951# else
952# if !@HAVE_PTHREAD_MUTEXATTR_GETROBUST@
953_GL_FUNCDECL_SYS (pthread_mutexattr_getrobust, int,
954 (const pthread_mutexattr_t *restrict attr,
955 int *restrict robustp),
956 _GL_ARG_NONNULL ((1, 2)));
957# endif
958/* Need to cast, because on FreeBSD the first parameter is
959 pthread_mutexattr_t *attr. */
960_GL_CXXALIAS_SYS_CAST (pthread_mutexattr_getrobust, int,
961 (const pthread_mutexattr_t *restrict attr,
962 int *restrict robustp));
963# endif
964# if __GLIBC__ >= 2
965_GL_CXXALIASWARN (pthread_mutexattr_getrobust);
966# endif
967#elif defined GNULIB_POSIXCHECK
968# undef pthread_mutexattr_getrobust
969# if HAVE_RAW_DECL_PTHREAD_MUTEXATTR_GETROBUST
970_GL_WARN_ON_USE (pthread_mutexattr_getrobust, "pthread_mutexattr_getrobust is not portable - "
971 "use gnulib module pthread-mutex for portability");
972# endif
973#endif
974
975#if @GNULIB_PTHREAD_MUTEX@
976# if @REPLACE_PTHREAD_MUTEXATTR_SETROBUST@
977# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
978# undef pthread_mutexattr_setrobust
979# define pthread_mutexattr_setrobust rpl_pthread_mutexattr_setrobust
980# endif
981_GL_FUNCDECL_RPL (pthread_mutexattr_setrobust, int,
982 (pthread_mutexattr_t *attr, int robust),
983 _GL_ARG_NONNULL ((1)));
984_GL_CXXALIAS_RPL (pthread_mutexattr_setrobust, int,
985 (pthread_mutexattr_t *attr, int robust));
986# else
987# if !@HAVE_PTHREAD_MUTEXATTR_SETROBUST@
988_GL_FUNCDECL_SYS (pthread_mutexattr_setrobust, int,
989 (pthread_mutexattr_t *attr, int robust),
990 _GL_ARG_NONNULL ((1)));
991# endif
992_GL_CXXALIAS_SYS (pthread_mutexattr_setrobust, int,
993 (pthread_mutexattr_t *attr, int robust));
994# endif
995# if __GLIBC__ >= 2
996_GL_CXXALIASWARN (pthread_mutexattr_setrobust);
997# endif
998#elif defined GNULIB_POSIXCHECK
999# undef pthread_mutexattr_setrobust
1000# if HAVE_RAW_DECL_PTHREAD_MUTEXATTR_SETROBUST
1001_GL_WARN_ON_USE (pthread_mutexattr_setrobust, "pthread_mutexattr_setrobust is not portable - "
1002 "use gnulib module pthread-mutex for portability");
1003# endif
1004#endif
1005
1006#if @GNULIB_PTHREAD_MUTEX@
1007# if @REPLACE_PTHREAD_MUTEXATTR_DESTROY@
1008# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1009# undef pthread_mutexattr_destroy
1010# define pthread_mutexattr_destroy rpl_pthread_mutexattr_destroy
1011# endif
1012_GL_FUNCDECL_RPL (pthread_mutexattr_destroy, int, (pthread_mutexattr_t *attr),
1013 _GL_ARG_NONNULL ((1)));
1014_GL_CXXALIAS_RPL (pthread_mutexattr_destroy, int, (pthread_mutexattr_t *attr));
1015# else
1016# if !@HAVE_PTHREAD_MUTEXATTR_DESTROY@
1017_GL_FUNCDECL_SYS (pthread_mutexattr_destroy, int, (pthread_mutexattr_t *attr),
1018 _GL_ARG_NONNULL ((1)));
1019# endif
1020_GL_CXXALIAS_SYS (pthread_mutexattr_destroy, int, (pthread_mutexattr_t *attr));
1021# endif
1022# if __GLIBC__ >= 2
1023_GL_CXXALIASWARN (pthread_mutexattr_destroy);
1024# endif
1025#elif defined GNULIB_POSIXCHECK
1026# undef pthread_mutexattr_destroy
1027# if HAVE_RAW_DECL_PTHREAD_MUTEXATTR_DESTROY
1028_GL_WARN_ON_USE (pthread_mutexattr_destroy, "pthread_mutexattr_destroy is not portable - "
1029 "use gnulib module pthread-mutex for portability");
1030# endif
1031#endif
1032
1033#if @GNULIB_PTHREAD_MUTEX@
1034# if @REPLACE_PTHREAD_MUTEX_LOCK@
1035# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1036# undef pthread_mutex_lock
1037# define pthread_mutex_lock rpl_pthread_mutex_lock
1038# endif
1039_GL_FUNCDECL_RPL (pthread_mutex_lock, int, (pthread_mutex_t *mutex),
1040 _GL_ARG_NONNULL ((1)));
1041_GL_CXXALIAS_RPL (pthread_mutex_lock, int, (pthread_mutex_t *mutex));
1042# else
1043# if !@HAVE_PTHREAD_MUTEX_LOCK@
1044_GL_FUNCDECL_SYS (pthread_mutex_lock, int, (pthread_mutex_t *mutex),
1045 _GL_ARG_NONNULL ((1)));
1046# endif
1047_GL_CXXALIAS_SYS (pthread_mutex_lock, int, (pthread_mutex_t *mutex));
1048# endif
1049# if __GLIBC__ >= 2
1050_GL_CXXALIASWARN (pthread_mutex_lock);
1051# endif
1052#elif defined GNULIB_POSIXCHECK
1053# undef pthread_mutex_lock
1054# if HAVE_RAW_DECL_PTHREAD_MUTEX_LOCK
1055_GL_WARN_ON_USE (pthread_mutex_lock, "pthread_mutex_lock is not portable - "
1056 "use gnulib module pthread-mutex for portability");
1057# endif
1058#endif
1059
1060#if @GNULIB_PTHREAD_MUTEX@
1061# if @REPLACE_PTHREAD_MUTEX_TRYLOCK@
1062# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1063# undef pthread_mutex_trylock
1064# define pthread_mutex_trylock rpl_pthread_mutex_trylock
1065# endif
1066_GL_FUNCDECL_RPL (pthread_mutex_trylock, int, (pthread_mutex_t *mutex),
1067 _GL_ARG_NONNULL ((1)));
1068_GL_CXXALIAS_RPL (pthread_mutex_trylock, int, (pthread_mutex_t *mutex));
1069# else
1070# if !@HAVE_PTHREAD_MUTEX_TRYLOCK@
1071_GL_FUNCDECL_SYS (pthread_mutex_trylock, int, (pthread_mutex_t *mutex),
1072 _GL_ARG_NONNULL ((1)));
1073# endif
1074_GL_CXXALIAS_SYS (pthread_mutex_trylock, int, (pthread_mutex_t *mutex));
1075# endif
1076# if __GLIBC__ >= 2
1077_GL_CXXALIASWARN (pthread_mutex_trylock);
1078# endif
1079#elif defined GNULIB_POSIXCHECK
1080# undef pthread_mutex_trylock
1081# if HAVE_RAW_DECL_PTHREAD_MUTEX_TRYLOCK
1082_GL_WARN_ON_USE (pthread_mutex_trylock, "pthread_mutex_trylock is not portable - "
1083 "use gnulib module pthread-mutex for portability");
1084# endif
1085#endif
1086
1087#if @GNULIB_PTHREAD_MUTEX_TIMEDLOCK@
1088# if @REPLACE_PTHREAD_MUTEX_TIMEDLOCK@
1089# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1090# undef pthread_mutex_timedlock
1091# define pthread_mutex_timedlock rpl_pthread_mutex_timedlock
1092# endif
1093_GL_FUNCDECL_RPL (pthread_mutex_timedlock, int,
1094 (pthread_mutex_t *restrict mutex,
1095 const struct timespec *restrict abstime),
1096 _GL_ARG_NONNULL ((1, 2)));
1097_GL_CXXALIAS_RPL (pthread_mutex_timedlock, int,
1098 (pthread_mutex_t *restrict mutex,
1099 const struct timespec *restrict abstime));
1100# else
1101# if !@HAVE_PTHREAD_MUTEX_TIMEDLOCK@
1102_GL_FUNCDECL_SYS (pthread_mutex_timedlock, int,
1103 (pthread_mutex_t *restrict mutex,
1104 const struct timespec *restrict abstime),
1105 _GL_ARG_NONNULL ((1, 2)));
1106# endif
1107_GL_CXXALIAS_SYS (pthread_mutex_timedlock, int,
1108 (pthread_mutex_t *restrict mutex,
1109 const struct timespec *restrict abstime));
1110# endif
1111# if __GLIBC__ >= 2
1112_GL_CXXALIASWARN (pthread_mutex_timedlock);
1113# endif
1114#elif defined GNULIB_POSIXCHECK
1115# undef pthread_mutex_timedlock
1116# if HAVE_RAW_DECL_PTHREAD_MUTEX_TIMEDLOCK
1117_GL_WARN_ON_USE (pthread_mutex_timedlock, "pthread_mutex_timedlock is not portable - "
1118 "use gnulib module pthread_mutex_timedlock for portability");
1119# endif
1120#endif
1121
1122#if @GNULIB_PTHREAD_MUTEX@
1123# if @REPLACE_PTHREAD_MUTEX_UNLOCK@
1124# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1125# undef pthread_mutex_unlock
1126# define pthread_mutex_unlock rpl_pthread_mutex_unlock
1127# endif
1128_GL_FUNCDECL_RPL (pthread_mutex_unlock, int, (pthread_mutex_t *mutex),
1129 _GL_ARG_NONNULL ((1)));
1130_GL_CXXALIAS_RPL (pthread_mutex_unlock, int, (pthread_mutex_t *mutex));
1131# else
1132# if !@HAVE_PTHREAD_MUTEX_UNLOCK@
1133_GL_FUNCDECL_SYS (pthread_mutex_unlock, int, (pthread_mutex_t *mutex),
1134 _GL_ARG_NONNULL ((1)));
1135# endif
1136_GL_CXXALIAS_SYS (pthread_mutex_unlock, int, (pthread_mutex_t *mutex));
1137# endif
1138# if __GLIBC__ >= 2
1139_GL_CXXALIASWARN (pthread_mutex_unlock);
1140# endif
1141#elif defined GNULIB_POSIXCHECK
1142# undef pthread_mutex_unlock
1143# if HAVE_RAW_DECL_PTHREAD_MUTEX_UNLOCK
1144_GL_WARN_ON_USE (pthread_mutex_unlock, "pthread_mutex_unlock is not portable - "
1145 "use gnulib module pthread-mutex for portability");
1146# endif
1147#endif
1148
1149#if @GNULIB_PTHREAD_MUTEX@
1150# if @REPLACE_PTHREAD_MUTEX_DESTROY@
1151# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1152# undef pthread_mutex_destroy
1153# define pthread_mutex_destroy rpl_pthread_mutex_destroy
1154# endif
1155_GL_FUNCDECL_RPL (pthread_mutex_destroy, int, (pthread_mutex_t *mutex),
1156 _GL_ARG_NONNULL ((1)));
1157_GL_CXXALIAS_RPL (pthread_mutex_destroy, int, (pthread_mutex_t *mutex));
1158# else
1159# if !@HAVE_PTHREAD_MUTEX_DESTROY@
1160_GL_FUNCDECL_SYS (pthread_mutex_destroy, int, (pthread_mutex_t *mutex),
1161 _GL_ARG_NONNULL ((1)));
1162# endif
1163_GL_CXXALIAS_SYS (pthread_mutex_destroy, int, (pthread_mutex_t *mutex));
1164# endif
1165# if __GLIBC__ >= 2
1166_GL_CXXALIASWARN (pthread_mutex_destroy);
1167# endif
1168#elif defined GNULIB_POSIXCHECK
1169# undef pthread_mutex_destroy
1170# if HAVE_RAW_DECL_PTHREAD_MUTEX_DESTROY
1171_GL_WARN_ON_USE (pthread_mutex_destroy, "pthread_mutex_destroy is not portable - "
1172 "use gnulib module pthread-mutex for portability");
1173# endif
1174#endif
1175
1176/* =========== Read-write lock functions =========== */
1177
1178#if @GNULIB_PTHREAD_RWLOCK@
1179# if @REPLACE_PTHREAD_RWLOCK_INIT@
1180# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1181# undef pthread_rwlock_init
1182# define pthread_rwlock_init rpl_pthread_rwlock_init
1183# endif
1184_GL_FUNCDECL_RPL (pthread_rwlock_init, int,
1185 (pthread_rwlock_t *restrict lock,
1186 const pthread_rwlockattr_t *restrict attr),
1187 _GL_ARG_NONNULL ((1)));
1188_GL_CXXALIAS_RPL (pthread_rwlock_init, int,
1189 (pthread_rwlock_t *restrict lock,
1190 const pthread_rwlockattr_t *restrict attr));
1191# else
1192# if !@HAVE_PTHREAD_RWLOCK_INIT@
1193_GL_FUNCDECL_SYS (pthread_rwlock_init, int,
1194 (pthread_rwlock_t *restrict lock,
1195 const pthread_rwlockattr_t *restrict attr),
1196 _GL_ARG_NONNULL ((1)));
1197# endif
1198_GL_CXXALIAS_SYS (pthread_rwlock_init, int,
1199 (pthread_rwlock_t *restrict lock,
1200 const pthread_rwlockattr_t *restrict attr));
1201# endif
1202# if __GLIBC__ >= 2
1203_GL_CXXALIASWARN (pthread_rwlock_init);
1204# endif
1205#elif defined GNULIB_POSIXCHECK
1206# undef pthread_rwlock_init
1207# if HAVE_RAW_DECL_PTHREAD_RWLOCK_INIT
1208_GL_WARN_ON_USE (pthread_rwlock_init, "pthread_rwlock_init is not portable - "
1209 "use gnulib module pthread-rwlock for portability");
1210# endif
1211#endif
1212
1213#if @GNULIB_PTHREAD_RWLOCK@
1214# if @REPLACE_PTHREAD_RWLOCKATTR_INIT@
1215# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1216# undef pthread_rwlockattr_init
1217# define pthread_rwlockattr_init rpl_pthread_rwlockattr_init
1218# endif
1219_GL_FUNCDECL_RPL (pthread_rwlockattr_init, int, (pthread_rwlockattr_t *attr),
1220 _GL_ARG_NONNULL ((1)));
1221_GL_CXXALIAS_RPL (pthread_rwlockattr_init, int, (pthread_rwlockattr_t *attr));
1222# else
1223# if !@HAVE_PTHREAD_RWLOCKATTR_INIT@
1224_GL_FUNCDECL_SYS (pthread_rwlockattr_init, int, (pthread_rwlockattr_t *attr),
1225 _GL_ARG_NONNULL ((1)));
1226# endif
1227_GL_CXXALIAS_SYS (pthread_rwlockattr_init, int, (pthread_rwlockattr_t *attr));
1228# endif
1229# if __GLIBC__ >= 2
1230_GL_CXXALIASWARN (pthread_rwlockattr_init);
1231# endif
1232#elif defined GNULIB_POSIXCHECK
1233# undef pthread_rwlockattr_init
1234# if HAVE_RAW_DECL_PTHREAD_RWLOCKATTR_INIT
1235_GL_WARN_ON_USE (pthread_rwlockattr_init, "pthread_rwlockattr_init is not portable - "
1236 "use gnulib module pthread-rwlock for portability");
1237# endif
1238#endif
1239
1240#if @GNULIB_PTHREAD_RWLOCK@
1241# if @REPLACE_PTHREAD_RWLOCKATTR_DESTROY@
1242# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1243# undef pthread_rwlockattr_destroy
1244# define pthread_rwlockattr_destroy rpl_pthread_rwlockattr_destroy
1245# endif
1246_GL_FUNCDECL_RPL (pthread_rwlockattr_destroy, int,
1247 (pthread_rwlockattr_t *attr), _GL_ARG_NONNULL ((1)));
1248_GL_CXXALIAS_RPL (pthread_rwlockattr_destroy, int,
1249 (pthread_rwlockattr_t *attr));
1250# else
1251# if !@HAVE_PTHREAD_RWLOCKATTR_DESTROY@
1252_GL_FUNCDECL_SYS (pthread_rwlockattr_destroy, int,
1253 (pthread_rwlockattr_t *attr), _GL_ARG_NONNULL ((1)));
1254# endif
1255_GL_CXXALIAS_SYS (pthread_rwlockattr_destroy, int,
1256 (pthread_rwlockattr_t *attr));
1257# endif
1258# if __GLIBC__ >= 2
1259_GL_CXXALIASWARN (pthread_rwlockattr_destroy);
1260# endif
1261#elif defined GNULIB_POSIXCHECK
1262# undef pthread_rwlockattr_destroy
1263# if HAVE_RAW_DECL_PTHREAD_RWLOCKATTR_DESTROY
1264_GL_WARN_ON_USE (pthread_rwlockattr_destroy, "pthread_rwlockattr_destroy is not portable - "
1265 "use gnulib module pthread-rwlock for portability");
1266# endif
1267#endif
1268
1269#if @GNULIB_PTHREAD_RWLOCK@
1270# if @REPLACE_PTHREAD_RWLOCK_RDLOCK@
1271# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1272# undef pthread_rwlock_rdlock
1273# define pthread_rwlock_rdlock rpl_pthread_rwlock_rdlock
1274# endif
1275_GL_FUNCDECL_RPL (pthread_rwlock_rdlock, int, (pthread_rwlock_t *lock),
1276 _GL_ARG_NONNULL ((1)));
1277_GL_CXXALIAS_RPL (pthread_rwlock_rdlock, int, (pthread_rwlock_t *lock));
1278# else
1279# if !@HAVE_PTHREAD_RWLOCK_RDLOCK@
1280_GL_FUNCDECL_SYS (pthread_rwlock_rdlock, int, (pthread_rwlock_t *lock),
1281 _GL_ARG_NONNULL ((1)));
1282# endif
1283_GL_CXXALIAS_SYS (pthread_rwlock_rdlock, int, (pthread_rwlock_t *lock));
1284# endif
1285# if __GLIBC__ >= 2
1286_GL_CXXALIASWARN (pthread_rwlock_rdlock);
1287# endif
1288#elif defined GNULIB_POSIXCHECK
1289# undef pthread_rwlock_rdlock
1290# if HAVE_RAW_DECL_PTHREAD_RWLOCK_RDLOCK
1291_GL_WARN_ON_USE (pthread_rwlock_rdlock, "pthread_rwlock_rdlock is not portable - "
1292 "use gnulib module pthread-rwlock for portability");
1293# endif
1294#endif
1295
1296#if @GNULIB_PTHREAD_RWLOCK@
1297# if @REPLACE_PTHREAD_RWLOCK_WRLOCK@
1298# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1299# undef pthread_rwlock_wrlock
1300# define pthread_rwlock_wrlock rpl_pthread_rwlock_wrlock
1301# endif
1302_GL_FUNCDECL_RPL (pthread_rwlock_wrlock, int, (pthread_rwlock_t *lock),
1303 _GL_ARG_NONNULL ((1)));
1304_GL_CXXALIAS_RPL (pthread_rwlock_wrlock, int, (pthread_rwlock_t *lock));
1305# else
1306# if !@HAVE_PTHREAD_RWLOCK_WRLOCK@
1307_GL_FUNCDECL_SYS (pthread_rwlock_wrlock, int, (pthread_rwlock_t *lock),
1308 _GL_ARG_NONNULL ((1)));
1309# endif
1310_GL_CXXALIAS_SYS (pthread_rwlock_wrlock, int, (pthread_rwlock_t *lock));
1311# endif
1312# if __GLIBC__ >= 2
1313_GL_CXXALIASWARN (pthread_rwlock_wrlock);
1314# endif
1315#elif defined GNULIB_POSIXCHECK
1316# undef pthread_rwlock_wrlock
1317# if HAVE_RAW_DECL_PTHREAD_RWLOCK_WRLOCK
1318_GL_WARN_ON_USE (pthread_rwlock_wrlock, "pthread_rwlock_wrlock is not portable - "
1319 "use gnulib module pthread-rwlock for portability");
1320# endif
1321#endif
1322
1323#if @GNULIB_PTHREAD_RWLOCK@
1324# if @REPLACE_PTHREAD_RWLOCK_TRYRDLOCK@
1325# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1326# undef pthread_rwlock_tryrdlock
1327# define pthread_rwlock_tryrdlock rpl_pthread_rwlock_tryrdlock
1328# endif
1329_GL_FUNCDECL_RPL (pthread_rwlock_tryrdlock, int, (pthread_rwlock_t *lock),
1330 _GL_ARG_NONNULL ((1)));
1331_GL_CXXALIAS_RPL (pthread_rwlock_tryrdlock, int, (pthread_rwlock_t *lock));
1332# else
1333# if !@HAVE_PTHREAD_RWLOCK_TRYRDLOCK@
1334_GL_FUNCDECL_SYS (pthread_rwlock_tryrdlock, int, (pthread_rwlock_t *lock),
1335 _GL_ARG_NONNULL ((1)));
1336# endif
1337_GL_CXXALIAS_SYS (pthread_rwlock_tryrdlock, int, (pthread_rwlock_t *lock));
1338# endif
1339# if __GLIBC__ >= 2
1340_GL_CXXALIASWARN (pthread_rwlock_tryrdlock);
1341# endif
1342#elif defined GNULIB_POSIXCHECK
1343# undef pthread_rwlock_tryrdlock
1344# if HAVE_RAW_DECL_PTHREAD_RWLOCK_TRYRDLOCK
1345_GL_WARN_ON_USE (pthread_rwlock_tryrdlock, "pthread_rwlock_tryrdlock is not portable - "
1346 "use gnulib module pthread-rwlock for portability");
1347# endif
1348#endif
1349
1350#if @GNULIB_PTHREAD_RWLOCK@
1351# if @REPLACE_PTHREAD_RWLOCK_TRYWRLOCK@
1352# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1353# undef pthread_rwlock_trywrlock
1354# define pthread_rwlock_trywrlock rpl_pthread_rwlock_trywrlock
1355# endif
1356_GL_FUNCDECL_RPL (pthread_rwlock_trywrlock, int, (pthread_rwlock_t *lock),
1357 _GL_ARG_NONNULL ((1)));
1358_GL_CXXALIAS_RPL (pthread_rwlock_trywrlock, int, (pthread_rwlock_t *lock));
1359# else
1360# if !@HAVE_PTHREAD_RWLOCK_TRYWRLOCK@
1361_GL_FUNCDECL_SYS (pthread_rwlock_trywrlock, int, (pthread_rwlock_t *lock),
1362 _GL_ARG_NONNULL ((1)));
1363# endif
1364_GL_CXXALIAS_SYS (pthread_rwlock_trywrlock, int, (pthread_rwlock_t *lock));
1365# endif
1366# if __GLIBC__ >= 2
1367_GL_CXXALIASWARN (pthread_rwlock_trywrlock);
1368# endif
1369#elif defined GNULIB_POSIXCHECK
1370# undef pthread_rwlock_trywrlock
1371# if HAVE_RAW_DECL_PTHREAD_RWLOCK_TRYWRLOCK
1372_GL_WARN_ON_USE (pthread_rwlock_trywrlock, "pthread_rwlock_trywrlock is not portable - "
1373 "use gnulib module pthread-rwlock for portability");
1374# endif
1375#endif
1376
1377#if @GNULIB_PTHREAD_RWLOCK@
1378# if @REPLACE_PTHREAD_RWLOCK_TIMEDRDLOCK@
1379# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1380# undef pthread_rwlock_timedrdlock
1381# define pthread_rwlock_timedrdlock rpl_pthread_rwlock_timedrdlock
1382# endif
1383_GL_FUNCDECL_RPL (pthread_rwlock_timedrdlock, int,
1384 (pthread_rwlock_t *restrict lock,
1385 const struct timespec *restrict abstime),
1386 _GL_ARG_NONNULL ((1, 2)));
1387_GL_CXXALIAS_RPL (pthread_rwlock_timedrdlock, int,
1388 (pthread_rwlock_t *restrict lock,
1389 const struct timespec *restrict abstime));
1390# else
1391# if !@HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK@
1392_GL_FUNCDECL_SYS (pthread_rwlock_timedrdlock, int,
1393 (pthread_rwlock_t *restrict lock,
1394 const struct timespec *restrict abstime),
1395 _GL_ARG_NONNULL ((1, 2)));
1396# endif
1397_GL_CXXALIAS_SYS (pthread_rwlock_timedrdlock, int,
1398 (pthread_rwlock_t *restrict lock,
1399 const struct timespec *restrict abstime));
1400# endif
1401# if __GLIBC__ >= 2
1402_GL_CXXALIASWARN (pthread_rwlock_timedrdlock);
1403# endif
1404#elif defined GNULIB_POSIXCHECK
1405# undef pthread_rwlock_timedrdlock
1406# if HAVE_RAW_DECL_PTHREAD_RWLOCK_TIMEDRDLOCK
1407_GL_WARN_ON_USE (pthread_rwlock_timedrdlock, "pthread_rwlock_timedrdlock is not portable - "
1408 "use gnulib module pthread-rwlock for portability");
1409# endif
1410#endif
1411
1412#if @GNULIB_PTHREAD_RWLOCK@
1413# if @REPLACE_PTHREAD_RWLOCK_TIMEDWRLOCK@
1414# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1415# undef pthread_rwlock_timedwrlock
1416# define pthread_rwlock_timedwrlock rpl_pthread_rwlock_timedwrlock
1417# endif
1418_GL_FUNCDECL_RPL (pthread_rwlock_timedwrlock, int,
1419 (pthread_rwlock_t *restrict lock,
1420 const struct timespec *restrict abstime),
1421 _GL_ARG_NONNULL ((1, 2)));
1422_GL_CXXALIAS_RPL (pthread_rwlock_timedwrlock, int,
1423 (pthread_rwlock_t *restrict lock,
1424 const struct timespec *restrict abstime));
1425# else
1426# if !@HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK@
1427_GL_FUNCDECL_SYS (pthread_rwlock_timedwrlock, int,
1428 (pthread_rwlock_t *restrict lock,
1429 const struct timespec *restrict abstime),
1430 _GL_ARG_NONNULL ((1, 2)));
1431# endif
1432_GL_CXXALIAS_SYS (pthread_rwlock_timedwrlock, int,
1433 (pthread_rwlock_t *restrict lock,
1434 const struct timespec *restrict abstime));
1435# endif
1436# if __GLIBC__ >= 2
1437_GL_CXXALIASWARN (pthread_rwlock_timedwrlock);
1438# endif
1439#elif defined GNULIB_POSIXCHECK
1440# undef pthread_rwlock_timedwrlock
1441# if HAVE_RAW_DECL_PTHREAD_RWLOCK_TIMEDWRLOCK
1442_GL_WARN_ON_USE (pthread_rwlock_timedwrlock, "pthread_rwlock_timedwrlock is not portable - "
1443 "use gnulib module pthread-rwlock for portability");
1444# endif
1445#endif
1446
1447#if @GNULIB_PTHREAD_RWLOCK@
1448# if @REPLACE_PTHREAD_RWLOCK_UNLOCK@
1449# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1450# undef pthread_rwlock_unlock
1451# define pthread_rwlock_unlock rpl_pthread_rwlock_unlock
1452# endif
1453_GL_FUNCDECL_RPL (pthread_rwlock_unlock, int, (pthread_rwlock_t *lock),
1454 _GL_ARG_NONNULL ((1)));
1455_GL_CXXALIAS_RPL (pthread_rwlock_unlock, int, (pthread_rwlock_t *lock));
1456# else
1457# if !@HAVE_PTHREAD_RWLOCK_UNLOCK@
1458_GL_FUNCDECL_SYS (pthread_rwlock_unlock, int, (pthread_rwlock_t *lock),
1459 _GL_ARG_NONNULL ((1)));
1460# endif
1461_GL_CXXALIAS_SYS (pthread_rwlock_unlock, int, (pthread_rwlock_t *lock));
1462# endif
1463# if __GLIBC__ >= 2
1464_GL_CXXALIASWARN (pthread_rwlock_unlock);
1465# endif
1466#elif defined GNULIB_POSIXCHECK
1467# undef pthread_rwlock_unlock
1468# if HAVE_RAW_DECL_PTHREAD_RWLOCK_UNLOCK
1469_GL_WARN_ON_USE (pthread_rwlock_unlock, "pthread_rwlock_unlock is not portable - "
1470 "use gnulib module pthread-rwlock for portability");
1471# endif
1472#endif
1473
1474#if @GNULIB_PTHREAD_RWLOCK@
1475# if @REPLACE_PTHREAD_RWLOCK_DESTROY@
1476# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1477# undef pthread_rwlock_destroy
1478# define pthread_rwlock_destroy rpl_pthread_rwlock_destroy
1479# endif
1480_GL_FUNCDECL_RPL (pthread_rwlock_destroy, int, (pthread_rwlock_t *lock),
1481 _GL_ARG_NONNULL ((1)));
1482_GL_CXXALIAS_RPL (pthread_rwlock_destroy, int, (pthread_rwlock_t *lock));
1483# else
1484# if !@HAVE_PTHREAD_RWLOCK_DESTROY@
1485_GL_FUNCDECL_SYS (pthread_rwlock_destroy, int, (pthread_rwlock_t *lock),
1486 _GL_ARG_NONNULL ((1)));
1487# endif
1488_GL_CXXALIAS_SYS (pthread_rwlock_destroy, int, (pthread_rwlock_t *lock));
1489# endif
1490# if __GLIBC__ >= 2
1491_GL_CXXALIASWARN (pthread_rwlock_destroy);
1492# endif
1493#elif defined GNULIB_POSIXCHECK
1494# undef pthread_rwlock_destroy
1495# if HAVE_RAW_DECL_PTHREAD_RWLOCK_DESTROY
1496_GL_WARN_ON_USE (pthread_rwlock_destroy, "pthread_rwlock_destroy is not portable - "
1497 "use gnulib module pthread-rwlock for portability");
1498# endif
1499#endif
1500
1501/* =========== Condition variable functions =========== */
1502
1503#if @GNULIB_PTHREAD_COND@
1504# if @REPLACE_PTHREAD_COND_INIT@
1505# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1506# undef pthread_cond_init
1507# define pthread_cond_init rpl_pthread_cond_init
1508# endif
1509_GL_FUNCDECL_RPL (pthread_cond_init, int,
1510 (pthread_cond_t *restrict cond,
1511 const pthread_condattr_t *restrict attr),
1512 _GL_ARG_NONNULL ((1)));
1513_GL_CXXALIAS_RPL (pthread_cond_init, int,
1514 (pthread_cond_t *restrict cond,
1515 const pthread_condattr_t *restrict attr));
1516# else
1517# if !@HAVE_PTHREAD_COND_INIT@
1518_GL_FUNCDECL_SYS (pthread_cond_init, int,
1519 (pthread_cond_t *restrict cond,
1520 const pthread_condattr_t *restrict attr),
1521 _GL_ARG_NONNULL ((1)));
1522# endif
1523_GL_CXXALIAS_SYS (pthread_cond_init, int,
1524 (pthread_cond_t *restrict cond,
1525 const pthread_condattr_t *restrict attr));
1526# endif
1527# if __GLIBC__ >= 2
1528_GL_CXXALIASWARN (pthread_cond_init);
1529# endif
1530#elif defined GNULIB_POSIXCHECK
1531# undef pthread_cond_init
1532# if HAVE_RAW_DECL_PTHREAD_COND_INIT
1533_GL_WARN_ON_USE (pthread_cond_init, "pthread_cond_init is not portable - "
1534 "use gnulib module pthread-cond for portability");
1535# endif
1536#endif
1537
1538#if @GNULIB_PTHREAD_COND@
1539# if @REPLACE_PTHREAD_CONDATTR_INIT@
1540# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1541# undef pthread_condattr_init
1542# define pthread_condattr_init rpl_pthread_condattr_init
1543# endif
1544_GL_FUNCDECL_RPL (pthread_condattr_init, int, (pthread_condattr_t *attr),
1545 _GL_ARG_NONNULL ((1)));
1546_GL_CXXALIAS_RPL (pthread_condattr_init, int, (pthread_condattr_t *attr));
1547# else
1548# if !@HAVE_PTHREAD_CONDATTR_INIT@
1549_GL_FUNCDECL_SYS (pthread_condattr_init, int, (pthread_condattr_t *attr),
1550 _GL_ARG_NONNULL ((1)));
1551# endif
1552_GL_CXXALIAS_SYS (pthread_condattr_init, int, (pthread_condattr_t *attr));
1553# endif
1554# if __GLIBC__ >= 2
1555_GL_CXXALIASWARN (pthread_condattr_init);
1556# endif
1557#elif defined GNULIB_POSIXCHECK
1558# undef pthread_condattr_init
1559# if HAVE_RAW_DECL_PTHREAD_CONDATTR_INIT
1560_GL_WARN_ON_USE (pthread_condattr_init, "pthread_condattr_init is not portable - "
1561 "use gnulib module pthread-cond for portability");
1562# endif
1563#endif
1564
1565#if @GNULIB_PTHREAD_COND@
1566# if @REPLACE_PTHREAD_CONDATTR_DESTROY@
1567# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1568# undef pthread_condattr_destroy
1569# define pthread_condattr_destroy rpl_pthread_condattr_destroy
1570# endif
1571_GL_FUNCDECL_RPL (pthread_condattr_destroy, int, (pthread_condattr_t *attr),
1572 _GL_ARG_NONNULL ((1)));
1573_GL_CXXALIAS_RPL (pthread_condattr_destroy, int, (pthread_condattr_t *attr));
1574# else
1575# if !@HAVE_PTHREAD_CONDATTR_DESTROY@
1576_GL_FUNCDECL_SYS (pthread_condattr_destroy, int, (pthread_condattr_t *attr),
1577 _GL_ARG_NONNULL ((1)));
1578# endif
1579_GL_CXXALIAS_SYS (pthread_condattr_destroy, int, (pthread_condattr_t *attr));
1580# endif
1581# if __GLIBC__ >= 2
1582_GL_CXXALIASWARN (pthread_condattr_destroy);
1583# endif
1584#elif defined GNULIB_POSIXCHECK
1585# undef pthread_condattr_destroy
1586# if HAVE_RAW_DECL_PTHREAD_CONDATTR_DESTROY
1587_GL_WARN_ON_USE (pthread_condattr_destroy, "pthread_condattr_destroy is not portable - "
1588 "use gnulib module pthread-cond for portability");
1589# endif
1590#endif
1591
1592#if @GNULIB_PTHREAD_COND@
1593# if @REPLACE_PTHREAD_COND_WAIT@
1594# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1595# undef pthread_cond_wait
1596# define pthread_cond_wait rpl_pthread_cond_wait
1597# endif
1598_GL_FUNCDECL_RPL (pthread_cond_wait, int,
1599 (pthread_cond_t *restrict cond,
1600 pthread_mutex_t *restrict mutex),
1601 _GL_ARG_NONNULL ((1, 2)));
1602_GL_CXXALIAS_RPL (pthread_cond_wait, int,
1603 (pthread_cond_t *restrict cond,
1604 pthread_mutex_t *restrict mutex));
1605# else
1606# if !@HAVE_PTHREAD_COND_WAIT@
1607_GL_FUNCDECL_SYS (pthread_cond_wait, int,
1608 (pthread_cond_t *restrict cond,
1609 pthread_mutex_t *restrict mutex),
1610 _GL_ARG_NONNULL ((1, 2)));
1611# endif
1612_GL_CXXALIAS_SYS (pthread_cond_wait, int,
1613 (pthread_cond_t *restrict cond,
1614 pthread_mutex_t *restrict mutex));
1615# endif
1616# if __GLIBC__ >= 2
1617_GL_CXXALIASWARN (pthread_cond_wait);
1618# endif
1619#elif defined GNULIB_POSIXCHECK
1620# undef pthread_cond_wait
1621# if HAVE_RAW_DECL_PTHREAD_COND_WAIT
1622_GL_WARN_ON_USE (pthread_cond_wait, "pthread_cond_wait is not portable - "
1623 "use gnulib module pthread-cond for portability");
1624# endif
1625#endif
1626
1627#if @GNULIB_PTHREAD_COND@
1628# if @REPLACE_PTHREAD_COND_TIMEDWAIT@
1629# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1630# undef pthread_cond_timedwait
1631# define pthread_cond_timedwait rpl_pthread_cond_timedwait
1632# endif
1633_GL_FUNCDECL_RPL (pthread_cond_timedwait, int,
1634 (pthread_cond_t *restrict cond,
1635 pthread_mutex_t *restrict mutex,
1636 const struct timespec *restrict abstime),
1637 _GL_ARG_NONNULL ((1, 2, 3)));
1638_GL_CXXALIAS_RPL (pthread_cond_timedwait, int,
1639 (pthread_cond_t *restrict cond,
1640 pthread_mutex_t *restrict mutex,
1641 const struct timespec *restrict abstime));
1642# else
1643# if !@HAVE_PTHREAD_COND_TIMEDWAIT@
1644_GL_FUNCDECL_SYS (pthread_cond_timedwait, int,
1645 (pthread_cond_t *restrict cond,
1646 pthread_mutex_t *restrict mutex,
1647 const struct timespec *restrict abstime),
1648 _GL_ARG_NONNULL ((1, 2, 3)));
1649# endif
1650_GL_CXXALIAS_SYS (pthread_cond_timedwait, int,
1651 (pthread_cond_t *restrict cond,
1652 pthread_mutex_t *restrict mutex,
1653 const struct timespec *restrict abstime));
1654# endif
1655# if __GLIBC__ >= 2
1656_GL_CXXALIASWARN (pthread_cond_timedwait);
1657# endif
1658#elif defined GNULIB_POSIXCHECK
1659# undef pthread_cond_timedwait
1660# if HAVE_RAW_DECL_PTHREAD_COND_TIMEDWAIT
1661_GL_WARN_ON_USE (pthread_cond_timedwait, "pthread_cond_timedwait is not portable - "
1662 "use gnulib module pthread-cond for portability");
1663# endif
1664#endif
1665
1666#if @GNULIB_PTHREAD_COND@
1667# if @REPLACE_PTHREAD_COND_SIGNAL@
1668# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1669# undef pthread_cond_signal
1670# define pthread_cond_signal rpl_pthread_cond_signal
1671# endif
1672_GL_FUNCDECL_RPL (pthread_cond_signal, int, (pthread_cond_t *cond),
1673 _GL_ARG_NONNULL ((1)));
1674_GL_CXXALIAS_RPL (pthread_cond_signal, int, (pthread_cond_t *cond));
1675# else
1676# if !@HAVE_PTHREAD_COND_SIGNAL@
1677_GL_FUNCDECL_SYS (pthread_cond_signal, int, (pthread_cond_t *cond),
1678 _GL_ARG_NONNULL ((1)));
1679# endif
1680_GL_CXXALIAS_SYS (pthread_cond_signal, int, (pthread_cond_t *cond));
1681# endif
1682# if __GLIBC__ >= 2
1683_GL_CXXALIASWARN (pthread_cond_signal);
1684# endif
1685#elif defined GNULIB_POSIXCHECK
1686# undef pthread_cond_signal
1687# if HAVE_RAW_DECL_PTHREAD_COND_SIGNAL
1688_GL_WARN_ON_USE (pthread_cond_signal, "pthread_cond_signal is not portable - "
1689 "use gnulib module pthread-cond for portability");
1690# endif
1691#endif
1692
1693#if @GNULIB_PTHREAD_COND@
1694# if @REPLACE_PTHREAD_COND_BROADCAST@
1695# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1696# undef pthread_cond_broadcast
1697# define pthread_cond_broadcast rpl_pthread_cond_broadcast
1698# endif
1699_GL_FUNCDECL_RPL (pthread_cond_broadcast, int, (pthread_cond_t *cond),
1700 _GL_ARG_NONNULL ((1)));
1701_GL_CXXALIAS_RPL (pthread_cond_broadcast, int, (pthread_cond_t *cond));
1702# else
1703# if !@HAVE_PTHREAD_COND_BROADCAST@
1704_GL_FUNCDECL_SYS (pthread_cond_broadcast, int, (pthread_cond_t *cond),
1705 _GL_ARG_NONNULL ((1)));
1706# endif
1707_GL_CXXALIAS_SYS (pthread_cond_broadcast, int, (pthread_cond_t *cond));
1708# endif
1709# if __GLIBC__ >= 2
1710_GL_CXXALIASWARN (pthread_cond_broadcast);
1711# endif
1712#elif defined GNULIB_POSIXCHECK
1713# undef pthread_cond_broadcast
1714# if HAVE_RAW_DECL_PTHREAD_COND_BROADCAST
1715_GL_WARN_ON_USE (pthread_cond_broadcast, "pthread_cond_broadcast is not portable - "
1716 "use gnulib module pthread-cond for portability");
1717# endif
1718#endif
1719
1720#if @GNULIB_PTHREAD_COND@
1721# if @REPLACE_PTHREAD_COND_DESTROY@
1722# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1723# undef pthread_cond_destroy
1724# define pthread_cond_destroy rpl_pthread_cond_destroy
1725# endif
1726_GL_FUNCDECL_RPL (pthread_cond_destroy, int, (pthread_cond_t *cond),
1727 _GL_ARG_NONNULL ((1)));
1728_GL_CXXALIAS_RPL (pthread_cond_destroy, int, (pthread_cond_t *cond));
1729# else
1730# if !@HAVE_PTHREAD_COND_DESTROY@
1731_GL_FUNCDECL_SYS (pthread_cond_destroy, int, (pthread_cond_t *cond),
1732 _GL_ARG_NONNULL ((1)));
1733# endif
1734_GL_CXXALIAS_SYS (pthread_cond_destroy, int, (pthread_cond_t *cond));
1735# endif
1736# if __GLIBC__ >= 2
1737_GL_CXXALIASWARN (pthread_cond_destroy);
1738# endif
1739#elif defined GNULIB_POSIXCHECK
1740# undef pthread_cond_destroy
1741# if HAVE_RAW_DECL_PTHREAD_COND_DESTROY
1742_GL_WARN_ON_USE (pthread_cond_destroy, "pthread_cond_destroy is not portable - "
1743 "use gnulib module pthread-cond for portability");
1744# endif
1745#endif
1746
1747/* =========== Thread-specific storage functions =========== */
1748
1749#if @GNULIB_PTHREAD_TSS@
1750# if @REPLACE_PTHREAD_KEY_CREATE@
1751# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1752# undef pthread_key_create
1753# define pthread_key_create rpl_pthread_key_create
1754# endif
1755_GL_FUNCDECL_RPL (pthread_key_create, int,
1756 (pthread_key_t *keyp, void (*destructor) (void *)),
1757 _GL_ARG_NONNULL ((1)));
1758_GL_CXXALIAS_RPL (pthread_key_create, int,
1759 (pthread_key_t *keyp, void (*destructor) (void *)));
1760# else
1761# if !@HAVE_PTHREAD_KEY_CREATE@
1762_GL_FUNCDECL_SYS (pthread_key_create, int,
1763 (pthread_key_t *keyp, void (*destructor) (void *)),
1764 _GL_ARG_NONNULL ((1)));
1765# endif
1766_GL_CXXALIAS_SYS_CAST (pthread_key_create, int,
1767 (pthread_key_t *keyp, void (*destructor) (void *)));
1768# endif
1769# if __GLIBC__ >= 2
1770_GL_CXXALIASWARN (pthread_key_create);
1771# endif
1772#elif defined GNULIB_POSIXCHECK
1773# undef pthread_key_create
1774# if HAVE_RAW_DECL_PTHREAD_KEY_CREATE
1775_GL_WARN_ON_USE (pthread_key_create, "pthread_key_create is not portable - "
1776 "use gnulib module pthread-tss for portability");
1777# endif
1778#endif
1779
1780#if @GNULIB_PTHREAD_TSS@
1781# if @REPLACE_PTHREAD_SETSPECIFIC@
1782# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1783# undef pthread_setspecific
1784# define pthread_setspecific rpl_pthread_setspecific
1785# endif
1786_GL_FUNCDECL_RPL (pthread_setspecific, int,
1787 (pthread_key_t key, const void *value), );
1788_GL_CXXALIAS_RPL (pthread_setspecific, int,
1789 (pthread_key_t key, const void *value));
1790# else
1791# if !@HAVE_PTHREAD_SETSPECIFIC@
1792_GL_FUNCDECL_SYS (pthread_setspecific, int,
1793 (pthread_key_t key, const void *value), );
1794# endif
1795_GL_CXXALIAS_SYS (pthread_setspecific, int,
1796 (pthread_key_t key, const void *value));
1797# endif
1798# if __GLIBC__ >= 2
1799_GL_CXXALIASWARN (pthread_setspecific);
1800# endif
1801#elif defined GNULIB_POSIXCHECK
1802# undef pthread_setspecific
1803# if HAVE_RAW_DECL_PTHREAD_SETSPECIFIC
1804_GL_WARN_ON_USE (pthread_setspecific, "pthread_setspecific is not portable - "
1805 "use gnulib module pthread-tss for portability");
1806# endif
1807#endif
1808
1809#if @GNULIB_PTHREAD_TSS@
1810# if @REPLACE_PTHREAD_GETSPECIFIC@
1811# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1812# undef pthread_getspecific
1813# define pthread_getspecific rpl_pthread_getspecific
1814# endif
1815_GL_FUNCDECL_RPL (pthread_getspecific, void *, (pthread_key_t key), );
1816_GL_CXXALIAS_RPL (pthread_getspecific, void *, (pthread_key_t key));
1817# else
1818# if !@HAVE_PTHREAD_GETSPECIFIC@
1819_GL_FUNCDECL_SYS (pthread_getspecific, void *, (pthread_key_t key), );
1820# endif
1821_GL_CXXALIAS_SYS (pthread_getspecific, void *, (pthread_key_t key));
1822# endif
1823# if __GLIBC__ >= 2
1824_GL_CXXALIASWARN (pthread_getspecific);
1825# endif
1826#elif defined GNULIB_POSIXCHECK
1827# undef pthread_getspecific
1828# if HAVE_RAW_DECL_PTHREAD_GETSPECIFIC
1829_GL_WARN_ON_USE (pthread_getspecific, "pthread_getspecific is not portable - "
1830 "use gnulib module pthread-tss for portability");
1831# endif
1832#endif
1833
1834#if @GNULIB_PTHREAD_TSS@
1835# if @REPLACE_PTHREAD_KEY_DELETE@
1836# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1837# undef pthread_key_delete
1838# define pthread_key_delete rpl_pthread_key_delete
1839# endif
1840_GL_FUNCDECL_RPL (pthread_key_delete, int, (pthread_key_t key), );
1841_GL_CXXALIAS_RPL (pthread_key_delete, int, (pthread_key_t key));
1842# else
1843# if !@HAVE_PTHREAD_KEY_DELETE@
1844_GL_FUNCDECL_SYS (pthread_key_delete, int, (pthread_key_t key), );
1845# endif
1846_GL_CXXALIAS_SYS (pthread_key_delete, int, (pthread_key_t key));
1847# endif
1848# if __GLIBC__ >= 2
1849_GL_CXXALIASWARN (pthread_key_delete);
1850# endif
1851#elif defined GNULIB_POSIXCHECK
1852# undef pthread_key_delete
1853# if HAVE_RAW_DECL_PTHREAD_KEY_DELETE
1854_GL_WARN_ON_USE (pthread_key_delete, "pthread_key_delete is not portable - "
1855 "use gnulib module pthread-tss for portability");
1856# endif
1857#endif
1858
1859/* =========== Spinlock functions =========== */
1860
1861#if @GNULIB_PTHREAD_SPIN@
1862# if @REPLACE_PTHREAD_SPIN_INIT@
1863# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1864# undef pthread_spin_init
1865# define pthread_spin_init rpl_pthread_spin_init
1866# endif
1867_GL_FUNCDECL_RPL (pthread_spin_init, int,
1868 (pthread_spinlock_t *lock, int shared_across_processes),
1869 _GL_ARG_NONNULL ((1)));
1870_GL_CXXALIAS_RPL (pthread_spin_init, int,
1871 (pthread_spinlock_t *lock, int shared_across_processes));
1872# else
1873# if !@HAVE_PTHREAD_SPIN_INIT@
1874_GL_FUNCDECL_SYS (pthread_spin_init, int,
1875 (pthread_spinlock_t *lock, int shared_across_processes),
1876 _GL_ARG_NONNULL ((1)));
1877# endif
1878_GL_CXXALIAS_SYS (pthread_spin_init, int,
1879 (pthread_spinlock_t *lock, int shared_across_processes));
1880# endif
1881# if __GLIBC__ >= 2
1882_GL_CXXALIASWARN (pthread_spin_init);
1883# endif
1884#elif defined GNULIB_POSIXCHECK
1885# undef pthread_spin_init
1886# if HAVE_RAW_DECL_PTHREAD_SPIN_INIT
1887_GL_WARN_ON_USE (pthread_spin_init, "pthread_spin_init is not portable - "
1888 "use gnulib module pthread-spin for portability");
1889# endif
1890#endif
1891
1892#if @GNULIB_PTHREAD_SPIN@
1893# if @REPLACE_PTHREAD_SPIN_LOCK@
1894# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1895# undef pthread_spin_lock
1896# define pthread_spin_lock rpl_pthread_spin_lock
1897# endif
1898_GL_FUNCDECL_RPL (pthread_spin_lock, int, (pthread_spinlock_t *lock),
1899 _GL_ARG_NONNULL ((1)));
1900_GL_CXXALIAS_RPL (pthread_spin_lock, int, (pthread_spinlock_t *lock));
1901# else
1902# if !@HAVE_PTHREAD_SPIN_LOCK@
1903_GL_FUNCDECL_SYS (pthread_spin_lock, int, (pthread_spinlock_t *lock),
1904 _GL_ARG_NONNULL ((1)));
1905# endif
1906_GL_CXXALIAS_SYS (pthread_spin_lock, int, (pthread_spinlock_t *lock));
1907# endif
1908# if __GLIBC__ >= 2
1909_GL_CXXALIASWARN (pthread_spin_lock);
1910# endif
1911#elif defined GNULIB_POSIXCHECK
1912# undef pthread_spin_lock
1913# if HAVE_RAW_DECL_PTHREAD_SPIN_LOCK
1914_GL_WARN_ON_USE (pthread_spin_lock, "pthread_spin_lock is not portable - "
1915 "use gnulib module pthread-spin for portability");
1916# endif
1917#endif
1918
1919#if @GNULIB_PTHREAD_SPIN@
1920# if @REPLACE_PTHREAD_SPIN_TRYLOCK@
1921# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1922# undef pthread_spin_trylock
1923# define pthread_spin_trylock rpl_pthread_spin_trylock
1924# endif
1925_GL_FUNCDECL_RPL (pthread_spin_trylock, int, (pthread_spinlock_t *lock),
1926 _GL_ARG_NONNULL ((1)));
1927_GL_CXXALIAS_RPL (pthread_spin_trylock, int, (pthread_spinlock_t *lock));
1928# else
1929# if !@HAVE_PTHREAD_SPIN_TRYLOCK@
1930_GL_FUNCDECL_SYS (pthread_spin_trylock, int, (pthread_spinlock_t *lock),
1931 _GL_ARG_NONNULL ((1)));
1932# endif
1933_GL_CXXALIAS_SYS (pthread_spin_trylock, int, (pthread_spinlock_t *lock));
1934# endif
1935# if __GLIBC__ >= 2
1936_GL_CXXALIASWARN (pthread_spin_trylock);
1937# endif
1938#elif defined GNULIB_POSIXCHECK
1939# undef pthread_spin_trylock
1940# if HAVE_RAW_DECL_PTHREAD_SPIN_TRYLOCK
1941_GL_WARN_ON_USE (pthread_spin_trylock, "pthread_spin_trylock is not portable - "
1942 "use gnulib module pthread-spin for portability");
1943# endif
1944#endif
1945
1946#if @GNULIB_PTHREAD_SPIN@
1947# if @REPLACE_PTHREAD_SPIN_UNLOCK@
1948# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1949# undef pthread_spin_unlock
1950# define pthread_spin_unlock rpl_pthread_spin_unlock
1951# endif
1952_GL_FUNCDECL_RPL (pthread_spin_unlock, int, (pthread_spinlock_t *lock),
1953 _GL_ARG_NONNULL ((1)));
1954_GL_CXXALIAS_RPL (pthread_spin_unlock, int, (pthread_spinlock_t *lock));
1955# else
1956# if !@HAVE_PTHREAD_SPIN_UNLOCK@
1957_GL_FUNCDECL_SYS (pthread_spin_unlock, int, (pthread_spinlock_t *lock),
1958 _GL_ARG_NONNULL ((1)));
1959# endif
1960_GL_CXXALIAS_SYS (pthread_spin_unlock, int, (pthread_spinlock_t *lock));
1961# endif
1962# if __GLIBC__ >= 2
1963_GL_CXXALIASWARN (pthread_spin_unlock);
1964# endif
1965#elif defined GNULIB_POSIXCHECK
1966# undef pthread_spin_unlock
1967# if HAVE_RAW_DECL_PTHREAD_SPIN_UNLOCK
1968_GL_WARN_ON_USE (pthread_spin_unlock, "pthread_spin_unlock is not portable - "
1969 "use gnulib module pthread-spin for portability");
1970# endif
1971#endif
1972
1973#if @GNULIB_PTHREAD_SPIN@
1974# if @REPLACE_PTHREAD_SPIN_DESTROY@
1975# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1976# undef pthread_spin_destroy
1977# define pthread_spin_destroy rpl_pthread_spin_destroy
1978# endif
1979_GL_FUNCDECL_RPL (pthread_spin_destroy, int, (pthread_spinlock_t *lock),
1980 _GL_ARG_NONNULL ((1)));
1981_GL_CXXALIAS_RPL (pthread_spin_destroy, int, (pthread_spinlock_t *lock));
1982# else
1983# if !@HAVE_PTHREAD_SPIN_DESTROY@
1984_GL_FUNCDECL_SYS (pthread_spin_destroy, int, (pthread_spinlock_t *lock),
1985 _GL_ARG_NONNULL ((1)));
1986# endif
1987_GL_CXXALIAS_SYS (pthread_spin_destroy, int, (pthread_spinlock_t *lock));
1988# endif
1989# if __GLIBC__ >= 2
1990_GL_CXXALIASWARN (pthread_spin_destroy);
1991# endif
1992#elif defined GNULIB_POSIXCHECK
1993# undef pthread_spin_destroy
1994# if HAVE_RAW_DECL_PTHREAD_SPIN_DESTROY
1995_GL_WARN_ON_USE (pthread_spin_destroy, "pthread_spin_destroy is not portable - "
1996 "use gnulib module pthread-spin for portability");
1997# endif
1998#endif
1999
2000
2001#if defined __cplusplus && defined GNULIB_NAMESPACE && !@HAVE_PTHREAD_H@ && defined __MINGW32__
2002/* Provide the symbols required by mingw's <bits/gthr-default.h>. */
2003using GNULIB_NAMESPACE::pthread_create;
2004using GNULIB_NAMESPACE::pthread_self;
2005using GNULIB_NAMESPACE::pthread_equal;
2006using GNULIB_NAMESPACE::pthread_detach;
2007using GNULIB_NAMESPACE::pthread_join;
2008using GNULIB_NAMESPACE::pthread_once;
2009using GNULIB_NAMESPACE::pthread_mutex_init;
2010using GNULIB_NAMESPACE::pthread_mutexattr_init;
2011using GNULIB_NAMESPACE::pthread_mutexattr_settype;
2012using GNULIB_NAMESPACE::pthread_mutexattr_destroy;
2013using GNULIB_NAMESPACE::pthread_mutex_lock;
2014using GNULIB_NAMESPACE::pthread_mutex_trylock;
2015using GNULIB_NAMESPACE::pthread_mutex_timedlock;
2016using GNULIB_NAMESPACE::pthread_mutex_unlock;
2017using GNULIB_NAMESPACE::pthread_mutex_destroy;
2018using GNULIB_NAMESPACE::pthread_cond_wait;
2019using GNULIB_NAMESPACE::pthread_cond_timedwait;
2020using GNULIB_NAMESPACE::pthread_cond_signal;
2021using GNULIB_NAMESPACE::pthread_cond_broadcast;
2022using GNULIB_NAMESPACE::pthread_cond_destroy;
2023using GNULIB_NAMESPACE::pthread_key_create;
2024using GNULIB_NAMESPACE::pthread_setspecific;
2025using GNULIB_NAMESPACE::pthread_getspecific;
2026using GNULIB_NAMESPACE::pthread_key_delete;
2027#endif
2028
2029
2030#endif /* _@GUARD_PREFIX@_PTHREAD_H_ */
2031#endif /* _@GUARD_PREFIX@_PTHREAD_H_ */
2032#endif
diff --git a/gl/realloc.c b/gl/realloc.c
index 05731396..04a28561 100644
--- a/gl/realloc.c
+++ b/gl/realloc.c
@@ -1,6 +1,6 @@
1/* realloc() function that is glibc compatible. 1/* realloc() function that is glibc compatible.
2 2
3 Copyright (C) 1997, 2003-2004, 2006-2007, 2009-2024 Free Software 3 Copyright (C) 1997, 2003-2004, 2006-2007, 2009-2025 Free Software
4 Foundation, Inc. 4 Foundation, Inc.
5 5
6 This file is free software: you can redistribute it and/or modify 6 This file is free software: you can redistribute it and/or modify
@@ -18,17 +18,21 @@
18 18
19/* written by Jim Meyering and Bruno Haible */ 19/* written by Jim Meyering and Bruno Haible */
20 20
21/* Ensure that we call the system's realloc() below. */
22#define _GL_USE_STDLIB_ALLOC 1
21#include <config.h> 23#include <config.h>
22 24
25#define _GL_REALLOC_INLINE _GL_EXTERN_INLINE
23#include <stdlib.h> 26#include <stdlib.h>
24 27
25#include <errno.h> 28#include <errno.h>
29#include <stdckdint.h>
26 30
27#include "xalloc-oversized.h" 31#ifdef __CHERI_PURE_CAPABILITY__
32# include <cheri.h>
33#endif
28 34
29/* Call the system's realloc below. This file does not define 35#ifndef _GL_INLINE_RPL_REALLOC
30 _GL_USE_STDLIB_ALLOC because it needs Gnulib's malloc if present. */
31#undef realloc
32 36
33/* Change the size of an allocated block of memory P to N bytes, 37/* Change the size of an allocated block of memory P to N bytes,
34 with error checking. If P is NULL, use malloc. Otherwise if N is zero, 38 with error checking. If P is NULL, use malloc. Otherwise if N is zero,
@@ -37,27 +41,70 @@
37void * 41void *
38rpl_realloc (void *p, size_t n) 42rpl_realloc (void *p, size_t n)
39{ 43{
40 if (p == NULL) 44 size_t n1 = n;
41 return malloc (n);
42 45
43 if (n == 0) 46 if (n == 0)
44 { 47 {
45 free (p); 48# if NEED_SANITIZED_REALLOC
46 return NULL; 49 /* When P is non-null, ISO C23 §7.24.3.7.(3) says realloc (P, 0) has
50 undefined behavior even though C17 and earlier partially defined
51 the behavior. Let the programmer know.
52 When the undefined-behaviour sanitizers report this case, i.e. when
53 <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117233> and
54 <https://github.com/llvm/llvm-project/issues/113065>
55 have been closed and new releases of GCC and clang have been made,
56 we can revisit this code. */
57 if (p != NULL)
58 abort ();
59# endif
60
61 /* realloc (NULL, 0) acts like glibc malloc (0), i.e., like malloc (1)
62 except the caller cannot dereference any non-null return.
63
64 realloc (P, 0) with non-null P is a messier situation.
65 As mentioned above, C23 says behavior is undefined.
66 POSIX.1-2024 extends C17 to say realloc (P, 0)
67 either fails by setting errno and returning a null pointer,
68 or succeeds by freeing P and then either:
69 (a) setting errno=EINVAL and returning a null pointer; or
70 (b) acting like a successful malloc (0).
71 glibc 1 through 2.1 realloc acted like (b),
72 which conforms to C17, to C23 and to POSIX.1-2024.
73 glibc 2.1.1+ realloc acts like (a) except it does not set errno;
74 this conforms to C17 and to C23 but not to POSIX.1-2024.
75 Quite possibly future versions of POSIX will change,
76 due either to C23 or to (a)'s semantics being messy.
77 Act like (b), as that's easy, matches GNU, BSD and V7 malloc,
78 matches BSD and V7 realloc, and requires no extra code at
79 caller sites. */
80
81# if !HAVE_REALLOC_0_NONNULL
82 n1 = 1;
83# endif
47 } 84 }
48 85
49 if (xalloc_oversized (n, 1)) 86# if !HAVE_MALLOC_PTRDIFF
87 ptrdiff_t signed_n;
88 if (ckd_add (&signed_n, n, 0))
50 { 89 {
51 errno = ENOMEM; 90 errno = ENOMEM;
52 return NULL; 91 return NULL;
53 } 92 }
93# endif
54 94
55 void *result = realloc (p, n); 95 void *result = realloc (p, n1);
56 96
57#if !HAVE_MALLOC_POSIX 97# if !HAVE_REALLOC_POSIX
58 if (result == NULL) 98 if (result == NULL)
59 errno = ENOMEM; 99 errno = ENOMEM;
60#endif 100# endif
101
102# ifdef __CHERI_PURE_CAPABILITY__
103 if (result != NULL)
104 result = cheri_bounds_set (result, n);
105# endif
61 106
62 return result; 107 return result;
63} 108}
109
110#endif
diff --git a/gl/reallocarray.c b/gl/reallocarray.c
index 09711a0e..77e8d84c 100644
--- a/gl/reallocarray.c
+++ b/gl/reallocarray.c
@@ -1,6 +1,6 @@
1/* reallocarray function that is glibc compatible. 1/* reallocarray function that is glibc compatible.
2 2
3 Copyright (C) 2017-2024 Free Software Foundation, Inc. 3 Copyright (C) 2017-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -33,6 +33,6 @@ reallocarray (void *ptr, size_t nmemb, size_t size)
33 return NULL; 33 return NULL;
34 } 34 }
35 35
36 /* Rely on the semantics of GNU realloc. */ 36 /* Call realloc, setting errno to ENOMEM on failure. */
37 return realloc (ptr, nbytes); 37 return realloc (ptr, nbytes);
38} 38}
diff --git a/gl/regcomp.c b/gl/regcomp.c
index 696cf813..878b65ba 100644
--- a/gl/regcomp.c
+++ b/gl/regcomp.c
@@ -1,5 +1,5 @@
1/* Extended regular expression matching and search library. 1/* Extended regular expression matching and search library.
2 Copyright (C) 2002-2024 Free Software Foundation, Inc. 2 Copyright (C) 2002-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. 4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
5 5
@@ -831,7 +831,7 @@ init_dfa (re_dfa_t *dfa, size_t pat_len)
831 if (table_size > pat_len) 831 if (table_size > pat_len)
832 break; 832 break;
833 833
834 dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size); 834 dfa->state_table = calloc (table_size, sizeof (struct re_state_table_entry));
835 dfa->state_hash_mask = table_size - 1; 835 dfa->state_hash_mask = table_size - 1;
836 836
837 dfa->mb_cur_max = MB_CUR_MAX; 837 dfa->mb_cur_max = MB_CUR_MAX;
@@ -862,7 +862,7 @@ init_dfa (re_dfa_t *dfa, size_t pat_len)
862 { 862 {
863 int i, j, ch; 863 int i, j, ch;
864 864
865 dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); 865 dfa->sb_char = (re_bitset_ptr_t) calloc (1, sizeof (bitset_t));
866 if (__glibc_unlikely (dfa->sb_char == NULL)) 866 if (__glibc_unlikely (dfa->sb_char == NULL))
867 return REG_ESPACE; 867 return REG_ESPACE;
868 868
@@ -1001,21 +1001,25 @@ create_initial_state (re_dfa_t *dfa)
1001 Idx dest_idx = dfa->edests[node_idx].elems[0]; 1001 Idx dest_idx = dfa->edests[node_idx].elems[0];
1002 if (!re_node_set_contains (&init_nodes, dest_idx)) 1002 if (!re_node_set_contains (&init_nodes, dest_idx))
1003 { 1003 {
1004 reg_errcode_t merge_err 1004 err
1005 = re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx); 1005 = re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx);
1006 if (merge_err != REG_NOERROR) 1006 if (err != REG_NOERROR)
1007 return merge_err; 1007 break;
1008 i = 0; 1008 i = 0;
1009 } 1009 }
1010 } 1010 }
1011 } 1011 }
1012 1012
1013 /* It must be the first time to invoke acquire_state. */ 1013 /* It must be the first time to invoke acquire_state. */
1014 dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0); 1014 dfa->init_state
1015 /* We don't check ERR here, since the initial state must not be NULL. */ 1015 = (err == REG_NOERROR
1016 ? re_acquire_state_context (&err, dfa, &init_nodes, 0)
1017 : NULL);
1016 if (__glibc_unlikely (dfa->init_state == NULL)) 1018 if (__glibc_unlikely (dfa->init_state == NULL))
1017 return err; 1019 {
1018 if (dfa->init_state->has_constraint) 1020 /* Don't check ERR here, as the initial state must not be null. */
1021 }
1022 else if (dfa->init_state->has_constraint)
1019 { 1023 {
1020 dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes, 1024 dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes,
1021 CONTEXT_WORD); 1025 CONTEXT_WORD);
@@ -1025,17 +1029,13 @@ create_initial_state (re_dfa_t *dfa)
1025 &init_nodes, 1029 &init_nodes,
1026 CONTEXT_NEWLINE 1030 CONTEXT_NEWLINE
1027 | CONTEXT_BEGBUF); 1031 | CONTEXT_BEGBUF);
1028 if (__glibc_unlikely (dfa->init_state_word == NULL
1029 || dfa->init_state_nl == NULL
1030 || dfa->init_state_begbuf == NULL))
1031 return err;
1032 } 1032 }
1033 else 1033 else
1034 dfa->init_state_word = dfa->init_state_nl 1034 dfa->init_state_word = dfa->init_state_nl
1035 = dfa->init_state_begbuf = dfa->init_state; 1035 = dfa->init_state_begbuf = dfa->init_state;
1036 1036
1037 re_node_set_free (&init_nodes); 1037 re_node_set_free (&init_nodes);
1038 return REG_NOERROR; 1038 return err;
1039} 1039}
1040 1040
1041/* If it is possible to do searching in single byte encoding instead of UTF-8 1041/* If it is possible to do searching in single byte encoding instead of UTF-8
@@ -1677,12 +1677,11 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
1677 { 1677 {
1678 err = duplicate_node_closure (dfa, node, node, node, 1678 err = duplicate_node_closure (dfa, node, node, node,
1679 dfa->nodes[node].constraint); 1679 dfa->nodes[node].constraint);
1680 if (__glibc_unlikely (err != REG_NOERROR))
1681 return err;
1682 } 1680 }
1683 1681
1684 /* Expand each epsilon destination nodes. */ 1682 /* Expand each epsilon destination nodes. */
1685 if (IS_EPSILON_NODE(dfa->nodes[node].type)) 1683 if (__glibc_likely (err == REG_NOERROR)
1684 && IS_EPSILON_NODE (dfa->nodes[node].type))
1686 for (i = 0; i < dfa->edests[node].nelem; ++i) 1685 for (i = 0; i < dfa->edests[node].nelem; ++i)
1687 { 1686 {
1688 re_node_set eclosure_elem; 1687 re_node_set eclosure_elem;
@@ -1700,14 +1699,14 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
1700 { 1699 {
1701 err = calc_eclosure_iter (&eclosure_elem, dfa, edest, false); 1700 err = calc_eclosure_iter (&eclosure_elem, dfa, edest, false);
1702 if (__glibc_unlikely (err != REG_NOERROR)) 1701 if (__glibc_unlikely (err != REG_NOERROR))
1703 return err; 1702 break;
1704 } 1703 }
1705 else 1704 else
1706 eclosure_elem = dfa->eclosures[edest]; 1705 eclosure_elem = dfa->eclosures[edest];
1707 /* Merge the epsilon closure of 'edest'. */ 1706 /* Merge the epsilon closure of 'edest'. */
1708 err = re_node_set_merge (&eclosure, &eclosure_elem); 1707 err = re_node_set_merge (&eclosure, &eclosure_elem);
1709 if (__glibc_unlikely (err != REG_NOERROR)) 1708 if (__glibc_unlikely (err != REG_NOERROR))
1710 return err; 1709 break;
1711 /* If the epsilon closure of 'edest' is incomplete, 1710 /* If the epsilon closure of 'edest' is incomplete,
1712 the epsilon closure of this node is also incomplete. */ 1711 the epsilon closure of this node is also incomplete. */
1713 if (dfa->eclosures[edest].nelem == 0) 1712 if (dfa->eclosures[edest].nelem == 0)
@@ -1717,12 +1716,18 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
1717 } 1716 }
1718 } 1717 }
1719 1718
1720 if (incomplete && !root) 1719 if (err != REG_NOERROR)
1721 dfa->eclosures[node].nelem = 0; 1720 re_node_set_free (&eclosure);
1722 else 1721 else
1723 dfa->eclosures[node] = eclosure; 1722 {
1724 *new_set = eclosure; 1723 if (incomplete && !root)
1725 return REG_NOERROR; 1724 dfa->eclosures[node].nelem = 0;
1725 else
1726 dfa->eclosures[node] = eclosure;
1727 *new_set = eclosure;
1728 }
1729
1730 return err;
1726} 1731}
1727 1732
1728/* Functions for token which are used in the parser. */ 1733/* Functions for token which are used in the parser. */
@@ -3055,8 +3060,8 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
3055 _NL_COLLATE_SYMB_EXTRAMB); 3060 _NL_COLLATE_SYMB_EXTRAMB);
3056 } 3061 }
3057#endif 3062#endif
3058 sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); 3063 sbcset = (re_bitset_ptr_t) calloc (1, sizeof (bitset_t));
3059 mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); 3064 mbcset = (re_charset_t *) calloc (1, sizeof (re_charset_t));
3060 if (__glibc_unlikely (sbcset == NULL || mbcset == NULL)) 3065 if (__glibc_unlikely (sbcset == NULL || mbcset == NULL))
3061 { 3066 {
3062 re_free (sbcset); 3067 re_free (sbcset);
@@ -3275,6 +3280,7 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
3275 else 3280 else
3276 { 3281 {
3277 free_charset (mbcset); 3282 free_charset (mbcset);
3283 mbcset = NULL;
3278 /* Build a tree for simple bracket. */ 3284 /* Build a tree for simple bracket. */
3279 br_token.type = SIMPLE_BRACKET; 3285 br_token.type = SIMPLE_BRACKET;
3280 br_token.opr.sbcset = sbcset; 3286 br_token.opr.sbcset = sbcset;
@@ -3288,7 +3294,8 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
3288 *err = REG_ESPACE; 3294 *err = REG_ESPACE;
3289 parse_bracket_exp_free_return: 3295 parse_bracket_exp_free_return:
3290 re_free (sbcset); 3296 re_free (sbcset);
3291 free_charset (mbcset); 3297 if (__glibc_likely (mbcset != NULL))
3298 free_charset (mbcset);
3292 return NULL; 3299 return NULL;
3293} 3300}
3294 3301
@@ -3548,13 +3555,13 @@ build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans,
3548 reg_errcode_t ret; 3555 reg_errcode_t ret;
3549 bin_tree_t *tree; 3556 bin_tree_t *tree;
3550 3557
3551 sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); 3558 sbcset = (re_bitset_ptr_t) calloc (1, sizeof (bitset_t));
3552 if (__glibc_unlikely (sbcset == NULL)) 3559 if (__glibc_unlikely (sbcset == NULL))
3553 { 3560 {
3554 *err = REG_ESPACE; 3561 *err = REG_ESPACE;
3555 return NULL; 3562 return NULL;
3556 } 3563 }
3557 mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); 3564 mbcset = (re_charset_t *) calloc (1, sizeof (re_charset_t));
3558 if (__glibc_unlikely (mbcset == NULL)) 3565 if (__glibc_unlikely (mbcset == NULL))
3559 { 3566 {
3560 re_free (sbcset); 3567 re_free (sbcset);
diff --git a/gl/regex.c b/gl/regex.c
index 4b1a6ed6..f5f65526 100644
--- a/gl/regex.c
+++ b/gl/regex.c
@@ -1,5 +1,5 @@
1/* Extended regular expression matching and search library. 1/* Extended regular expression matching and search library.
2 Copyright (C) 2002-2024 Free Software Foundation, Inc. 2 Copyright (C) 2002-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. 4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
5 5
diff --git a/gl/regex.h b/gl/regex.h
index ccf40ceb..e9ab85e8 100644
--- a/gl/regex.h
+++ b/gl/regex.h
@@ -1,6 +1,6 @@
1/* Definitions for data structures and routines for the regular 1/* Definitions for data structures and routines for the regular
2 expression library. 2 expression library.
3 Copyright (C) 1985, 1989-2024 Free Software Foundation, Inc. 3 Copyright (C) 1985, 1989-2025 Free Software Foundation, Inc.
4 This file is part of the GNU C Library. 4 This file is part of the GNU C Library.
5 5
6 The GNU C Library is free software; you can redistribute it and/or 6 The GNU C Library is free software; you can redistribute it and/or
@@ -66,15 +66,14 @@ typedef unsigned long int active_reg_t;
66 66
67/* The following bits are used to determine the regexp syntax we 67/* The following bits are used to determine the regexp syntax we
68 recognize. The set/not-set meanings are chosen so that Emacs syntax 68 recognize. The set/not-set meanings are chosen so that Emacs syntax
69 remains the value 0. The bits are given in alphabetical order, and 69 is the value 0 for Emacs 20 (2000) and earlier, and the value
70 the definitions shifted by one from the previous bit; thus, when we 70 RE_SYNTAX_EMACS for Emacs 21 (2001) and later. */
71 add or remove a bit, only one other definition need change. */
72typedef unsigned long int reg_syntax_t; 71typedef unsigned long int reg_syntax_t;
73 72
74#ifdef __USE_GNU 73#ifdef __USE_GNU
75/* If this bit is not set, then \ inside a bracket expression is literal. 74/* If this bit is not set, then \ inside a bracket expression is literal.
76 If set, then such a \ quotes the following character. */ 75 If set, then such a \ quotes the following character. */
77# define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) 76# define RE_BACKSLASH_ESCAPE_IN_LISTS 1ul
78 77
79/* If this bit is not set, then + and ? are operators, and \+ and \? are 78/* If this bit is not set, then + and ? are operators, and \+ and \? are
80 literals. 79 literals.
@@ -215,7 +214,8 @@ extern reg_syntax_t re_syntax_options;
215 (The [[[ comments delimit what gets put into the Texinfo file, so 214 (The [[[ comments delimit what gets put into the Texinfo file, so
216 don't delete them!) */ 215 don't delete them!) */
217/* [[[begin syntaxes]]] */ 216/* [[[begin syntaxes]]] */
218# define RE_SYNTAX_EMACS 0 217# define RE_SYNTAX_EMACS \
218 (RE_CHAR_CLASSES | RE_INTERVALS)
219 219
220# define RE_SYNTAX_AWK \ 220# define RE_SYNTAX_AWK \
221 (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ 221 (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
@@ -522,20 +522,6 @@ typedef struct
522 522
523/* Declarations for routines. */ 523/* Declarations for routines. */
524 524
525#ifndef _REGEX_NELTS
526# if (defined __STDC_VERSION__ && 199901L <= __STDC_VERSION__ \
527 && !defined __STDC_NO_VLA__)
528# define _REGEX_NELTS(n) n
529# else
530# define _REGEX_NELTS(n)
531# endif
532#endif
533
534#if defined __GNUC__ && 4 < __GNUC__ + (6 <= __GNUC_MINOR__)
535# pragma GCC diagnostic push
536# pragma GCC diagnostic ignored "-Wvla"
537#endif
538
539#ifndef _Attr_access_ 525#ifndef _Attr_access_
540# ifdef __attr_access 526# ifdef __attr_access
541# define _Attr_access_(arg) __attr_access (arg) 527# define _Attr_access_(arg) __attr_access (arg)
@@ -647,10 +633,12 @@ extern int re_exec (const char *);
647 || 2 < __GNUC__ + (95 <= __GNUC_MINOR__) \ 633 || 2 < __GNUC__ + (95 <= __GNUC_MINOR__) \
648 || __clang_major__ >= 3 634 || __clang_major__ >= 3
649# define _Restrict_ __restrict 635# define _Restrict_ __restrict
650# elif 199901L <= __STDC_VERSION__ || defined restrict
651# define _Restrict_ restrict
652# else 636# else
653# define _Restrict_ 637# if 199901L <= __STDC_VERSION__ || defined restrict
638# define _Restrict_ restrict
639# else
640# define _Restrict_
641# endif
654# endif 642# endif
655#endif 643#endif
656/* For the ISO C99 syntax 644/* For the ISO C99 syntax
@@ -661,13 +649,15 @@ extern int re_exec (const char *);
661#ifndef _Restrict_arr_ 649#ifndef _Restrict_arr_
662# ifdef __restrict_arr 650# ifdef __restrict_arr
663# define _Restrict_arr_ __restrict_arr 651# define _Restrict_arr_ __restrict_arr
664# elif ((199901L <= __STDC_VERSION__ \ 652# else
653# if ((199901L <= __STDC_VERSION__ \
665 || 3 < __GNUC__ + (1 <= __GNUC_MINOR__) \ 654 || 3 < __GNUC__ + (1 <= __GNUC_MINOR__) \
666 || __clang_major__ >= 3) \ 655 || __clang_major__ >= 3) \
667 && !defined __cplusplus) 656 && !defined __cplusplus)
668# define _Restrict_arr_ _Restrict_ 657# define _Restrict_arr_ _Restrict_
669# else 658# else
670# define _Restrict_arr_ 659# define _Restrict_arr_
660# endif
671# endif 661# endif
672#endif 662#endif
673 663
@@ -678,8 +668,7 @@ extern int regcomp (regex_t *_Restrict_ __preg,
678 668
679extern int regexec (const regex_t *_Restrict_ __preg, 669extern int regexec (const regex_t *_Restrict_ __preg,
680 const char *_Restrict_ __String, size_t __nmatch, 670 const char *_Restrict_ __String, size_t __nmatch,
681 regmatch_t __pmatch[_Restrict_arr_ 671 regmatch_t __pmatch[_Restrict_arr_],
682 _REGEX_NELTS (__nmatch)],
683 int __eflags); 672 int __eflags);
684 673
685extern size_t regerror (int __errcode, const regex_t *_Restrict_ __preg, 674extern size_t regerror (int __errcode, const regex_t *_Restrict_ __preg,
@@ -688,10 +677,6 @@ extern size_t regerror (int __errcode, const regex_t *_Restrict_ __preg,
688 677
689extern void regfree (regex_t *__preg); 678extern void regfree (regex_t *__preg);
690 679
691#if defined __GNUC__ && 4 < __GNUC__ + (6 <= __GNUC_MINOR__)
692# pragma GCC diagnostic pop
693#endif
694
695#ifdef __cplusplus 680#ifdef __cplusplus
696} 681}
697#endif /* C++ */ 682#endif /* C++ */
diff --git a/gl/regex_internal.c b/gl/regex_internal.c
index 8cd096eb..9b89cc93 100644
--- a/gl/regex_internal.c
+++ b/gl/regex_internal.c
@@ -1,5 +1,5 @@
1/* Extended regular expression matching and search library. 1/* Extended regular expression matching and search library.
2 Copyright (C) 2002-2024 Free Software Foundation, Inc. 2 Copyright (C) 2002-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. 4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
5 5
@@ -937,8 +937,7 @@ re_node_set_alloc (re_node_set *set, Idx size)
937 set->alloc = size; 937 set->alloc = size;
938 set->nelem = 0; 938 set->nelem = 0;
939 set->elems = re_malloc (Idx, size); 939 set->elems = re_malloc (Idx, size);
940 if (__glibc_unlikely (set->elems == NULL) 940 if (__glibc_unlikely (set->elems == NULL))
941 && (MALLOC_0_IS_NONNULL || size != 0))
942 return REG_ESPACE; 941 return REG_ESPACE;
943 return REG_NOERROR; 942 return REG_NOERROR;
944} 943}
@@ -1596,7 +1595,7 @@ create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
1596 reg_errcode_t err; 1595 reg_errcode_t err;
1597 re_dfastate_t *newstate; 1596 re_dfastate_t *newstate;
1598 1597
1599 newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); 1598 newstate = (re_dfastate_t *) calloc (1, sizeof (re_dfastate_t));
1600 if (__glibc_unlikely (newstate == NULL)) 1599 if (__glibc_unlikely (newstate == NULL))
1601 return NULL; 1600 return NULL;
1602 err = re_node_set_init_copy (&newstate->nodes, nodes); 1601 err = re_node_set_init_copy (&newstate->nodes, nodes);
@@ -1644,7 +1643,7 @@ create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
1644 reg_errcode_t err; 1643 reg_errcode_t err;
1645 re_dfastate_t *newstate; 1644 re_dfastate_t *newstate;
1646 1645
1647 newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); 1646 newstate = (re_dfastate_t *) calloc (1, sizeof (re_dfastate_t));
1648 if (__glibc_unlikely (newstate == NULL)) 1647 if (__glibc_unlikely (newstate == NULL))
1649 return NULL; 1648 return NULL;
1650 err = re_node_set_init_copy (&newstate->nodes, nodes); 1649 err = re_node_set_init_copy (&newstate->nodes, nodes);
diff --git a/gl/regex_internal.h b/gl/regex_internal.h
index 6165cb17..1f297299 100644
--- a/gl/regex_internal.h
+++ b/gl/regex_internal.h
@@ -1,5 +1,5 @@
1/* Extended regular expression matching and search library. 1/* Extended regular expression matching and search library.
2 Copyright (C) 2002-2024 Free Software Foundation, Inc. 2 Copyright (C) 2002-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. 4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
5 5
@@ -100,10 +100,12 @@
100/* This is for other GNU distributions with internationalized messages. */ 100/* This is for other GNU distributions with internationalized messages. */
101#if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC 101#if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC
102# include <libintl.h> 102# include <libintl.h>
103# undef gettext
103# ifdef _LIBC 104# ifdef _LIBC
104# undef gettext
105# define gettext(msgid) \ 105# define gettext(msgid) \
106 __dcgettext (_libc_intl_domainname, msgid, LC_MESSAGES) 106 __dcgettext (_libc_intl_domainname, msgid, LC_MESSAGES)
107# else
108# define gettext(msgid) dgettext ("gnulib", msgid)
107# endif 109# endif
108#else 110#else
109# undef gettext 111# undef gettext
@@ -436,12 +438,6 @@ typedef struct re_dfa_t re_dfa_t;
436#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx)) 438#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx))
437#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx)) 439#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx))
438 440
439#ifdef _LIBC
440# define MALLOC_0_IS_NONNULL 1
441#elif !defined MALLOC_0_IS_NONNULL
442# define MALLOC_0_IS_NONNULL 0
443#endif
444
445#ifndef MAX 441#ifndef MAX
446# define MAX(a,b) ((a) < (b) ? (b) : (a)) 442# define MAX(a,b) ((a) < (b) ? (b) : (a))
447#endif 443#endif
diff --git a/gl/regexec.c b/gl/regexec.c
index 9f065dfa..0d14ac35 100644
--- a/gl/regexec.c
+++ b/gl/regexec.c
@@ -1,5 +1,5 @@
1/* Extended regular expression matching and search library. 1/* Extended regular expression matching and search library.
2 Copyright (C) 2002-2024 Free Software Foundation, Inc. 2 Copyright (C) 2002-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. 4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
5 5
@@ -185,7 +185,7 @@ static reg_errcode_t extend_buffers (re_match_context_t *mctx, int min_len);
185 185
186int 186int
187regexec (const regex_t *__restrict preg, const char *__restrict string, 187regexec (const regex_t *__restrict preg, const char *__restrict string,
188 size_t nmatch, regmatch_t pmatch[_REGEX_NELTS (nmatch)], int eflags) 188 size_t nmatch, regmatch_t pmatch[], int eflags)
189{ 189{
190 reg_errcode_t err; 190 reg_errcode_t err;
191 Idx start, length; 191 Idx start, length;
@@ -229,7 +229,7 @@ int
229attribute_compat_text_section 229attribute_compat_text_section
230__compat_regexec (const regex_t *__restrict preg, 230__compat_regexec (const regex_t *__restrict preg,
231 const char *__restrict string, size_t nmatch, 231 const char *__restrict string, size_t nmatch,
232 regmatch_t pmatch[_REGEX_NELTS (nmatch)], int eflags) 232 regmatch_t pmatch[], int eflags)
233{ 233{
234 return regexec (preg, string, nmatch, pmatch, 234 return regexec (preg, string, nmatch, pmatch,
235 eflags & (REG_NOTBOL | REG_NOTEOL)); 235 eflags & (REG_NOTBOL | REG_NOTEOL));
@@ -2271,7 +2271,7 @@ merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx,
2271 these destinations and the results of the transition table. */ 2271 these destinations and the results of the transition table. */
2272 pstate = mctx->state_log[cur_idx]; 2272 pstate = mctx->state_log[cur_idx];
2273 log_nodes = pstate->entrance_nodes; 2273 log_nodes = pstate->entrance_nodes;
2274 if (next_state != NULL) 2274 if (next_state != NULL && next_state->entrance_nodes != NULL)
2275 { 2275 {
2276 table_nodes = next_state->entrance_nodes; 2276 table_nodes = next_state->entrance_nodes;
2277 *err = re_node_set_init_union (&next_nodes, table_nodes, 2277 *err = re_node_set_init_union (&next_nodes, table_nodes,
@@ -2721,8 +2721,8 @@ get_subexp (re_match_context_t *mctx, Idx bkref_node, Idx bkref_str_idx)
2721 continue; /* No. */ 2721 continue; /* No. */
2722 if (sub_top->path == NULL) 2722 if (sub_top->path == NULL)
2723 { 2723 {
2724 sub_top->path = calloc (sizeof (state_array_t), 2724 sub_top->path = calloc (sl_str - sub_top->str_idx + 1,
2725 sl_str - sub_top->str_idx + 1); 2725 sizeof (state_array_t));
2726 if (sub_top->path == NULL) 2726 if (sub_top->path == NULL)
2727 return REG_ESPACE; 2727 return REG_ESPACE;
2728 } 2728 }
@@ -3266,7 +3266,7 @@ build_trtable (const re_dfa_t *dfa, re_dfastate_t *state)
3266 if (ndests == 0) 3266 if (ndests == 0)
3267 { 3267 {
3268 state->trtable = (re_dfastate_t **) 3268 state->trtable = (re_dfastate_t **)
3269 calloc (sizeof (re_dfastate_t *), SBC_MAX); 3269 calloc (SBC_MAX, sizeof (re_dfastate_t *));
3270 if (__glibc_unlikely (state->trtable == NULL)) 3270 if (__glibc_unlikely (state->trtable == NULL))
3271 return false; 3271 return false;
3272 return true; 3272 return true;
@@ -3338,7 +3338,7 @@ build_trtable (const re_dfa_t *dfa, re_dfastate_t *state)
3338 discern by looking at the character code: allocate a 3338 discern by looking at the character code: allocate a
3339 256-entry transition table. */ 3339 256-entry transition table. */
3340 trtable = state->trtable = 3340 trtable = state->trtable =
3341 (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); 3341 (re_dfastate_t **) calloc (SBC_MAX, sizeof (re_dfastate_t *));
3342 if (__glibc_unlikely (trtable == NULL)) 3342 if (__glibc_unlikely (trtable == NULL))
3343 goto out_free; 3343 goto out_free;
3344 3344
@@ -3369,7 +3369,7 @@ build_trtable (const re_dfa_t *dfa, re_dfastate_t *state)
3369 transition tables, one starting at trtable[0] and one 3369 transition tables, one starting at trtable[0] and one
3370 starting at trtable[SBC_MAX]. */ 3370 starting at trtable[SBC_MAX]. */
3371 trtable = state->word_trtable = 3371 trtable = state->word_trtable =
3372 (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX); 3372 (re_dfastate_t **) calloc (2 * SBC_MAX, sizeof (re_dfastate_t *));
3373 if (__glibc_unlikely (trtable == NULL)) 3373 if (__glibc_unlikely (trtable == NULL))
3374 goto out_free; 3374 goto out_free;
3375 3375
diff --git a/gl/sched.h b/gl/sched.h
new file mode 100644
index 00000000..4d9d546d
--- /dev/null
+++ b/gl/sched.h
@@ -0,0 +1,631 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* A GNU-like <sched.h>.
3 Copyright (C) 2008-2025 Free Software Foundation, Inc.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#ifndef _GL_SCHED_H
19
20#if __GNUC__ >= 3
21#pragma GCC system_header
22#endif
23
24
25/* This file uses #include_next of a system file that defines time_t.
26 For the 'year2038' module to work right, <config.h> needs to have been
27 included before. */
28#if !_GL_CONFIG_H_INCLUDED
29 #error "Please include config.h first."
30#endif
31
32/* The include_next requires a split double-inclusion guard. */
33#if 1
34# if 1
35# include <sys/cdefs.h>
36# endif
37# include_next <sched.h>
38#endif
39
40#ifndef _GL_SCHED_H
41#define _GL_SCHED_H
42
43/* This file uses GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
44#if !_GL_CONFIG_H_INCLUDED
45 #error "Please include config.h first."
46#endif
47
48/* Get pid_t.
49 This is needed on glibc 2.11 (see
50 glibc bug <https://sourceware.org/PR13198>)
51 and Mac OS X 10.5. */
52#include <sys/types.h>
53
54#ifdef __KLIBC__
55/* On OS/2 kLIBC, struct sched_param is in spawn.h. */
56# include <spawn.h>
57#endif
58
59#ifdef __VMS
60/* On OpenVMS, struct sched_param is in <pthread.h>. */
61# include <pthread.h>
62#endif
63
64/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
65/* C++ compatible function declaration macros.
66 Copyright (C) 2010-2025 Free Software Foundation, Inc.
67
68 This program is free software: you can redistribute it and/or modify it
69 under the terms of the GNU Lesser General Public License as published
70 by the Free Software Foundation; either version 2 of the License, or
71 (at your option) any later version.
72
73 This program is distributed in the hope that it will be useful,
74 but WITHOUT ANY WARRANTY; without even the implied warranty of
75 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
76 Lesser General Public License for more details.
77
78 You should have received a copy of the GNU Lesser General Public License
79 along with this program. If not, see <https://www.gnu.org/licenses/>. */
80
81#ifndef _GL_CXXDEFS_H
82#define _GL_CXXDEFS_H
83
84/* Begin/end the GNULIB_NAMESPACE namespace. */
85#if defined __cplusplus && defined GNULIB_NAMESPACE
86# define _GL_BEGIN_NAMESPACE namespace GNULIB_NAMESPACE {
87# define _GL_END_NAMESPACE }
88#else
89# define _GL_BEGIN_NAMESPACE
90# define _GL_END_NAMESPACE
91#endif
92
93/* The three most frequent use cases of these macros are:
94
95 * For providing a substitute for a function that is missing on some
96 platforms, but is declared and works fine on the platforms on which
97 it exists:
98
99 #if @GNULIB_FOO@
100 # if !@HAVE_FOO@
101 _GL_FUNCDECL_SYS (foo, ...);
102 # endif
103 _GL_CXXALIAS_SYS (foo, ...);
104 _GL_CXXALIASWARN (foo);
105 #elif defined GNULIB_POSIXCHECK
106 ...
107 #endif
108
109 * For providing a replacement for a function that exists on all platforms,
110 but is broken/insufficient and needs to be replaced on some platforms:
111
112 #if @GNULIB_FOO@
113 # if @REPLACE_FOO@
114 # if !(defined __cplusplus && defined GNULIB_NAMESPACE)
115 # undef foo
116 # define foo rpl_foo
117 # endif
118 _GL_FUNCDECL_RPL (foo, ...);
119 _GL_CXXALIAS_RPL (foo, ...);
120 # else
121 _GL_CXXALIAS_SYS (foo, ...);
122 # endif
123 _GL_CXXALIASWARN (foo);
124 #elif defined GNULIB_POSIXCHECK
125 ...
126 #endif
127
128 * For providing a replacement for a function that exists on some platforms
129 but is broken/insufficient and needs to be replaced on some of them and
130 is additionally either missing or undeclared on some other platforms:
131
132 #if @GNULIB_FOO@
133 # if @REPLACE_FOO@
134 # if !(defined __cplusplus && defined GNULIB_NAMESPACE)
135 # undef foo
136 # define foo rpl_foo
137 # endif
138 _GL_FUNCDECL_RPL (foo, ...);
139 _GL_CXXALIAS_RPL (foo, ...);
140 # else
141 # if !@HAVE_FOO@ or if !@HAVE_DECL_FOO@
142 _GL_FUNCDECL_SYS (foo, ...);
143 # endif
144 _GL_CXXALIAS_SYS (foo, ...);
145 # endif
146 _GL_CXXALIASWARN (foo);
147 #elif defined GNULIB_POSIXCHECK
148 ...
149 #endif
150*/
151
152/* _GL_EXTERN_C declaration;
153 performs the declaration with C linkage. */
154#if defined __cplusplus
155# define _GL_EXTERN_C extern "C"
156#else
157# define _GL_EXTERN_C extern
158#endif
159
160/* _GL_EXTERN_C_FUNC declaration;
161 performs the declaration of a function with C linkage. */
162#if defined __cplusplus
163# define _GL_EXTERN_C_FUNC extern "C"
164#else
165/* In C mode, omit the 'extern' keyword, because attributes in bracket syntax
166 are not allowed between 'extern' and the return type (see gnulib-common.m4).
167 */
168# define _GL_EXTERN_C_FUNC
169#endif
170
171/* _GL_FUNCDECL_RPL (func, rettype, parameters, [attributes]);
172 declares a replacement function, named rpl_func, with the given prototype,
173 consisting of return type, parameters, and attributes.
174 Although attributes are optional, the comma before them is required
175 for portability to C17 and earlier. The attribute _GL_ATTRIBUTE_NOTHROW,
176 if needed, must be placed after the _GL_FUNCDECL_RPL invocation,
177 at the end of the declaration.
178 Examples:
179 _GL_FUNCDECL_RPL (free, void, (void *ptr), ) _GL_ATTRIBUTE_NOTHROW;
180 _GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...),
181 _GL_ARG_NONNULL ((1)));
182
183 Note: Attributes, such as _GL_ATTRIBUTE_DEPRECATED, are supported in front
184 of a _GL_FUNCDECL_RPL invocation only in C mode, not in C++ mode. (That's
185 because
186 [[...]] extern "C" <declaration>;
187 is invalid syntax in C++.)
188 */
189#define _GL_FUNCDECL_RPL(func,rettype,parameters,...) \
190 _GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters, __VA_ARGS__)
191#define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters,...) \
192 _GL_EXTERN_C_FUNC __VA_ARGS__ rettype rpl_func parameters
193
194/* _GL_FUNCDECL_SYS_NAME (func) expands to plain func if C++, and to
195 parenthesized func otherwise. Parenthesization is needed in C23 if
196 the function is like strchr and so is a qualifier-generic macro
197 that expands to something more complicated. */
198#ifdef __cplusplus
199# define _GL_FUNCDECL_SYS_NAME(func) func
200#else
201# define _GL_FUNCDECL_SYS_NAME(func) (func)
202#endif
203
204/* _GL_FUNCDECL_SYS (func, rettype, parameters, [attributes]);
205 declares the system function, named func, with the given prototype,
206 consisting of return type, parameters, and attributes.
207 Although attributes are optional, the comma before them is required
208 for portability to C17 and earlier. The attribute _GL_ATTRIBUTE_NOTHROW,
209 if needed, must be placed after the _GL_FUNCDECL_RPL invocation,
210 at the end of the declaration.
211 Examples:
212 _GL_FUNCDECL_SYS (getumask, mode_t, (void), ) _GL_ATTRIBUTE_NOTHROW;
213 _GL_FUNCDECL_SYS (posix_openpt, int, (int flags), _GL_ATTRIBUTE_NODISCARD);
214 */
215#define _GL_FUNCDECL_SYS(func,rettype,parameters,...) \
216 _GL_EXTERN_C_FUNC __VA_ARGS__ rettype _GL_FUNCDECL_SYS_NAME (func) parameters
217
218/* _GL_CXXALIAS_RPL (func, rettype, parameters);
219 declares a C++ alias called GNULIB_NAMESPACE::func
220 that redirects to rpl_func, if GNULIB_NAMESPACE is defined.
221 Example:
222 _GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...));
223
224 Wrapping rpl_func in an object with an inline conversion operator
225 avoids a reference to rpl_func unless GNULIB_NAMESPACE::func is
226 actually used in the program. */
227#define _GL_CXXALIAS_RPL(func,rettype,parameters) \
228 _GL_CXXALIAS_RPL_1 (func, rpl_##func, rettype, parameters)
229#if defined __cplusplus && defined GNULIB_NAMESPACE
230# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
231 namespace GNULIB_NAMESPACE \
232 { \
233 static const struct _gl_ ## func ## _wrapper \
234 { \
235 typedef rettype (*type) parameters; \
236 \
237 inline operator type () const \
238 { \
239 return ::rpl_func; \
240 } \
241 } func = {}; \
242 } \
243 _GL_EXTERN_C int _gl_cxxalias_dummy
244#else
245# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
246 _GL_EXTERN_C int _gl_cxxalias_dummy
247#endif
248
249/* _GL_CXXALIAS_MDA (func, rettype, parameters);
250 is to be used when func is a Microsoft deprecated alias, on native Windows.
251 It declares a C++ alias called GNULIB_NAMESPACE::func
252 that redirects to _func, if GNULIB_NAMESPACE is defined.
253 Example:
254 _GL_CXXALIAS_MDA (open, int, (const char *filename, int flags, ...));
255 */
256#define _GL_CXXALIAS_MDA(func,rettype,parameters) \
257 _GL_CXXALIAS_RPL_1 (func, _##func, rettype, parameters)
258
259/* _GL_CXXALIAS_RPL_CAST_1 (func, rpl_func, rettype, parameters);
260 is like _GL_CXXALIAS_RPL_1 (func, rpl_func, rettype, parameters);
261 except that the C function rpl_func may have a slightly different
262 declaration. A cast is used to silence the "invalid conversion" error
263 that would otherwise occur. */
264#if defined __cplusplus && defined GNULIB_NAMESPACE
265# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \
266 namespace GNULIB_NAMESPACE \
267 { \
268 static const struct _gl_ ## func ## _wrapper \
269 { \
270 typedef rettype (*type) parameters; \
271 \
272 inline operator type () const \
273 { \
274 return reinterpret_cast<type>(::rpl_func); \
275 } \
276 } func = {}; \
277 } \
278 _GL_EXTERN_C int _gl_cxxalias_dummy
279#else
280# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \
281 _GL_EXTERN_C int _gl_cxxalias_dummy
282#endif
283
284/* _GL_CXXALIAS_MDA_CAST (func, rettype, parameters);
285 is like _GL_CXXALIAS_MDA (func, rettype, parameters);
286 except that the C function func may have a slightly different declaration.
287 A cast is used to silence the "invalid conversion" error that would
288 otherwise occur. */
289#define _GL_CXXALIAS_MDA_CAST(func,rettype,parameters) \
290 _GL_CXXALIAS_RPL_CAST_1 (func, _##func, rettype, parameters)
291
292/* _GL_CXXALIAS_SYS (func, rettype, parameters);
293 declares a C++ alias called GNULIB_NAMESPACE::func
294 that redirects to the system provided function func, if GNULIB_NAMESPACE
295 is defined.
296 Example:
297 _GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...));
298
299 Wrapping func in an object with an inline conversion operator
300 avoids a reference to func unless GNULIB_NAMESPACE::func is
301 actually used in the program. */
302#if defined __cplusplus && defined GNULIB_NAMESPACE
303# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
304 namespace GNULIB_NAMESPACE \
305 { \
306 static const struct _gl_ ## func ## _wrapper \
307 { \
308 typedef rettype (*type) parameters; \
309 \
310 inline operator type () const \
311 { \
312 return ::func; \
313 } \
314 } func = {}; \
315 } \
316 _GL_EXTERN_C int _gl_cxxalias_dummy
317#else
318# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
319 _GL_EXTERN_C int _gl_cxxalias_dummy
320#endif
321
322/* _GL_CXXALIAS_SYS_CAST (func, rettype, parameters);
323 is like _GL_CXXALIAS_SYS (func, rettype, parameters);
324 except that the C function func may have a slightly different declaration.
325 A cast is used to silence the "invalid conversion" error that would
326 otherwise occur. */
327#if defined __cplusplus && defined GNULIB_NAMESPACE
328# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \
329 namespace GNULIB_NAMESPACE \
330 { \
331 static const struct _gl_ ## func ## _wrapper \
332 { \
333 typedef rettype (*type) parameters; \
334 \
335 inline operator type () const \
336 { \
337 return reinterpret_cast<type>(::func); \
338 } \
339 } func = {}; \
340 } \
341 _GL_EXTERN_C int _gl_cxxalias_dummy
342#else
343# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \
344 _GL_EXTERN_C int _gl_cxxalias_dummy
345#endif
346
347/* _GL_CXXALIAS_SYS_CAST2 (func, rettype, parameters, rettype2, parameters2);
348 is like _GL_CXXALIAS_SYS (func, rettype, parameters);
349 except that the C function is picked among a set of overloaded functions,
350 namely the one with rettype2 and parameters2. Two consecutive casts
351 are used to silence the "cannot find a match" and "invalid conversion"
352 errors that would otherwise occur. */
353#if defined __cplusplus && defined GNULIB_NAMESPACE
354 /* The outer cast must be a reinterpret_cast.
355 The inner cast: When the function is defined as a set of overloaded
356 functions, it works as a static_cast<>, choosing the designated variant.
357 When the function is defined as a single variant, it works as a
358 reinterpret_cast<>. The parenthesized cast syntax works both ways. */
359# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \
360 namespace GNULIB_NAMESPACE \
361 { \
362 static const struct _gl_ ## func ## _wrapper \
363 { \
364 typedef rettype (*type) parameters; \
365 \
366 inline operator type () const \
367 { \
368 return reinterpret_cast<type>((rettype2 (*) parameters2)(::func)); \
369 } \
370 } func = {}; \
371 } \
372 _GL_EXTERN_C int _gl_cxxalias_dummy
373#else
374# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \
375 _GL_EXTERN_C int _gl_cxxalias_dummy
376#endif
377
378/* _GL_CXXALIASWARN (func);
379 causes a warning to be emitted when ::func is used but not when
380 GNULIB_NAMESPACE::func is used. func must be defined without overloaded
381 variants. */
382#if defined __cplusplus && defined GNULIB_NAMESPACE
383# define _GL_CXXALIASWARN(func) \
384 _GL_CXXALIASWARN_1 (func, GNULIB_NAMESPACE)
385# define _GL_CXXALIASWARN_1(func,namespace) \
386 _GL_CXXALIASWARN_2 (func, namespace)
387/* To work around GCC bug <https://gcc.gnu.org/PR43881>,
388 we enable the warning only when not optimizing. */
389# if !(defined __GNUC__ && !defined __clang__ && __OPTIMIZE__)
390# define _GL_CXXALIASWARN_2(func,namespace) \
391 _GL_WARN_ON_USE (func, \
392 "The symbol ::" #func " refers to the system function. " \
393 "Use " #namespace "::" #func " instead.")
394# elif (__GNUC__ >= 3 || defined __clang__) && GNULIB_STRICT_CHECKING
395# define _GL_CXXALIASWARN_2(func,namespace) \
396 extern __typeof__ (func) func
397# else
398# define _GL_CXXALIASWARN_2(func,namespace) \
399 _GL_EXTERN_C int _gl_cxxalias_dummy
400# endif
401#else
402# define _GL_CXXALIASWARN(func) \
403 _GL_EXTERN_C int _gl_cxxalias_dummy
404#endif
405
406/* _GL_CXXALIASWARN1 (func, rettype, parameters_and_attributes);
407 causes a warning to be emitted when the given overloaded variant of ::func
408 is used but not when GNULIB_NAMESPACE::func is used. */
409#if defined __cplusplus && defined GNULIB_NAMESPACE
410# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \
411 _GL_CXXALIASWARN1_1 (func, rettype, parameters_and_attributes, \
412 GNULIB_NAMESPACE)
413# define _GL_CXXALIASWARN1_1(func,rettype,parameters_and_attributes,namespace) \
414 _GL_CXXALIASWARN1_2 (func, rettype, parameters_and_attributes, namespace)
415/* To work around GCC bug <https://gcc.gnu.org/PR43881>,
416 we enable the warning only when not optimizing. */
417# if !(defined __GNUC__ && !defined __clang__ && __OPTIMIZE__)
418# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \
419 _GL_WARN_ON_USE_CXX (func, rettype, rettype, parameters_and_attributes, \
420 "The symbol ::" #func " refers to the system function. " \
421 "Use " #namespace "::" #func " instead.")
422# else
423# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \
424 _GL_EXTERN_C int _gl_cxxalias_dummy
425# endif
426#else
427# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \
428 _GL_EXTERN_C int _gl_cxxalias_dummy
429#endif
430
431#endif /* _GL_CXXDEFS_H */
432
433/* The definition of _GL_WARN_ON_USE is copied here. */
434/* A C macro for emitting warnings if a function is used.
435 Copyright (C) 2010-2025 Free Software Foundation, Inc.
436
437 This program is free software: you can redistribute it and/or modify it
438 under the terms of the GNU Lesser General Public License as published
439 by the Free Software Foundation; either version 2 of the License, or
440 (at your option) any later version.
441
442 This program is distributed in the hope that it will be useful,
443 but WITHOUT ANY WARRANTY; without even the implied warranty of
444 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
445 Lesser General Public License for more details.
446
447 You should have received a copy of the GNU Lesser General Public License
448 along with this program. If not, see <https://www.gnu.org/licenses/>. */
449
450/* _GL_WARN_ON_USE (function, "literal string") issues a declaration
451 for FUNCTION which will then trigger a compiler warning containing
452 the text of "literal string" anywhere that function is called, if
453 supported by the compiler. If the compiler does not support this
454 feature, the macro expands to an unused extern declaration.
455
456 _GL_WARN_ON_USE_ATTRIBUTE ("literal string") expands to the
457 attribute used in _GL_WARN_ON_USE. If the compiler does not support
458 this feature, it expands to empty.
459
460 These macros are useful for marking a function as a potential
461 portability trap, with the intent that "literal string" include
462 instructions on the replacement function that should be used
463 instead.
464 _GL_WARN_ON_USE is for functions with 'extern' linkage.
465 _GL_WARN_ON_USE_ATTRIBUTE is for functions with 'static' or 'inline'
466 linkage.
467
468 _GL_WARN_ON_USE should not be used more than once for a given function
469 in a given compilation unit (because this may generate a warning even
470 if the function is never called).
471
472 However, one of the reasons that a function is a portability trap is
473 if it has the wrong signature. Declaring FUNCTION with a different
474 signature in C is a compilation error, so this macro must use the
475 same type as any existing declaration so that programs that avoid
476 the problematic FUNCTION do not fail to compile merely because they
477 included a header that poisoned the function. But this implies that
478 _GL_WARN_ON_USE is only safe to use if FUNCTION is known to already
479 have a declaration. Use of this macro implies that there must not
480 be any other macro hiding the declaration of FUNCTION; but
481 undefining FUNCTION first is part of the poisoning process anyway
482 (although for symbols that are provided only via a macro, the result
483 is a compilation error rather than a warning containing
484 "literal string"). Also note that in C++, it is only safe to use if
485 FUNCTION has no overloads.
486
487 For an example, it is possible to poison 'getline' by:
488 - adding a call to gl_WARN_ON_USE_PREPARE([[#include <stdio.h>]],
489 [getline]) in configure.ac, which potentially defines
490 HAVE_RAW_DECL_GETLINE
491 - adding this code to a header that wraps the system <stdio.h>:
492 #undef getline
493 #if HAVE_RAW_DECL_GETLINE
494 _GL_WARN_ON_USE (getline, "getline is required by POSIX 2008, but"
495 "not universally present; use the gnulib module getline");
496 #endif
497
498 It is not possible to directly poison global variables. But it is
499 possible to write a wrapper accessor function, and poison that
500 (less common usage, like &environ, will cause a compilation error
501 rather than issue the nice warning, but the end result of informing
502 the developer about their portability problem is still achieved):
503 #if HAVE_RAW_DECL_ENVIRON
504 static char ***
505 rpl_environ (void) { return &environ; }
506 _GL_WARN_ON_USE (rpl_environ, "environ is not always properly declared");
507 # undef environ
508 # define environ (*rpl_environ ())
509 #endif
510 or better (avoiding contradictory use of 'static' and 'extern'):
511 #if HAVE_RAW_DECL_ENVIRON
512 static char ***
513 _GL_WARN_ON_USE_ATTRIBUTE ("environ is not always properly declared")
514 rpl_environ (void) { return &environ; }
515 # undef environ
516 # define environ (*rpl_environ ())
517 #endif
518 */
519#ifndef _GL_WARN_ON_USE
520
521# if (4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)) && !defined __clang__
522/* A compiler attribute is available in gcc versions 4.3.0 and later. */
523# define _GL_WARN_ON_USE(function, message) \
524_GL_WARN_EXTERN_C __typeof__ (function) function __attribute__ ((__warning__ (message)))
525# define _GL_WARN_ON_USE_ATTRIBUTE(message) \
526 __attribute__ ((__warning__ (message)))
527# elif __clang_major__ >= 4
528/* Another compiler attribute is available in clang. */
529# define _GL_WARN_ON_USE(function, message) \
530_GL_WARN_EXTERN_C __typeof__ (function) function \
531 __attribute__ ((__diagnose_if__ (1, message, "warning")))
532# define _GL_WARN_ON_USE_ATTRIBUTE(message) \
533 __attribute__ ((__diagnose_if__ (1, message, "warning")))
534# elif (__GNUC__ >= 3 || defined __clang__) && GNULIB_STRICT_CHECKING
535/* Verify the existence of the function. */
536# define _GL_WARN_ON_USE(function, message) \
537_GL_WARN_EXTERN_C __typeof__ (function) function
538# define _GL_WARN_ON_USE_ATTRIBUTE(message)
539# else /* Unsupported. */
540# define _GL_WARN_ON_USE(function, message) \
541_GL_WARN_EXTERN_C int _gl_warn_on_use
542# define _GL_WARN_ON_USE_ATTRIBUTE(message)
543# endif
544#endif
545
546/* _GL_WARN_ON_USE_CXX (function, rettype_gcc, rettype_clang, parameters_and_attributes, "message")
547 is like _GL_WARN_ON_USE (function, "message"), except that in C++ mode the
548 function is declared with the given prototype, consisting of return type,
549 parameters, and attributes.
550 This variant is useful for overloaded functions in C++. _GL_WARN_ON_USE does
551 not work in this case. */
552#ifndef _GL_WARN_ON_USE_CXX
553# if !defined __cplusplus
554# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
555 _GL_WARN_ON_USE (function, msg)
556# else
557# if (4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)) && !defined __clang__
558/* A compiler attribute is available in gcc versions 4.3.0 and later. */
559# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
560extern rettype_gcc function parameters_and_attributes \
561 __attribute__ ((__warning__ (msg)))
562# elif __clang_major__ >= 4
563/* Another compiler attribute is available in clang. */
564# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
565extern rettype_clang function parameters_and_attributes \
566 __attribute__ ((__diagnose_if__ (1, msg, "warning")))
567# elif (__GNUC__ >= 3 || defined __clang__) && GNULIB_STRICT_CHECKING
568/* Verify the existence of the function. */
569# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
570extern rettype_gcc function parameters_and_attributes
571# else /* Unsupported. */
572# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
573_GL_WARN_EXTERN_C int _gl_warn_on_use
574# endif
575# endif
576#endif
577
578/* _GL_WARN_EXTERN_C declaration;
579 performs the declaration with C linkage. */
580#ifndef _GL_WARN_EXTERN_C
581# if defined __cplusplus
582# define _GL_WARN_EXTERN_C extern "C"
583# else
584# define _GL_WARN_EXTERN_C extern
585# endif
586#endif
587
588#if !1
589
590# if !GNULIB_defined_struct_sched_param
591struct sched_param
592{
593 int sched_priority;
594};
595# define GNULIB_defined_struct_sched_param 1
596# endif
597
598#endif
599
600#if !(defined SCHED_FIFO && defined SCHED_RR && defined SCHED_OTHER)
601# define SCHED_FIFO 1
602# define SCHED_RR 2
603# define SCHED_OTHER 0
604#endif
605
606#if 0
607# if 0
608# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
609# undef sched_yield
610# define sched_yield rpl_sched_yield
611# endif
612_GL_FUNCDECL_RPL (sched_yield, int, (void), );
613_GL_CXXALIAS_RPL (sched_yield, int, (void));
614# else
615# if !1
616_GL_FUNCDECL_SYS (sched_yield, int, (void), );
617# endif
618_GL_CXXALIAS_SYS (sched_yield, int, (void));
619# endif
620# if __GLIBC__ >= 2
621_GL_CXXALIASWARN (sched_yield);
622# endif
623#elif defined GNULIB_POSIXCHECK
624# if HAVE_RAW_DECL_SCHED_YIELD
625_GL_WARN_ON_USE (sched_yield, "sched_yield is not portable - "
626 "use gnulib module sched_yield for portability");
627# endif
628#endif
629
630#endif /* _GL_SCHED_H */
631#endif /* _GL_SCHED_H */
diff --git a/gl/sched.in.h b/gl/sched.in.h
new file mode 100644
index 00000000..5b4034c3
--- /dev/null
+++ b/gl/sched.in.h
@@ -0,0 +1,111 @@
1/* A GNU-like <sched.h>.
2 Copyright (C) 2008-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#ifndef _@GUARD_PREFIX@_SCHED_H
18
19#if __GNUC__ >= 3
20@PRAGMA_SYSTEM_HEADER@
21#endif
22@PRAGMA_COLUMNS@
23
24/* This file uses #include_next of a system file that defines time_t.
25 For the 'year2038' module to work right, <config.h> needs to have been
26 included before. */
27#if !_GL_CONFIG_H_INCLUDED
28 #error "Please include config.h first."
29#endif
30
31/* The include_next requires a split double-inclusion guard. */
32#if @HAVE_SCHED_H@
33# if @HAVE_SYS_CDEFS_H@
34# include <sys/cdefs.h>
35# endif
36# @INCLUDE_NEXT@ @NEXT_SCHED_H@
37#endif
38
39#ifndef _@GUARD_PREFIX@_SCHED_H
40#define _@GUARD_PREFIX@_SCHED_H
41
42/* This file uses GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
43#if !_GL_CONFIG_H_INCLUDED
44 #error "Please include config.h first."
45#endif
46
47/* Get pid_t.
48 This is needed on glibc 2.11 (see
49 glibc bug <https://sourceware.org/bugzilla/show_bug.cgi?id=13198>)
50 and Mac OS X 10.5. */
51#include <sys/types.h>
52
53#ifdef __KLIBC__
54/* On OS/2 kLIBC, struct sched_param is in spawn.h. */
55# include <spawn.h>
56#endif
57
58#ifdef __VMS
59/* On OpenVMS, struct sched_param is in <pthread.h>. */
60# include <pthread.h>
61#endif
62
63/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
64
65/* The definition of _GL_WARN_ON_USE is copied here. */
66
67#if !@HAVE_STRUCT_SCHED_PARAM@
68
69# if !GNULIB_defined_struct_sched_param
70struct sched_param
71{
72 int sched_priority;
73};
74# define GNULIB_defined_struct_sched_param 1
75# endif
76
77#endif
78
79#if !(defined SCHED_FIFO && defined SCHED_RR && defined SCHED_OTHER)
80# define SCHED_FIFO 1
81# define SCHED_RR 2
82# define SCHED_OTHER 0
83#endif
84
85#if @GNULIB_SCHED_YIELD@
86# if @REPLACE_SCHED_YIELD@
87# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
88# undef sched_yield
89# define sched_yield rpl_sched_yield
90# endif
91_GL_FUNCDECL_RPL (sched_yield, int, (void), );
92_GL_CXXALIAS_RPL (sched_yield, int, (void));
93# else
94# if !@HAVE_SCHED_YIELD@
95_GL_FUNCDECL_SYS (sched_yield, int, (void), );
96# endif
97_GL_CXXALIAS_SYS (sched_yield, int, (void));
98# endif
99# if __GLIBC__ >= 2
100_GL_CXXALIASWARN (sched_yield);
101# endif
102#elif defined GNULIB_POSIXCHECK
103# undef sched_yield
104# if HAVE_RAW_DECL_SCHED_YIELD
105_GL_WARN_ON_USE (sched_yield, "sched_yield is not portable - "
106 "use gnulib module sched_yield for portability");
107# endif
108#endif
109
110#endif /* _@GUARD_PREFIX@_SCHED_H */
111#endif /* _@GUARD_PREFIX@_SCHED_H */
diff --git a/gl/setenv.c b/gl/setenv.c
index 9e2e9e2f..ef301d41 100644
--- a/gl/setenv.c
+++ b/gl/setenv.c
@@ -1,4 +1,4 @@
1/* Copyright (C) 1992, 1995-2003, 2005-2024 Free Software Foundation, Inc. 1/* Copyright (C) 1992, 1995-2003, 2005-2025 Free Software Foundation, Inc.
2 This file is part of the GNU C Library. 2 This file is part of the GNU C Library.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
@@ -38,11 +38,23 @@
38# include <unistd.h> 38# include <unistd.h>
39#endif 39#endif
40 40
41#if defined _WIN32 && ! defined __CYGWIN__
42# define WIN32_LEAN_AND_MEAN
43# include <windows.h>
44#endif
45
41#if !_LIBC 46#if !_LIBC
42# include "malloca.h" 47# include "malloca.h"
43#endif 48#endif
44 49
50#if defined _WIN32 && ! defined __CYGWIN__
51/* Don't assume that UNICODE is not defined. */
52# undef SetEnvironmentVariable
53# define SetEnvironmentVariable SetEnvironmentVariableA
54#endif
55
45#if _LIBC || !HAVE_SETENV 56#if _LIBC || !HAVE_SETENV
57#if !HAVE_DECL__PUTENV
46 58
47#if !_LIBC 59#if !_LIBC
48# define __environ environ 60# define __environ environ
@@ -215,8 +227,7 @@ __add_to_environ (const char *name, const char *value, const char *combined,
215 } 227 }
216 228
217 if (__environ != last_environ) 229 if (__environ != last_environ)
218 memcpy ((char *) new_environ, (char *) __environ, 230 memcpy (new_environ, __environ, size * sizeof (char *));
219 size * sizeof (char *));
220 231
221 new_environ[size + 1] = NULL; 232 new_environ[size + 1] = NULL;
222 233
@@ -343,6 +354,84 @@ weak_alias (__setenv, setenv)
343weak_alias (__clearenv, clearenv) 354weak_alias (__clearenv, clearenv)
344#endif 355#endif
345 356
357#else /* HAVE_DECL__PUTENV */
358/* Native Windows */
359
360int
361setenv (const char *name, const char *value, int replace)
362{
363 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
364 {
365 errno = EINVAL;
366 return -1;
367 }
368
369 /* The Microsoft documentation
370 <https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-wputenv>
371 says:
372 "Don't change an environment entry directly: instead,
373 use _putenv or _wputenv to change it."
374 Note: Microsoft's _putenv updates not only the contents of _environ but
375 also the contents of _wenviron, so that both are in kept in sync. */
376 const char *existing_value = getenv (name);
377 if (existing_value != NULL)
378 {
379 if (replace)
380 {
381 if (strcmp (existing_value, value) == 0)
382 /* No need to allocate memory. */
383 return 0;
384 }
385 else
386 /* Keep the existing value. */
387 return 0;
388 }
389 /* Allocate a new environment entry in the heap. */
390 /* _putenv ("NAME=") unsets NAME, so if VALUE is the empty string, invoke
391 _putenv ("NAME= ") and fix up the result afterwards. */
392 const char *value_ = (value[0] == '\0' ? " " : value);
393 size_t name_len = strlen (name);
394 size_t value_len = strlen (value_);
395 char *string = (char *) malloc (name_len + 1 + value_len + 1);
396 if (string == NULL)
397 return -1;
398 memcpy (string, name, name_len);
399 string[name_len] = '=';
400 memcpy (&string[name_len + 1], value_, value_len + 1);
401 /* Use _putenv. */
402 if (_putenv (string) < 0)
403 return -1;
404 if (value[0] == '\0')
405 {
406 /* Fix up the result. */
407 char *new_value = getenv (name);
408 if (new_value != NULL && new_value[0] == ' ' && new_value[1] == '\0')
409 new_value[0] = '\0';
410# if defined _WIN32 && ! defined __CYGWIN__
411 /* _putenv propagated "NAME= " into the subprocess environment;
412 fix that by calling SetEnvironmentVariable directly. */
413 /* Documentation:
414 <https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setenvironmentvariable> */
415 if (!SetEnvironmentVariable (name, ""))
416 {
417 switch (GetLastError ())
418 {
419 case ERROR_NOT_ENOUGH_MEMORY:
420 case ERROR_OUTOFMEMORY:
421 errno = ENOMEM;
422 break;
423 default:
424 errno = EINVAL;
425 break;
426 }
427 return -1;
428 }
429# endif
430 }
431 return 0;
432}
433
434#endif /* HAVE_DECL__PUTENV */
346#endif /* _LIBC || !HAVE_SETENV */ 435#endif /* _LIBC || !HAVE_SETENV */
347 436
348/* The rest of this file is called into use when replacing an existing 437/* The rest of this file is called into use when replacing an existing
@@ -360,7 +449,7 @@ int
360rpl_setenv (const char *name, const char *value, int replace) 449rpl_setenv (const char *name, const char *value, int replace)
361{ 450{
362 int result; 451 int result;
363 if (!name || !*name || strchr (name, '=')) 452 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
364 { 453 {
365 errno = EINVAL; 454 errno = EINVAL;
366 return -1; 455 return -1;
diff --git a/gl/setlocale-lock.c b/gl/setlocale-lock.c
index 192489c4..87e0048c 100644
--- a/gl/setlocale-lock.c
+++ b/gl/setlocale-lock.c
@@ -1,5 +1,5 @@
1/* Return the internal lock used by setlocale_null_r. 1/* Return the internal lock used by setlocale_null_r.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc. 2 Copyright (C) 2019-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/setlocale_null-unlocked.c b/gl/setlocale_null-unlocked.c
index 0a86f0df..72729e6b 100644
--- a/gl/setlocale_null-unlocked.c
+++ b/gl/setlocale_null-unlocked.c
@@ -1,5 +1,5 @@
1/* Query the name of the current global locale, without locking. 1/* Query the name of the current global locale, without locking.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc. 2 Copyright (C) 2019-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/setlocale_null.c b/gl/setlocale_null.c
index 5ecf413d..29889642 100644
--- a/gl/setlocale_null.c
+++ b/gl/setlocale_null.c
@@ -1,5 +1,5 @@
1/* Query the name of the current global locale. 1/* Query the name of the current global locale.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc. 2 Copyright (C) 2019-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/setlocale_null.h b/gl/setlocale_null.h
index 966c53cf..3fcb7a82 100644
--- a/gl/setlocale_null.h
+++ b/gl/setlocale_null.h
@@ -1,5 +1,5 @@
1/* Query the name of the current global locale. 1/* Query the name of the current global locale.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc. 2 Copyright (C) 2019-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/sha256-stream.c b/gl/sha256-stream.c
index 08d24b7b..e2668078 100644
--- a/gl/sha256-stream.c
+++ b/gl/sha256-stream.c
@@ -1,7 +1,7 @@
1/* sha256.c - Functions to compute SHA256 and SHA224 message digest of files or 1/* sha256.c - Functions to compute SHA256 and SHA224 message digest of files or
2 memory blocks according to the NIST specification FIPS-180-2. 2 memory blocks according to the NIST specification FIPS-180-2.
3 3
4 Copyright (C) 2005-2006, 2008-2024 Free Software Foundation, Inc. 4 Copyright (C) 2005-2006, 2008-2025 Free Software Foundation, Inc.
5 5
6 This file is free software: you can redistribute it and/or modify 6 This file is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as 7 it under the terms of the GNU Lesser General Public License as
@@ -23,9 +23,6 @@
23#include <config.h> 23#include <config.h>
24 24
25/* Specification. */ 25/* Specification. */
26#if HAVE_OPENSSL_SHA256
27# define GL_OPENSSL_INLINE _GL_EXTERN_INLINE
28#endif
29#include "sha256.h" 26#include "sha256.h"
30 27
31#include <stdlib.h> 28#include <stdlib.h>
@@ -136,10 +133,3 @@ sha224_stream (FILE *stream, void *resblock)
136 return shaxxx_stream (stream, "sha224", resblock, SHA224_DIGEST_SIZE, 133 return shaxxx_stream (stream, "sha224", resblock, SHA224_DIGEST_SIZE,
137 sha224_init_ctx, sha224_finish_ctx); 134 sha224_init_ctx, sha224_finish_ctx);
138} 135}
139
140/*
141 * Hey Emacs!
142 * Local Variables:
143 * coding: utf-8
144 * End:
145 */
diff --git a/gl/sha256.c b/gl/sha256.c
index fe7c5446..9358faff 100644
--- a/gl/sha256.c
+++ b/gl/sha256.c
@@ -1,7 +1,7 @@
1/* sha256.c - Functions to compute SHA256 and SHA224 message digest of files or 1/* sha256.c - Functions to compute SHA256 and SHA224 message digest of files or
2 memory blocks according to the NIST specification FIPS-180-2. 2 memory blocks according to the NIST specification FIPS-180-2.
3 3
4 Copyright (C) 2005-2006, 2008-2024 Free Software Foundation, Inc. 4 Copyright (C) 2005-2006, 2008-2025 Free Software Foundation, Inc.
5 5
6 This file is free software: you can redistribute it and/or modify 6 This file is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as 7 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/sha256.h b/gl/sha256.h
index a9d7abb8..cd1a9fe3 100644
--- a/gl/sha256.h
+++ b/gl/sha256.h
@@ -1,6 +1,6 @@
1/* Declarations of functions and data types used for SHA256 and SHA224 sum 1/* Declarations of functions and data types used for SHA256 and SHA224 sum
2 library functions. 2 library functions.
3 Copyright (C) 2005-2006, 2008-2024 Free Software Foundation, Inc. 3 Copyright (C) 2005-2006, 2008-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/size_max.h b/gl/size_max.h
index bd2eb43e..93eb96a6 100644
--- a/gl/size_max.h
+++ b/gl/size_max.h
@@ -1,5 +1,5 @@
1/* size_max.h -- declare SIZE_MAX through system headers 1/* size_max.h -- declare SIZE_MAX through system headers
2 Copyright (C) 2005-2006, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2006, 2009-2025 Free Software Foundation, Inc.
3 Written by Simon Josefsson. 3 Written by Simon Josefsson.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/snprintf.c b/gl/snprintf.c
index c1b93562..edeee083 100644
--- a/gl/snprintf.c
+++ b/gl/snprintf.c
@@ -1,6 +1,5 @@
1/* Formatted output to strings. 1/* Formatted output to strings.
2 Copyright (C) 2004, 2006-2024 Free Software Foundation, Inc. 2 Copyright (C) 2004, 2006-2025 Free Software Foundation, Inc.
3 Written by Simon Josefsson and Paul Eggert.
4 3
5 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -23,49 +22,25 @@
23#include <errno.h> 22#include <errno.h>
24#include <limits.h> 23#include <limits.h>
25#include <stdarg.h> 24#include <stdarg.h>
26#include <stdlib.h> 25#include <stdint.h>
27#include <string.h>
28 26
29#include "vasnprintf.h"
30
31/* Print formatted output to string STR. Similar to sprintf, but
32 additional length SIZE limit how much is written into STR. Returns
33 string length of formatted string (which may be larger than SIZE).
34 STR may be NULL, in which case nothing will be written. On error,
35 return a negative value. */
36int 27int
37snprintf (char *str, size_t size, const char *format, ...) 28snprintf (char *str, size_t size, const char *format, ...)
38{ 29{
39 char *output;
40 size_t len;
41 size_t lenbuf = size;
42 va_list args; 30 va_list args;
31 ptrdiff_t ret;
43 32
44 va_start (args, format); 33 va_start (args, format);
45 output = vasnprintf (str, &lenbuf, format, args); 34 ret = vsnzprintf (str, size, format, args);
46 len = lenbuf;
47 va_end (args); 35 va_end (args);
48 36
49 if (!output) 37#if PTRDIFF_MAX > INT_MAX
50 return -1; 38 if (ret > INT_MAX)
51
52 if (output != str)
53 {
54 if (size)
55 {
56 size_t pruned_len = (len < size ? len : size - 1);
57 memcpy (str, output, pruned_len);
58 str[pruned_len] = '\0';
59 }
60
61 free (output);
62 }
63
64 if (INT_MAX < len)
65 { 39 {
66 errno = EOVERFLOW; 40 errno = EOVERFLOW;
67 return -1; 41 return -1;
68 } 42 }
43#endif
69 44
70 return len; 45 return ret;
71} 46}
diff --git a/gl/sockets.c b/gl/sockets.c
index 92beb7d3..7accfdd3 100644
--- a/gl/sockets.c
+++ b/gl/sockets.c
@@ -1,6 +1,6 @@
1/* sockets.c --- wrappers for Windows socket functions 1/* sockets.c --- wrappers for Windows socket functions
2 2
3 Copyright (C) 2008-2024 Free Software Foundation, Inc. 3 Copyright (C) 2008-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/sockets.h b/gl/sockets.h
index 55077ae9..5be5d3f6 100644
--- a/gl/sockets.h
+++ b/gl/sockets.h
@@ -1,6 +1,6 @@
1/* sockets.h - wrappers for Windows socket functions 1/* sockets.h - wrappers for Windows socket functions
2 2
3 Copyright (C) 2008-2024 Free Software Foundation, Inc. 3 Copyright (C) 2008-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -52,7 +52,7 @@ int gl_sockets_cleanup (void)
52#endif 52#endif
53 53
54 54
55/* This function is useful it you create a socket using gnulib's 55/* This function is useful if you create a socket using gnulib's
56 Winsock wrappers but needs to pass on the socket handle to some 56 Winsock wrappers but needs to pass on the socket handle to some
57 other library that only accepts sockets. */ 57 other library that only accepts sockets. */
58#ifdef WINDOWS_SOCKETS 58#ifdef WINDOWS_SOCKETS
diff --git a/gl/stat-time.c b/gl/stat-time.c
index 1ab01f53..fa93e16c 100644
--- a/gl/stat-time.c
+++ b/gl/stat-time.c
@@ -1,6 +1,6 @@
1/* stat-related time functions. 1/* stat-related time functions.
2 2
3 Copyright (C) 2012-2024 Free Software Foundation, Inc. 3 Copyright (C) 2012-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/stat-time.h b/gl/stat-time.h
index 3cd8478f..38315b9f 100644
--- a/gl/stat-time.h
+++ b/gl/stat-time.h
@@ -1,6 +1,6 @@
1/* stat-related time functions. 1/* stat-related time functions.
2 2
3 Copyright (C) 2005, 2007, 2009-2024 Free Software Foundation, Inc. 3 Copyright (C) 2005, 2007, 2009-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -117,6 +117,31 @@ get_stat_birthtime_ns (_GL_UNUSED struct stat const *st)
117# endif 117# endif
118} 118}
119 119
120/* Constructs a 'struct timespec' with the given contents.
121 This macro / function is private to stat-time.h. */
122#if !defined __cplusplus
123/* Use a C99 compound literal.
124 This is guaranteed to initialize also the padding bits, for example on
125 platforms where tv_sec is 64 bits and tv_nsec is 32 bits, thus avoiding
126 gcc -Wuse-of-uninitialized-value warnings. */
127# define _gl_make_timespec(sec,nsec) \
128 (struct timespec) { .tv_sec = (sec), .tv_nsec = (nsec) }
129#else
130/* C++ does not have C99 compound literals.
131 A constructor invocation
132 timespec { (sec), (nsec) }
133 would make assumptions about the order of the fields of 'struct timespec',
134 which are not guaranteed by POSIX. So, use an inline function. */
135static inline struct timespec
136_gl_make_timespec (time_t sec, long nsec)
137{
138 struct timespec ts;
139 ts.tv_sec = sec;
140 ts.tv_nsec = nsec;
141 return ts;
142}
143#endif
144
120/* Return *ST's access time. */ 145/* Return *ST's access time. */
121_GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE 146_GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
122get_stat_atime (struct stat const *st) 147get_stat_atime (struct stat const *st)
@@ -124,8 +149,7 @@ get_stat_atime (struct stat const *st)
124#ifdef STAT_TIMESPEC 149#ifdef STAT_TIMESPEC
125 return STAT_TIMESPEC (st, st_atim); 150 return STAT_TIMESPEC (st, st_atim);
126#else 151#else
127 return (struct timespec) { .tv_sec = st->st_atime, 152 return _gl_make_timespec (st->st_atime, get_stat_atime_ns (st));
128 .tv_nsec = get_stat_atime_ns (st) };
129#endif 153#endif
130} 154}
131 155
@@ -136,8 +160,7 @@ get_stat_ctime (struct stat const *st)
136#ifdef STAT_TIMESPEC 160#ifdef STAT_TIMESPEC
137 return STAT_TIMESPEC (st, st_ctim); 161 return STAT_TIMESPEC (st, st_ctim);
138#else 162#else
139 return (struct timespec) { .tv_sec = st->st_ctime, 163 return _gl_make_timespec (st->st_ctime, get_stat_ctime_ns (st));
140 .tv_nsec = get_stat_ctime_ns (st) };
141#endif 164#endif
142} 165}
143 166
@@ -148,8 +171,7 @@ get_stat_mtime (struct stat const *st)
148#ifdef STAT_TIMESPEC 171#ifdef STAT_TIMESPEC
149 return STAT_TIMESPEC (st, st_mtim); 172 return STAT_TIMESPEC (st, st_mtim);
150#else 173#else
151 return (struct timespec) { .tv_sec = st->st_mtime, 174 return _gl_make_timespec (st->st_mtime, get_stat_mtime_ns (st));
152 .tv_nsec = get_stat_mtime_ns (st) };
153#endif 175#endif
154} 176}
155 177
@@ -164,8 +186,7 @@ get_stat_birthtime (_GL_UNUSED struct stat const *st)
164 || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC) 186 || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC)
165 t = STAT_TIMESPEC (st, st_birthtim); 187 t = STAT_TIMESPEC (st, st_birthtim);
166#elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC 188#elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC
167 t = (struct timespec) { .tv_sec = st->st_birthtime, 189 t = _gl_make_timespec (st->st_birthtime, st->st_birthtimensec);
168 .tv_nsec = st->st_birthtimensec };
169#elif defined _WIN32 && ! defined __CYGWIN__ 190#elif defined _WIN32 && ! defined __CYGWIN__
170 /* Native Windows platforms (but not Cygwin) put the "file creation 191 /* Native Windows platforms (but not Cygwin) put the "file creation
171 time" in st_ctime (!). See 192 time" in st_ctime (!). See
@@ -173,11 +194,11 @@ get_stat_birthtime (_GL_UNUSED struct stat const *st)
173# if _GL_WINDOWS_STAT_TIMESPEC 194# if _GL_WINDOWS_STAT_TIMESPEC
174 t = st->st_ctim; 195 t = st->st_ctim;
175# else 196# else
176 t = (struct timespec) { .tv_sec = st->st_ctime }; 197 t = _gl_make_timespec (st->st_ctime, 0);
177# endif 198# endif
178#else 199#else
179 /* Birth time is not supported. */ 200 /* Birth time is not supported. */
180 t = (struct timespec) { .tv_sec = -1, .tv_nsec = -1 }; 201 t = _gl_make_timespec (-1, -1);
181#endif 202#endif
182 203
183#if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \ 204#if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \
@@ -189,7 +210,7 @@ get_stat_birthtime (_GL_UNUSED struct stat const *st)
189 sometimes returns junk in the birth time fields; work around this 210 sometimes returns junk in the birth time fields; work around this
190 bug if it is detected. */ 211 bug if it is detected. */
191 if (! (t.tv_sec && 0 <= t.tv_nsec && t.tv_nsec < 1000000000)) 212 if (! (t.tv_sec && 0 <= t.tv_nsec && t.tv_nsec < 1000000000))
192 t = (struct timespec) { .tv_sec = -1, .tv_nsec = -1 }; 213 t = _gl_make_timespec (-1, -1);
193#endif 214#endif
194 215
195 return t; 216 return t;
diff --git a/gl/stat-w32.c b/gl/stat-w32.c
index ddd6f598..8da8fe5c 100644
--- a/gl/stat-w32.c
+++ b/gl/stat-w32.c
@@ -1,5 +1,5 @@
1/* Core of implementation of fstat and stat for native Windows. 1/* Core of implementation of fstat and stat for native Windows.
2 Copyright (C) 2017-2024 Free Software Foundation, Inc. 2 Copyright (C) 2017-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/stat-w32.h b/gl/stat-w32.h
index 392faed1..c70c1be3 100644
--- a/gl/stat-w32.h
+++ b/gl/stat-w32.h
@@ -1,5 +1,5 @@
1/* Core of implementation of fstat and stat for native Windows. 1/* Core of implementation of fstat and stat for native Windows.
2 Copyright (C) 2017-2024 Free Software Foundation, Inc. 2 Copyright (C) 2017-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/stat.c b/gl/stat.c
index ecf9f9bb..66637837 100644
--- a/gl/stat.c
+++ b/gl/stat.c
@@ -1,5 +1,5 @@
1/* Work around platform bugs in stat. 1/* Work around platform bugs in stat.
2 Copyright (C) 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2009-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -118,6 +118,10 @@ rpl_stat (char const *name, struct stat *buf)
118 around length limitations 118 around length limitations
119 <https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file> ? */ 119 <https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file> ? */
120 120
121 /* To ease portability. Like in open.c. */
122 if (strcmp (name, "/dev/null") == 0)
123 name = "NUL";
124
121 /* POSIX <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13> 125 /* POSIX <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>
122 specifies: "More than two leading <slash> characters shall be treated as 126 specifies: "More than two leading <slash> characters shall be treated as
123 a single <slash> character." */ 127 a single <slash> character." */
diff --git a/gl/stdckdint.in.h b/gl/stdckdint.in.h
index 91848806..bb9089b4 100644
--- a/gl/stdckdint.in.h
+++ b/gl/stdckdint.in.h
@@ -1,6 +1,6 @@
1/* stdckdint.h -- checked integer arithmetic 1/* stdckdint.h -- checked integer arithmetic
2 2
3 Copyright 2022-2024 Free Software Foundation, Inc. 3 Copyright 2022-2025 Free Software Foundation, Inc.
4 4
5 This program is free software: you can redistribute it and/or modify it 5 This program is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Lesser General Public License as published 6 under the terms of the GNU Lesser General Public License as published
@@ -15,10 +15,30 @@
15 You should have received a copy of the GNU Lesser General Public License 15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 17
18#ifndef _GL_STDCKDINT_H 18#if __GNUC__ >= 3
19#define _GL_STDCKDINT_H 19@PRAGMA_SYSTEM_HEADER@
20#endif
21@PRAGMA_COLUMNS@
20 22
21#include "intprops-internal.h" 23#ifndef _@GUARD_PREFIX@_STDCKDINT_H
24
25/* The include_next requires a split double-inclusion guard. */
26#if defined __cplusplus ? @HAVE_CXX_STDCKDINT_H@ : @HAVE_C_STDCKDINT_H@
27# @INCLUDE_NEXT@ @NEXT_STDCKDINT_H@
28#endif
29
30#ifndef _@GUARD_PREFIX@_STDCKDINT_H
31#define _@GUARD_PREFIX@_STDCKDINT_H
32
33/* Do nothing but include the system header if it works properly. */
34# if defined __cplusplus ? !@HAVE_WORKING_CXX_STDCKDINT_H@ : !@HAVE_WORKING_C_STDCKDINT_H@
35
36/* Avoid redefining macros. */
37# undef ckd_add
38# undef ckd_sub
39# undef ckd_mul
40
41# include "intprops-internal.h"
22 42
23/* Store into *R the low-order bits of A + B, A - B, A * B, respectively. 43/* Store into *R the low-order bits of A + B, A - B, A * B, respectively.
24 Return 1 if the result overflows, 0 otherwise. 44 Return 1 if the result overflows, 0 otherwise.
@@ -26,10 +46,13 @@
26 bit-precise integer type, or an enumeration type. 46 bit-precise integer type, or an enumeration type.
27 47
28 These are like the standard macros introduced in C23, except that 48 These are like the standard macros introduced in C23, except that
29 arguments should not have side effects. */ 49 arguments should not have side effects. The C++26 standard is
50 expected to add this header and it's macros. */
30 51
31#define ckd_add(r, a, b) ((bool) _GL_INT_ADD_WRAPV (a, b, r)) 52# define ckd_add(r, a, b) ((bool) _GL_INT_ADD_WRAPV (a, b, r))
32#define ckd_sub(r, a, b) ((bool) _GL_INT_SUBTRACT_WRAPV (a, b, r)) 53# define ckd_sub(r, a, b) ((bool) _GL_INT_SUBTRACT_WRAPV (a, b, r))
33#define ckd_mul(r, a, b) ((bool) _GL_INT_MULTIPLY_WRAPV (a, b, r)) 54# define ckd_mul(r, a, b) ((bool) _GL_INT_MULTIPLY_WRAPV (a, b, r))
34 55
35#endif /* _GL_STDCKDINT_H */ 56# endif /* defined __cplusplus ? @HAVE_WORKING_CXX_STDCKDINT_H@ : @HAVE_WORKING_C_STDCKDINT_H@ */
57#endif /* _@GUARD_PREFIX@_STDCKDINT_H */
58#endif /* _@GUARD_PREFIX@_STDCKDINT_H */
diff --git a/gl/stddef.in.h b/gl/stddef.in.h
index fa8998d9..e8c55ff1 100644
--- a/gl/stddef.in.h
+++ b/gl/stddef.in.h
@@ -1,6 +1,6 @@
1/* A substitute for POSIX 2008 <stddef.h>, for platforms that have issues. 1/* A substitute for POSIX 2008 <stddef.h>, for platforms that have issues.
2 2
3 Copyright (C) 2009-2024 Free Software Foundation, Inc. 3 Copyright (C) 2009-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -27,13 +27,21 @@
27#endif 27#endif
28@PRAGMA_COLUMNS@ 28@PRAGMA_COLUMNS@
29 29
30#if defined __need_wchar_t || defined __need_size_t \ 30#if (defined __need_wchar_t || defined __need_size_t \
31 || defined __need_ptrdiff_t || defined __need_NULL \ 31 || defined __need_ptrdiff_t || defined __need_NULL \
32 || defined __need_wint_t 32 || defined __need_wint_t) \
33 /* Avoid warning triggered by "gcc -std=gnu23 -Wsystem-headers" \
34 in GCC 13.3 and 14.2 \
35 <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114870>. */ \
36 && !@STDDEF_NOT_IDEMPOTENT@
33/* Special invocation convention inside gcc header files. In 37/* Special invocation convention inside gcc header files. In
34 particular, gcc provides a version of <stddef.h> that blindly 38 particular, <stddef.h> in some ancient versions of GCC blindly
35 redefines NULL even when __need_wint_t was defined, even though 39 redefined NULL when __need_wint_t was defined, even though wint_t
36 wint_t is not normally provided by <stddef.h>. Hence, we must 40 is not normally provided by <stddef.h>.
41 (FIXME: It's not clear what GCC versions those were - perhaps so
42 ancient that we can stop worrying about this?)
43 Although glibc 2.26 (2017) and later do not use __need_wint_t,
44 for portability to macOS, Cygwin, Haiku, and older Glibc + GCC,
37 remember if special invocation has ever been used to obtain wint_t, 45 remember if special invocation has ever been used to obtain wint_t,
38 in which case we need to clean up NULL yet again. */ 46 in which case we need to clean up NULL yet again. */
39 47
@@ -52,6 +60,13 @@
52# endif 60# endif
53 61
54#else 62#else
63/* For @STDDEF_NOT_IDEMPOTENT@. */
64# undef __need_wchar_t
65# undef __need_size_t
66# undef __need_ptrdiff_t
67# undef __need_NULL
68# undef __need_wint_t
69
55/* Normal invocation convention. */ 70/* Normal invocation convention. */
56 71
57# ifndef _@GUARD_PREFIX@_STDDEF_H 72# ifndef _@GUARD_PREFIX@_STDDEF_H
@@ -74,6 +89,12 @@ typedef long max_align_t;
74# endif 89# endif
75# endif 90# endif
76 91
92# if !defined _GCC_NULLPTR_T && !@NULLPTR_T_NEEDS_STDDEF@
93 /* Suppress unwanted nullptr_t typedef. See
94 <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114869>. */
95# define _GCC_NULLPTR_T
96# endif
97
77/* The include_next requires a split double-inclusion guard. */ 98/* The include_next requires a split double-inclusion guard. */
78 99
79# @INCLUDE_NEXT@ @NEXT_STDDEF_H@ 100# @INCLUDE_NEXT@ @NEXT_STDDEF_H@
@@ -110,7 +131,7 @@ typedef long max_align_t;
110 */ 131 */
111#ifndef _GL_ATTRIBUTE_NOTHROW 132#ifndef _GL_ATTRIBUTE_NOTHROW
112# if defined __cplusplus 133# if defined __cplusplus
113# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major >= 4 134# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major__ >= 4
114# if __cplusplus >= 201103L 135# if __cplusplus >= 201103L
115# define _GL_ATTRIBUTE_NOTHROW noexcept (true) 136# define _GL_ATTRIBUTE_NOTHROW noexcept (true)
116# else 137# else
@@ -128,11 +149,6 @@ typedef long max_align_t;
128# endif 149# endif
129#endif 150#endif
130 151
131/* Some platforms lack wchar_t. */
132#if !@HAVE_WCHAR_T@
133# define wchar_t int
134#endif
135
136/* Some platforms lack max_align_t. The check for _GCC_MAX_ALIGN_T is 152/* Some platforms lack max_align_t. The check for _GCC_MAX_ALIGN_T is
137 a hack in case the configure-time test was done with g++ even though 153 a hack in case the configure-time test was done with g++ even though
138 we are currently compiling with gcc. 154 we are currently compiling with gcc.
@@ -172,38 +188,57 @@ typedef union
172#endif 188#endif
173 189
174/* ISO C 23 § 7.21.1 The unreachable macro */ 190/* ISO C 23 § 7.21.1 The unreachable macro */
175#ifndef unreachable 191/* This macro is only usable in C, not in C++.
192 There is no way to define it as a macro in C++, because that would break code
193 that does
194 #include <utility>
195 ... std::unreachable() ...
196 Similarly, there is no way to define it as an inline function in C++, because
197 that would break code that does
198 #include <utility>
199 using std::unreachable;
200 As a workaround, we define a macro gl_unreachable, that is like unreachable,
201 but is usable in both C and C++. */
176 202
177/* Code borrowed from verify.h. */ 203/* Code borrowed from verify.h. */
178# ifndef _GL_HAS_BUILTIN_UNREACHABLE 204#ifndef _GL_HAS_BUILTIN_UNREACHABLE
179# if defined __clang_major__ && __clang_major__ < 5 205# if defined __clang_major__ && __clang_major__ < 5
180# define _GL_HAS_BUILTIN_UNREACHABLE 0 206# define _GL_HAS_BUILTIN_UNREACHABLE 0
181# elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__) 207# elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__) && !defined __clang__
182# define _GL_HAS_BUILTIN_UNREACHABLE 1 208# define _GL_HAS_BUILTIN_UNREACHABLE 1
183# elif defined __has_builtin 209# elif defined __has_builtin
184# define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable) 210# define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable)
185# else 211# else
186# define _GL_HAS_BUILTIN_UNREACHABLE 0 212# define _GL_HAS_BUILTIN_UNREACHABLE 0
187# endif
188# endif 213# endif
214#endif
189 215
190# if _GL_HAS_BUILTIN_UNREACHABLE 216#if _GL_HAS_BUILTIN_UNREACHABLE
191# define unreachable() __builtin_unreachable () 217# define gl_unreachable() __builtin_unreachable ()
192# elif 1200 <= _MSC_VER 218#elif 1200 <= _MSC_VER
193# define unreachable() __assume (0) 219# define gl_unreachable() __assume (0)
194# else 220#elif !defined __cplusplus && @HAVE_C_UNREACHABLE@
221# define gl_unreachable() unreachable ()
222#else
195/* Declare abort(), without including <stdlib.h>. */ 223/* Declare abort(), without including <stdlib.h>. */
196extern 224extern
197# if defined __cplusplus 225# if defined __cplusplus
198"C" 226"C"
199# endif 227# endif
200_Noreturn 228_Noreturn
201void abort (void) 229void abort (void)
202# if defined __cplusplus && (__GLIBC__ >= 2) 230# if defined __cplusplus && (__GLIBC__ >= 2)
203_GL_ATTRIBUTE_NOTHROW 231_GL_ATTRIBUTE_NOTHROW
204# endif 232# endif
205; 233;
206# define unreachable() abort () 234# define gl_unreachable() abort ()
235#endif
236
237#if !defined __cplusplus && !@HAVE_C_UNREACHABLE@
238/* In C, define unreachable as a macro. */
239
240# ifndef unreachable
241# define unreachable() gl_unreachable ()
207# endif 242# endif
208 243
209#endif 244#endif
diff --git a/gl/stdint.in.h b/gl/stdint.in.h
index fea7483b..ca566b30 100644
--- a/gl/stdint.in.h
+++ b/gl/stdint.in.h
@@ -1,4 +1,4 @@
1/* Copyright (C) 2001-2002, 2004-2024 Free Software Foundation, Inc. 1/* Copyright (C) 2001-2002, 2004-2025 Free Software Foundation, Inc.
2 Written by Paul Eggert, Bruno Haible, Sam Steingold, Peter Burwood. 2 Written by Paul Eggert, Bruno Haible, Sam Steingold, Peter Burwood.
3 This file is part of gnulib. 3 This file is part of gnulib.
4 4
@@ -80,7 +80,7 @@
80#define _@GUARD_PREFIX@_STDINT_H 80#define _@GUARD_PREFIX@_STDINT_H
81 81
82/* Get SCHAR_MIN, SCHAR_MAX, UCHAR_MAX, INT_MIN, INT_MAX, 82/* Get SCHAR_MIN, SCHAR_MAX, UCHAR_MAX, INT_MIN, INT_MAX,
83 LONG_MIN, LONG_MAX, ULONG_MAX, _GL_INTEGER_WIDTH. */ 83 LONG_MIN, LONG_MAX, ULONG_MAX, CHAR_BIT, _GL_INTEGER_WIDTH. */
84#include <limits.h> 84#include <limits.h>
85 85
86/* Override WINT_MIN and WINT_MAX if gnulib's <wchar.h> or <wctype.h> overrides 86/* Override WINT_MIN and WINT_MAX if gnulib's <wchar.h> or <wctype.h> overrides
@@ -189,6 +189,10 @@ typedef __int64 gl_int64_t;
189# define int64_t gl_int64_t 189# define int64_t gl_int64_t
190# define GL_INT64_T 190# define GL_INT64_T
191# else 191# else
192/* Verify that 'long long' has exactly 64 bits. */
193typedef _gl_verify_int64_bits[
194 _STDINT_MAX (1, sizeof (long long) * CHAR_BIT, 0ll) >> 31 >> 31 == 1
195 ? 1 : -1];
192# undef int64_t 196# undef int64_t
193typedef long long int gl_int64_t; 197typedef long long int gl_int64_t;
194# define int64_t gl_int64_t 198# define int64_t gl_int64_t
@@ -210,6 +214,11 @@ typedef unsigned __int64 gl_uint64_t;
210# define uint64_t gl_uint64_t 214# define uint64_t gl_uint64_t
211# define GL_UINT64_T 215# define GL_UINT64_T
212# else 216# else
217/* Verify that 'unsigned long long' has exactly 64 bits. */
218typedef _gl_verify_uint64_bits[
219 _STDINT_MAX (0, sizeof (unsigned long long) * CHAR_BIT, 0ull)
220 >> 31 >> 31 >> 1 == 1
221 ? 1 : -1];
213# undef uint64_t 222# undef uint64_t
214typedef unsigned long long int gl_uint64_t; 223typedef unsigned long long int gl_uint64_t;
215# define uint64_t gl_uint64_t 224# define uint64_t gl_uint64_t
diff --git a/gl/stdio-consolesafe.c b/gl/stdio-consolesafe.c
new file mode 100644
index 00000000..80561a6d
--- /dev/null
+++ b/gl/stdio-consolesafe.c
@@ -0,0 +1,199 @@
1/* msvcrt workarounds.
2 Copyright (C) 2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19/* Specification. */
20#include <stdio.h>
21
22#include <stdckdint.h>
23#include <stdlib.h>
24#include <string.h>
25
26/* Outputs N bytes starting at S to FP.
27 These N bytes are known to be followed by a NUL.
28 Finally frees the string at S.
29 Returns the number of written bytes. */
30static size_t
31workaround_fwrite0 (char *s, size_t n, FILE *fp)
32{
33 const char *ptr = s;
34 /* Use fputs instead of fwrite, which is buggy in msvcrt. */
35 size_t written = 0;
36 while (n > 0)
37 {
38 size_t l = strlen (ptr); /* 0 <= l <= n */
39 if (l > 0)
40 {
41 if (fputs (ptr, fp) == EOF)
42 break;
43 written += l;
44 n -= l;
45 }
46 if (n == 0)
47 break;
48 if (fputc ('\0', fp) == EOF)
49 break;
50 written++;
51 n--;
52 ptr += l + 1;
53 }
54 free (s);
55 return written;
56}
57
58size_t
59gl_consolesafe_fwrite (const void *ptr, size_t size, size_t nmemb, FILE *fp)
60{
61 size_t nbytes;
62 if (ckd_mul (&nbytes, size, nmemb) || nbytes == 0)
63 /* Overflow, or nothing to do. */
64 return 0;
65 char *tmp = malloc (nbytes + 1);
66 if (tmp == NULL)
67 return 0;
68 memcpy (tmp, ptr, nbytes);
69 tmp[nbytes] = '\0';
70 size_t written = workaround_fwrite0 (tmp, nbytes, fp);
71 return written / size;
72}
73
74#if defined __MINGW32__ && __USE_MINGW_ANSI_STDIO
75
76# include "fseterr.h"
77# include <stdarg.h>
78
79# if !HAVE_VASPRINTF
80
81# include <errno.h>
82
83/* The old mingw (before mingw-w64) does not have the vasprintf function.
84 Define a suitable replacement here, that supports the same format
85 specifiers as the mingw *printf functions. */
86
87static int
88vasprintf (char **resultp, const char *format, va_list args)
89{
90 /* First try: Use a stack-allocated buffer. */
91 char buf[2048];
92 size_t bufsize = sizeof (buf);
93 int ret = __mingw_vsnprintf (buf, bufsize, format, args);
94 if (ret < 0)
95 return -1;
96 size_t nbytes = ret;
97 char *mem = (char *) malloc (nbytes + 1);
98 if (mem == NULL)
99 {
100 errno = ENOMEM;
101 return -1;
102 }
103 if (ret < bufsize)
104 {
105 /* The buffer was sufficiently large. */
106 memcpy (mem, buf, nbytes + 1);
107 }
108 else
109 {
110 /* Second try: Use the heap-allocated memory. */
111 ret = __mingw_vsnprintf (mem, nbytes + 1, format, args);
112 if (ret < 0)
113 {
114 int saved_errno = errno;
115 free (mem);
116 errno = saved_errno;
117 return -1;
118 }
119 if (ret != nbytes)
120 abort ();
121 }
122 *resultp = mem;
123 return nbytes;
124}
125
126# endif
127
128/* Bypass the functions __mingw_[v][f]printf, that trigger a bug in msvcrt,
129 but without losing the support for modern format specifiers added by
130 __mingw_*printf. */
131
132int
133gl_consolesafe_fprintf (FILE *restrict fp, const char *restrict format, ...)
134{
135 va_list args;
136 char *tmpstring;
137 va_start (args, format);
138 int result = vasprintf (&tmpstring, format, args);
139 va_end (args);
140 if (result >= 0)
141 {
142 if (workaround_fwrite0 (tmpstring, result, fp) < result)
143 result = -1;
144 }
145 else
146 fseterr (fp);
147 return result;
148}
149
150int
151gl_consolesafe_printf (const char *restrict format, ...)
152{
153 va_list args;
154 char *tmpstring;
155 va_start (args, format);
156 int result = vasprintf (&tmpstring, format, args);
157 va_end (args);
158 if (result >= 0)
159 {
160 if (workaround_fwrite0 (tmpstring, result, stdout) < result)
161 result = -1;
162 }
163 else
164 fseterr (stdout);
165 return result;
166}
167
168int
169gl_consolesafe_vfprintf (FILE *restrict fp,
170 const char *restrict format, va_list args)
171{
172 char *tmpstring;
173 int result = vasprintf (&tmpstring, format, args);
174 if (result >= 0)
175 {
176 if (workaround_fwrite0 (tmpstring, result, fp) < result)
177 result = -1;
178 }
179 else
180 fseterr (fp);
181 return result;
182}
183
184int
185gl_consolesafe_vprintf (const char *restrict format, va_list args)
186{
187 char *tmpstring;
188 int result = vasprintf (&tmpstring, format, args);
189 if (result >= 0)
190 {
191 if (workaround_fwrite0 (tmpstring, result, stdout) < result)
192 result = -1;
193 }
194 else
195 fseterr (stdout);
196 return result;
197}
198
199#endif
diff --git a/gl/stdio-impl.h b/gl/stdio-impl.h
index 63ebf7c6..e4a69a8d 100644
--- a/gl/stdio-impl.h
+++ b/gl/stdio-impl.h
@@ -1,5 +1,5 @@
1/* Implementation details of FILE streams. 1/* Implementation details of FILE streams.
2 Copyright (C) 2007-2008, 2010-2024 Free Software Foundation, Inc. 2 Copyright (C) 2007-2008, 2010-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -30,6 +30,49 @@
30# endif 30# endif
31#endif 31#endif
32 32
33/* Haiku stdio implementation. */
34#if defined __HAIKU__
35# include <stdint.h>
36/* This FILE structure was made into an incomplete type in 2025.
37 See <https://cgit.haiku-os.org/haiku/tree/src/system/libroot/posix/glibc/libio/libio.h>. */
38# define fp_ ((struct { int _flags; \
39 char *_IO_read_ptr; \
40 char *_IO_read_end; \
41 char *_IO_read_base; \
42 char *_IO_write_base; \
43 char *_IO_write_ptr; \
44 char *_IO_write_end; \
45 char *_IO_buf_base; \
46 char *_IO_buf_end; \
47 char *_IO_save_base; \
48 char *_IO_backup_base; \
49 char *_IO_save_end; \
50 void *_markers; \
51 void *_chain; \
52 int _fileno; \
53 int _flags2; \
54 off_t _old_offset; \
55 unsigned short _cur_column; \
56 signed char _vtable_offset; \
57 char _shortbuf[1]; \
58 void *_lock; \
59 int64_t _offset; \
60 /* More fields, not relevant here. */ \
61 } *) fp)
62# if !defined _IO_UNBUFFERED
63# define _IO_UNBUFFERED 0x2
64# endif
65# if !defined _IO_EOF_SEEN
66# define _IO_EOF_SEEN 0x10
67# endif
68# if !defined _IO_IN_BACKUP
69# define _IO_IN_BACKUP 0x100
70# endif
71# if !defined _IO_LINE_BUF
72# define _IO_LINE_BUF 0x200
73# endif
74#endif
75
33/* BSD stdio derived implementations. */ 76/* BSD stdio derived implementations. */
34 77
35#if defined __NetBSD__ /* NetBSD */ 78#if defined __NetBSD__ /* NetBSD */
@@ -39,7 +82,7 @@
39 82
40#include <errno.h> /* For detecting Plan9. */ 83#include <errno.h> /* For detecting Plan9. */
41 84
42#if defined __sferror || defined __DragonFly__ || defined __ANDROID__ 85#if defined __sferror || defined __OpenBSD__ || defined __DragonFly__ || defined __ANDROID__
43 /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Minix 3, Android */ 86 /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Minix 3, Android */
44 87
45# if defined __DragonFly__ /* DragonFly */ 88# if defined __DragonFly__ /* DragonFly */
@@ -65,13 +108,59 @@
65# define _flags pub._flags 108# define _flags pub._flags
66# define _r pub._r 109# define _r pub._r
67# define _w pub._w 110# define _w pub._w
68# elif defined __ANDROID__ /* Android */ 111# elif defined __OpenBSD__ /* OpenBSD */
69# ifdef __LP64__ 112# if defined __sferror /* OpenBSD <= 7.7 */
113# define _gl_flags_file_t short
114# else /* OpenBSD >= 7.8 */
115# define _gl_flags_file_t int
116# endif
117 /* Up to this commit from 2025-07-16
118 <https://github.com/openbsd/src/commit/b7f6c2eb760a2da367dd51d539ef06f5f3553790>
119 the innards of FILE were public. After this commit, the innards of FILE
120 are hidden. In this commit
121 <https://github.com/openbsd/src/commit/9063a2f1ec94013fb0e2c7ec851495108e788a6e>
122 they were reshuffled. */
123# if defined __sferror /* OpenBSD <= 7.7 */
124# define fp_ ((struct { unsigned char *_p; \
125 int _r; \
126 int _w; \
127 _gl_flags_file_t _flags; \
128 _gl_flags_file_t _file; \
129 struct { unsigned char *_base; size_t _size; } _bf; \
130 int _lbfsize; \
131 void *_cookie; \
132 void *_close; \
133 void *_read; \
134 void *_seek; \
135 void *_write; \
136 struct { unsigned char *_base; size_t _size; } _ext; \
137 unsigned char *_up; \
138 int _ur; \
139 unsigned char _ubuf[3]; \
140 unsigned char _nbuf[1]; \
141 struct { unsigned char *_base; size_t _size; } _lb; \
142 int _blksize; \
143 fpos_t _offset; \
144 /* More fields, not relevant here. */ \
145 } *) fp)
146# else /* OpenBSD >= 7.8 */
147# define fp_ ((struct { _gl_flags_file_t _flags; \
148 _gl_flags_file_t _file; \
149 unsigned char *_p; \
150 int _r; \
151 int _w; \
152 struct { unsigned char *_base; size_t _size; } _bf; \
153 int _lbfsize; \
154 /* More fields, not relevant here. */ \
155 } *) fp)
156# endif
157# elif defined __ANDROID__ /* Android */
158# if defined __LP64__
70# define _gl_flags_file_t int 159# define _gl_flags_file_t int
71# else 160# else
72# define _gl_flags_file_t short 161# define _gl_flags_file_t short
73# endif 162# endif
74# ifdef __LP64__ 163# if defined __LP64__
75# define _gl_file_offset_t int64_t 164# define _gl_file_offset_t int64_t
76# else 165# else
77 /* see https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md */ 166 /* see https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md */
@@ -79,7 +168,7 @@
79# endif 168# endif
80 /* Up to this commit from 2015-10-12 169 /* Up to this commit from 2015-10-12
81 <https://android.googlesource.com/platform/bionic.git/+/f0141dfab10a4b332769d52fa76631a64741297a> 170 <https://android.googlesource.com/platform/bionic.git/+/f0141dfab10a4b332769d52fa76631a64741297a>
82 the innards of FILE were public, and fp_ub could be defined like for OpenBSD, 171 the innards of FILE were public,
83 see <https://android.googlesource.com/platform/bionic.git/+/e78392637d5086384a5631ddfdfa8d7ec8326ee3/libc/stdio/fileext.h> 172 see <https://android.googlesource.com/platform/bionic.git/+/e78392637d5086384a5631ddfdfa8d7ec8326ee3/libc/stdio/fileext.h>
84 and <https://android.googlesource.com/platform/bionic.git/+/e78392637d5086384a5631ddfdfa8d7ec8326ee3/libc/stdio/local.h>. 173 and <https://android.googlesource.com/platform/bionic.git/+/e78392637d5086384a5631ddfdfa8d7ec8326ee3/libc/stdio/local.h>.
85 After this commit, the innards of FILE are hidden. */ 174 After this commit, the innards of FILE are hidden. */
@@ -109,9 +198,8 @@
109# define fp_ fp 198# define fp_ fp
110# endif 199# endif
111 200
112# if (defined __NetBSD__ && __NetBSD_Version__ >= 105270000) || defined __OpenBSD__ || defined __minix /* NetBSD >= 1.5ZA, OpenBSD, Minix 3 */ 201# if (defined __NetBSD__ && __NetBSD_Version__ >= 105270000) || defined __minix /* NetBSD >= 1.5ZA, Minix 3 */
113 /* See <http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/stdio/fileext.h?rev=HEAD&content-type=text/x-cvsweb-markup> 202 /* See <https://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/stdio/fileext.h?rev=HEAD&content-type=text/x-cvsweb-markup>
114 and <https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/fileext.h?rev=HEAD&content-type=text/x-cvsweb-markup>
115 and <https://github.com/Stichting-MINIX-Research-Foundation/minix/blob/master/lib/libc/stdio/fileext.h> */ 203 and <https://github.com/Stichting-MINIX-Research-Foundation/minix/blob/master/lib/libc/stdio/fileext.h> */
116 struct __sfileext 204 struct __sfileext
117 { 205 {
@@ -119,7 +207,7 @@
119 /* More fields, not relevant here. */ 207 /* More fields, not relevant here. */
120 }; 208 };
121# define fp_ub ((struct __sfileext *) fp->_ext._base)->_ub 209# define fp_ub ((struct __sfileext *) fp->_ext._base)->_ub
122# elif defined __ANDROID__ /* Android */ 210# elif defined __ANDROID__ || defined __OpenBSD__ /* Android, OpenBSD */
123 struct __sfileext 211 struct __sfileext
124 { 212 {
125 struct { unsigned char *_base; size_t _size; } _ub; /* ungetc buffer */ 213 struct { unsigned char *_base; size_t _size; } _ub; /* ungetc buffer */
@@ -132,9 +220,11 @@
132 220
133# define HASUB(fp) (fp_ub._base != NULL) 221# define HASUB(fp) (fp_ub._base != NULL)
134 222
135# if defined __ANDROID__ /* Android */ 223# if defined __ANDROID__ || defined __OpenBSD__ /* Android, OpenBSD */
136 /* Needed after this commit from 2016-01-25 224 /* Needed after this Android commit from 2016-01-25
137 <https://android.googlesource.com/platform/bionic.git/+/e70e0e9267d069bf56a5078c99307e08a7280de7> */ 225 <https://android.googlesource.com/platform/bionic.git/+/e70e0e9267d069bf56a5078c99307e08a7280de7>
226 And after this OpenBSD commit from 2025-07-16
227 <https://github.com/openbsd/src/commit/b7f6c2eb760a2da367dd51d539ef06f5f3553790>. */
138# ifndef __SEOF 228# ifndef __SEOF
139# define __SLBF 1 229# define __SLBF 1
140# define __SNBF 2 230# define __SNBF 2
diff --git a/gl/stdio-read.c b/gl/stdio-read.c
index 253b8aa4..70452b48 100644
--- a/gl/stdio-read.c
+++ b/gl/stdio-read.c
@@ -1,5 +1,5 @@
1/* POSIX compatible FILE stream read function. 1/* POSIX compatible FILE stream read function.
2 Copyright (C) 2008-2024 Free Software Foundation, Inc. 2 Copyright (C) 2008-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2011. 3 Written by Bruno Haible <bruno@clisp.org>, 2011.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/stdio-write.c b/gl/stdio-write.c
index ca6aa00c..59ba8fc4 100644
--- a/gl/stdio-write.c
+++ b/gl/stdio-write.c
@@ -1,5 +1,5 @@
1/* POSIX compatible FILE stream write function. 1/* POSIX compatible FILE stream write function.
2 Copyright (C) 2008-2024 Free Software Foundation, Inc. 2 Copyright (C) 2008-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2008. 3 Written by Bruno Haible <bruno@clisp.org>, 2008.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
@@ -162,6 +162,9 @@ vprintf (const char *format, va_list args)
162int 162int
163vfprintf (FILE *stream, const char *format, va_list args) 163vfprintf (FILE *stream, const char *format, va_list args)
164#undef vfprintf 164#undef vfprintf
165#if defined __MINGW32__ && !defined _UCRT && __USE_MINGW_ANSI_STDIO
166# define vfprintf gl_consolesafe_vfprintf
167#endif
165{ 168{
166 CALL_WITH_SIGPIPE_EMULATION (int, vfprintf (stream, format, args), ret == EOF) 169 CALL_WITH_SIGPIPE_EMULATION (int, vfprintf (stream, format, args), ret == EOF)
167} 170}
@@ -198,6 +201,9 @@ puts (const char *string)
198size_t 201size_t
199fwrite (const void *ptr, size_t s, size_t n, FILE *stream) 202fwrite (const void *ptr, size_t s, size_t n, FILE *stream)
200#undef fwrite 203#undef fwrite
204#if (defined _WIN32 && !defined __CYGWIN__) && !defined _UCRT
205# define fwrite gl_consolesafe_fwrite
206#endif
201{ 207{
202 CALL_WITH_SIGPIPE_EMULATION (size_t, fwrite (ptr, s, n, stream), ret < n) 208 CALL_WITH_SIGPIPE_EMULATION (size_t, fwrite (ptr, s, n, stream), ret < n)
203} 209}
diff --git a/gl/stdio.in.h b/gl/stdio.in.h
index 35b9f748..bc454454 100644
--- a/gl/stdio.in.h
+++ b/gl/stdio.in.h
@@ -1,6 +1,6 @@
1/* A GNU-like <stdio.h>. 1/* A GNU-like <stdio.h>.
2 2
3 Copyright (C) 2004, 2007-2024 Free Software Foundation, Inc. 3 Copyright (C) 2004, 2007-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -20,7 +20,7 @@
20#endif 20#endif
21@PRAGMA_COLUMNS@ 21@PRAGMA_COLUMNS@
22 22
23#if defined __need_FILE || defined __need___FILE || defined _GL_ALREADY_INCLUDING_STDIO_H 23#if defined __need_FILE || defined __need___FILE || defined _@GUARD_PREFIX@_ALREADY_INCLUDING_STDIO_H || defined _GL_SKIP_GNULIB_STDIO_H
24/* Special invocation convention: 24/* Special invocation convention:
25 - Inside glibc header files. 25 - Inside glibc header files.
26 - On OSF/1 5.1 we have a sequence of nested includes 26 - On OSF/1 5.1 we have a sequence of nested includes
@@ -48,12 +48,12 @@
48# endif 48# endif
49#endif 49#endif
50 50
51#define _GL_ALREADY_INCLUDING_STDIO_H 51#define _@GUARD_PREFIX@_ALREADY_INCLUDING_STDIO_H
52 52
53/* The include_next requires a split double-inclusion guard. */ 53/* The include_next requires a split double-inclusion guard. */
54#@INCLUDE_NEXT@ @NEXT_STDIO_H@ 54#@INCLUDE_NEXT@ @NEXT_STDIO_H@
55 55
56#undef _GL_ALREADY_INCLUDING_STDIO_H 56#undef _@GUARD_PREFIX@_ALREADY_INCLUDING_STDIO_H
57 57
58#ifdef _GL_DEFINED__POSIX_C_SOURCE 58#ifdef _GL_DEFINED__POSIX_C_SOURCE
59# undef _GL_DEFINED__POSIX_C_SOURCE 59# undef _GL_DEFINED__POSIX_C_SOURCE
@@ -64,8 +64,8 @@
64#define _@GUARD_PREFIX@_STDIO_H 64#define _@GUARD_PREFIX@_STDIO_H
65 65
66/* This file uses _GL_ATTRIBUTE_DEALLOC, _GL_ATTRIBUTE_FORMAT, 66/* This file uses _GL_ATTRIBUTE_DEALLOC, _GL_ATTRIBUTE_FORMAT,
67 _GL_ATTRIBUTE_MALLOC, _GL_ATTRIBUTE_NOTHROW, GNULIB_POSIXCHECK, 67 _GL_ATTRIBUTE_MALLOC, _GL_ATTRIBUTE_NODISCARD, _GL_ATTRIBUTE_NOTHROW,
68 HAVE_RAW_DECL_*. */ 68 GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
69#if !_GL_CONFIG_H_INCLUDED 69#if !_GL_CONFIG_H_INCLUDED
70 #error "Please include config.h first." 70 #error "Please include config.h first."
71#endif 71#endif
@@ -77,7 +77,8 @@
77 77
78/* Get off_t and ssize_t. Needed on many systems, including glibc 2.8 78/* Get off_t and ssize_t. Needed on many systems, including glibc 2.8
79 and eglibc 2.11.2. 79 and eglibc 2.11.2.
80 May also define off_t to a 64-bit type on native Windows. */ 80 May also define off_t to a 64-bit type on native Windows.
81 Also defines off64_t on macOS, NetBSD, OpenBSD, MSVC, Cygwin, Haiku. */
81#include <sys/types.h> 82#include <sys/types.h>
82 83
83/* Solaris 10 and NetBSD 7.0 declare renameat in <unistd.h>, not in <stdio.h>. */ 84/* Solaris 10 and NetBSD 7.0 declare renameat in <unistd.h>, not in <stdio.h>. */
@@ -119,7 +120,7 @@
119 that can be freed by passing them as the Ith argument to the 120 that can be freed by passing them as the Ith argument to the
120 function F. */ 121 function F. */
121#ifndef _GL_ATTRIBUTE_DEALLOC 122#ifndef _GL_ATTRIBUTE_DEALLOC
122# if __GNUC__ >= 11 123# if __GNUC__ >= 11 && !defined __clang__
123# define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i))) 124# define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i)))
124# else 125# else
125# define _GL_ATTRIBUTE_DEALLOC(f, i) 126# define _GL_ATTRIBUTE_DEALLOC(f, i)
@@ -154,7 +155,7 @@
154 */ 155 */
155#ifndef _GL_ATTRIBUTE_NOTHROW 156#ifndef _GL_ATTRIBUTE_NOTHROW
156# if defined __cplusplus 157# if defined __cplusplus
157# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major >= 4 158# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major__ >= 4
158# if __cplusplus >= 201103L 159# if __cplusplus >= 201103L
159# define _GL_ATTRIBUTE_NOTHROW noexcept (true) 160# define _GL_ATTRIBUTE_NOTHROW noexcept (true)
160# else 161# else
@@ -177,7 +178,7 @@
177 standardized by ISO C99 and POSIX. 178 standardized by ISO C99 and POSIX.
178 _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD */ 179 _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD */
179/* __gnu_printf__ is supported in GCC >= 4.4. */ 180/* __gnu_printf__ is supported in GCC >= 4.4. */
180#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) 181#if (__GNUC__ + (__GNUC_MINOR__ >= 4) > 4) && !defined __clang__
181# define _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD __gnu_printf__ 182# define _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD __gnu_printf__
182#else 183#else
183# define _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD __printf__ 184# define _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD __printf__
@@ -279,18 +280,64 @@
279#endif 280#endif
280 281
281 282
283#if (defined _WIN32 && !defined __CYGWIN__) && !defined _UCRT
284/* Workarounds against msvcrt bugs. */
285_GL_FUNCDECL_SYS (gl_consolesafe_fwrite, size_t,
286 (const void *ptr, size_t size, size_t nmemb, FILE *fp),
287 _GL_ARG_NONNULL ((1, 4)));
288# if defined __MINGW32__
289_GL_FUNCDECL_SYS (gl_consolesafe_fprintf, int,
290 (FILE *restrict fp, const char *restrict format, ...),
291 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
292 _GL_ARG_NONNULL ((1, 2)));
293_GL_FUNCDECL_SYS (gl_consolesafe_printf, int,
294 (const char *restrict format, ...),
295 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 2)
296 _GL_ARG_NONNULL ((1)));
297_GL_FUNCDECL_SYS (gl_consolesafe_vfprintf, int,
298 (FILE *restrict fp,
299 const char *restrict format, va_list args),
300 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
301 _GL_ARG_NONNULL ((1, 2)));
302_GL_FUNCDECL_SYS (gl_consolesafe_vprintf, int,
303 (const char *restrict format, va_list args),
304 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 0)
305 _GL_ARG_NONNULL ((1)));
306# endif
307#endif
308
309
310#if @GNULIB_DZPRINTF@
311/* Prints formatted output to file descriptor FD.
312 Returns the number of bytes written to the file descriptor. Upon
313 failure, returns -1 with errno set.
314 Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
315 Therefore, if the format string is valid and does not use %ls/%lc
316 directives nor widths, the only possible failure codes are ENOMEM
317 and the possible failure codes from write(), excluding EINTR. */
318_GL_FUNCDECL_SYS (dzprintf, off64_t,
319 (int fd, const char *restrict format, ...),
320 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
321 _GL_ARG_NONNULL ((2)));
322_GL_CXXALIAS_SYS (dzprintf, off64_t,
323 (int fd, const char *restrict format, ...));
324#endif
325
282#if @GNULIB_DPRINTF@ 326#if @GNULIB_DPRINTF@
327/* Prints formatted output to file descriptor FD.
328 Returns the number of bytes written to the file descriptor. Upon
329 failure, returns a negative value. */
283# if @REPLACE_DPRINTF@ 330# if @REPLACE_DPRINTF@
284# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 331# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
285# define dprintf rpl_dprintf 332# define dprintf rpl_dprintf
286# endif 333# endif
287_GL_FUNCDECL_RPL (dprintf, int, (int fd, const char *restrict format, ...) 334_GL_FUNCDECL_RPL (dprintf, int, (int fd, const char *restrict format, ...),
288 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) 335 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
289 _GL_ARG_NONNULL ((2))); 336 _GL_ARG_NONNULL ((2)));
290_GL_CXXALIAS_RPL (dprintf, int, (int fd, const char *restrict format, ...)); 337_GL_CXXALIAS_RPL (dprintf, int, (int fd, const char *restrict format, ...));
291# else 338# else
292# if !@HAVE_DPRINTF@ 339# if !@HAVE_DPRINTF@
293_GL_FUNCDECL_SYS (dprintf, int, (int fd, const char *restrict format, ...) 340_GL_FUNCDECL_SYS (dprintf, int, (int fd, const char *restrict format, ...),
294 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) 341 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
295 _GL_ARG_NONNULL ((2))); 342 _GL_ARG_NONNULL ((2)));
296# endif 343# endif
@@ -313,7 +360,7 @@ _GL_WARN_ON_USE (dprintf, "dprintf is unportable - "
313# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 360# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
314# define fclose rpl_fclose 361# define fclose rpl_fclose
315# endif 362# endif
316_GL_FUNCDECL_RPL (fclose, int, (FILE *stream) _GL_ARG_NONNULL ((1))); 363_GL_FUNCDECL_RPL (fclose, int, (FILE *stream), _GL_ARG_NONNULL ((1)));
317_GL_CXXALIAS_RPL (fclose, int, (FILE *stream)); 364_GL_CXXALIAS_RPL (fclose, int, (FILE *stream));
318# else 365# else
319_GL_CXXALIAS_SYS (fclose, int, (FILE *stream)); 366_GL_CXXALIAS_SYS (fclose, int, (FILE *stream));
@@ -360,9 +407,10 @@ _GL_CXXALIASWARN (fcloseall);
360# define fdopen rpl_fdopen 407# define fdopen rpl_fdopen
361# endif 408# endif
362_GL_FUNCDECL_RPL (fdopen, FILE *, 409_GL_FUNCDECL_RPL (fdopen, FILE *,
363 (int fd, const char *mode) 410 (int fd, const char *mode),
364 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1) 411 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)
365 _GL_ATTRIBUTE_MALLOC); 412 _GL_ATTRIBUTE_MALLOC
413 _GL_ATTRIBUTE_NODISCARD);
366_GL_CXXALIAS_RPL (fdopen, FILE *, (int fd, const char *mode)); 414_GL_CXXALIAS_RPL (fdopen, FILE *, (int fd, const char *mode));
367# elif defined _WIN32 && !defined __CYGWIN__ 415# elif defined _WIN32 && !defined __CYGWIN__
368# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 416# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -371,36 +419,38 @@ _GL_CXXALIAS_RPL (fdopen, FILE *, (int fd, const char *mode));
371# endif 419# endif
372_GL_CXXALIAS_MDA (fdopen, FILE *, (int fd, const char *mode)); 420_GL_CXXALIAS_MDA (fdopen, FILE *, (int fd, const char *mode));
373# else 421# else
374# if __GNUC__ >= 11 422# if __GNUC__ >= 11 && !defined __clang__
375/* For -Wmismatched-dealloc: Associate fdopen with fclose or rpl_fclose. */ 423/* For -Wmismatched-dealloc: Associate fdopen with fclose or rpl_fclose. */
376# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2 424# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
377_GL_FUNCDECL_SYS (fdopen, FILE *, 425_GL_FUNCDECL_SYS (fdopen, FILE *,
378 (int fd, const char *mode) 426 (int fd, const char *mode),
379 _GL_ATTRIBUTE_NOTHROW
380 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1) 427 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)
381 _GL_ATTRIBUTE_MALLOC); 428 _GL_ATTRIBUTE_MALLOC
429 _GL_ATTRIBUTE_NODISCARD)
430 _GL_ATTRIBUTE_NOTHROW;
382# else 431# else
383_GL_FUNCDECL_SYS (fdopen, FILE *, 432_GL_FUNCDECL_SYS (fdopen, FILE *,
384 (int fd, const char *mode) 433 (int fd, const char *mode),
385 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1) 434 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)
386 _GL_ATTRIBUTE_MALLOC); 435 _GL_ATTRIBUTE_MALLOC
436 _GL_ATTRIBUTE_NODISCARD);
387# endif 437# endif
388# endif 438# endif
389_GL_CXXALIAS_SYS (fdopen, FILE *, (int fd, const char *mode)); 439_GL_CXXALIAS_SYS (fdopen, FILE *, (int fd, const char *mode));
390# endif 440# endif
391_GL_CXXALIASWARN (fdopen); 441_GL_CXXALIASWARN (fdopen);
392#else 442#else
393# if @GNULIB_FCLOSE@ && __GNUC__ >= 11 && !defined fdopen 443# if @GNULIB_FCLOSE@ && (__GNUC__ >= 11 && !defined __clang__) && !defined fdopen
394/* For -Wmismatched-dealloc: Associate fdopen with fclose or rpl_fclose. */ 444/* For -Wmismatched-dealloc: Associate fdopen with fclose or rpl_fclose. */
395# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2 445# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
396_GL_FUNCDECL_SYS (fdopen, FILE *, 446_GL_FUNCDECL_SYS (fdopen, FILE *,
397 (int fd, const char *mode) 447 (int fd, const char *mode),
398 _GL_ATTRIBUTE_NOTHROW
399 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1) 448 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)
400 _GL_ATTRIBUTE_MALLOC); 449 _GL_ATTRIBUTE_MALLOC)
450 _GL_ATTRIBUTE_NOTHROW;
401# else 451# else
402_GL_FUNCDECL_SYS (fdopen, FILE *, 452_GL_FUNCDECL_SYS (fdopen, FILE *,
403 (int fd, const char *mode) 453 (int fd, const char *mode),
404 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1) 454 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)
405 _GL_ATTRIBUTE_MALLOC); 455 _GL_ATTRIBUTE_MALLOC);
406# endif 456# endif
@@ -438,7 +488,7 @@ _GL_CXXALIASWARN (fdopen);
438# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 488# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
439# define fflush rpl_fflush 489# define fflush rpl_fflush
440# endif 490# endif
441_GL_FUNCDECL_RPL (fflush, int, (FILE *gl_stream)); 491_GL_FUNCDECL_RPL (fflush, int, (FILE *gl_stream), );
442_GL_CXXALIAS_RPL (fflush, int, (FILE *gl_stream)); 492_GL_CXXALIAS_RPL (fflush, int, (FILE *gl_stream));
443# else 493# else
444_GL_CXXALIAS_SYS (fflush, int, (FILE *gl_stream)); 494_GL_CXXALIAS_SYS (fflush, int, (FILE *gl_stream));
@@ -459,7 +509,7 @@ _GL_WARN_ON_USE (fflush, "fflush is not always POSIX compliant - "
459# undef fgetc 509# undef fgetc
460# define fgetc rpl_fgetc 510# define fgetc rpl_fgetc
461# endif 511# endif
462_GL_FUNCDECL_RPL (fgetc, int, (FILE *stream) _GL_ARG_NONNULL ((1))); 512_GL_FUNCDECL_RPL (fgetc, int, (FILE *stream), _GL_ARG_NONNULL ((1)));
463_GL_CXXALIAS_RPL (fgetc, int, (FILE *stream)); 513_GL_CXXALIAS_RPL (fgetc, int, (FILE *stream));
464# else 514# else
465_GL_CXXALIAS_SYS (fgetc, int, (FILE *stream)); 515_GL_CXXALIAS_SYS (fgetc, int, (FILE *stream));
@@ -476,8 +526,8 @@ _GL_CXXALIASWARN (fgetc);
476# define fgets rpl_fgets 526# define fgets rpl_fgets
477# endif 527# endif
478_GL_FUNCDECL_RPL (fgets, char *, 528_GL_FUNCDECL_RPL (fgets, char *,
479 (char *restrict s, int n, FILE *restrict stream) 529 (char *restrict s, int n, FILE *restrict stream),
480 _GL_ARG_NONNULL ((1, 3))); 530 _GL_ARG_NONNULL ((1, 3)) _GL_ATTRIBUTE_NODISCARD);
481_GL_CXXALIAS_RPL (fgets, char *, 531_GL_CXXALIAS_RPL (fgets, char *,
482 (char *restrict s, int n, FILE *restrict stream)); 532 (char *restrict s, int n, FILE *restrict stream));
483# else 533# else
@@ -513,17 +563,18 @@ _GL_CXXALIASWARN (fileno);
513# define fopen rpl_fopen 563# define fopen rpl_fopen
514# endif 564# endif
515_GL_FUNCDECL_RPL (fopen, FILE *, 565_GL_FUNCDECL_RPL (fopen, FILE *,
516 (const char *restrict filename, const char *restrict mode) 566 (const char *restrict filename, const char *restrict mode),
517 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1) 567 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)
518 _GL_ATTRIBUTE_MALLOC); 568 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_NODISCARD);
519_GL_CXXALIAS_RPL (fopen, FILE *, 569_GL_CXXALIAS_RPL (fopen, FILE *,
520 (const char *restrict filename, const char *restrict mode)); 570 (const char *restrict filename, const char *restrict mode));
521# else 571# else
522# if __GNUC__ >= 11 572# if __GNUC__ >= 11 && !defined __clang__
523/* For -Wmismatched-dealloc: Associate fopen with fclose or rpl_fclose. */ 573/* For -Wmismatched-dealloc: Associate fopen with fclose or rpl_fclose. */
524_GL_FUNCDECL_SYS (fopen, FILE *, 574_GL_FUNCDECL_SYS (fopen, FILE *,
525 (const char *restrict filename, const char *restrict mode) 575 (const char *restrict filename, const char *restrict mode),
526 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)); 576 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)
577 _GL_ATTRIBUTE_NODISCARD);
527# endif 578# endif
528_GL_CXXALIAS_SYS (fopen, FILE *, 579_GL_CXXALIAS_SYS (fopen, FILE *,
529 (const char *restrict filename, const char *restrict mode)); 580 (const char *restrict filename, const char *restrict mode));
@@ -532,10 +583,10 @@ _GL_CXXALIAS_SYS (fopen, FILE *,
532_GL_CXXALIASWARN (fopen); 583_GL_CXXALIASWARN (fopen);
533# endif 584# endif
534#else 585#else
535# if @GNULIB_FCLOSE@ && __GNUC__ >= 11 && !defined fopen 586# if @GNULIB_FCLOSE@ && (__GNUC__ >= 11 && !defined __clang__) && !defined fopen
536/* For -Wmismatched-dealloc: Associate fopen with fclose or rpl_fclose. */ 587/* For -Wmismatched-dealloc: Associate fopen with fclose or rpl_fclose. */
537_GL_FUNCDECL_SYS (fopen, FILE *, 588_GL_FUNCDECL_SYS (fopen, FILE *,
538 (const char *restrict filename, const char *restrict mode) 589 (const char *restrict filename, const char *restrict mode),
539 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)); 590 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1));
540# endif 591# endif
541# if defined GNULIB_POSIXCHECK 592# if defined GNULIB_POSIXCHECK
@@ -546,7 +597,26 @@ _GL_WARN_ON_USE (fopen, "fopen on native Windows platforms is not POSIX complian
546# endif 597# endif
547#endif 598#endif
548 599
600#if @GNULIB_FZPRINTF@
601/* Prints formatted output to stream FP.
602 Returns the number of bytes written to the stream. Upon failure,
603 returns -1 with the stream's error indicator set.
604 Failure cause EOVERFLOW can only occur when a width > INT_MAX is used.
605 Therefore, if the format string is valid and does not use %ls/%lc
606 directives nor widths, the only possible failure causes are ENOMEM
607 and the possible failure causes from fwrite(). */
608_GL_FUNCDECL_SYS (fzprintf, off64_t,
609 (FILE *restrict fp, const char *restrict format, ...),
610 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
611 _GL_ARG_NONNULL ((1, 2)));
612_GL_CXXALIAS_SYS (fzprintf, off64_t,
613 (FILE *restrict fp, const char *restrict format, ...));
614#endif
615
549#if @GNULIB_FPRINTF_POSIX@ || @GNULIB_FPRINTF@ 616#if @GNULIB_FPRINTF_POSIX@ || @GNULIB_FPRINTF@
617/* Prints formatted output to stream FP.
618 Returns the number of bytes written to the stream. Upon failure,
619 returns a negative value with the stream's error indicator set. */
550# if (@GNULIB_FPRINTF_POSIX@ && @REPLACE_FPRINTF@) \ 620# if (@GNULIB_FPRINTF_POSIX@ && @REPLACE_FPRINTF@) \
551 || (@GNULIB_FPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)) 621 || (@GNULIB_FPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@))
552# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 622# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -555,12 +625,12 @@ _GL_WARN_ON_USE (fopen, "fopen on native Windows platforms is not POSIX complian
555# define GNULIB_overrides_fprintf 1 625# define GNULIB_overrides_fprintf 1
556# if @GNULIB_FPRINTF_POSIX@ || @GNULIB_VFPRINTF_POSIX@ 626# if @GNULIB_FPRINTF_POSIX@ || @GNULIB_VFPRINTF_POSIX@
557_GL_FUNCDECL_RPL (fprintf, int, 627_GL_FUNCDECL_RPL (fprintf, int,
558 (FILE *restrict fp, const char *restrict format, ...) 628 (FILE *restrict fp, const char *restrict format, ...),
559 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) 629 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
560 _GL_ARG_NONNULL ((1, 2))); 630 _GL_ARG_NONNULL ((1, 2)));
561# else 631# else
562_GL_FUNCDECL_RPL (fprintf, int, 632_GL_FUNCDECL_RPL (fprintf, int,
563 (FILE *restrict fp, const char *restrict format, ...) 633 (FILE *restrict fp, const char *restrict format, ...),
564 _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (2, 3) 634 _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (2, 3)
565 _GL_ARG_NONNULL ((1, 2))); 635 _GL_ARG_NONNULL ((1, 2)));
566# endif 636# endif
@@ -573,6 +643,11 @@ _GL_CXXALIAS_SYS (fprintf, int,
573# if __GLIBC__ >= 2 643# if __GLIBC__ >= 2
574_GL_CXXALIASWARN (fprintf); 644_GL_CXXALIASWARN (fprintf);
575# endif 645# endif
646#elif defined __MINGW32__ && !defined _UCRT && __USE_MINGW_ANSI_STDIO
647# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
648# undef fprintf
649# define fprintf gl_consolesafe_fprintf
650# endif
576#endif 651#endif
577#if !@GNULIB_FPRINTF_POSIX@ && defined GNULIB_POSIXCHECK 652#if !@GNULIB_FPRINTF_POSIX@ && defined GNULIB_POSIXCHECK
578# if !GNULIB_overrides_fprintf 653# if !GNULIB_overrides_fprintf
@@ -595,15 +670,17 @@ _GL_WARN_ON_USE (fprintf, "fprintf is not always POSIX compliant - "
595# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 670# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
596# define fpurge rpl_fpurge 671# define fpurge rpl_fpurge
597# endif 672# endif
598_GL_FUNCDECL_RPL (fpurge, int, (FILE *gl_stream) _GL_ARG_NONNULL ((1))); 673_GL_FUNCDECL_RPL (fpurge, int, (FILE *gl_stream), _GL_ARG_NONNULL ((1)));
599_GL_CXXALIAS_RPL (fpurge, int, (FILE *gl_stream)); 674_GL_CXXALIAS_RPL (fpurge, int, (FILE *gl_stream));
600# else 675# else
601# if !@HAVE_DECL_FPURGE@ 676# if !@HAVE_DECL_FPURGE@
602_GL_FUNCDECL_SYS (fpurge, int, (FILE *gl_stream) _GL_ARG_NONNULL ((1))); 677_GL_FUNCDECL_SYS (fpurge, int, (FILE *gl_stream), _GL_ARG_NONNULL ((1)));
603# endif 678# endif
604_GL_CXXALIAS_SYS (fpurge, int, (FILE *gl_stream)); 679_GL_CXXALIAS_SYS (fpurge, int, (FILE *gl_stream));
605# endif 680# endif
681# if __GLIBC__ >= 2
606_GL_CXXALIASWARN (fpurge); 682_GL_CXXALIASWARN (fpurge);
683# endif
607#elif defined GNULIB_POSIXCHECK 684#elif defined GNULIB_POSIXCHECK
608# undef fpurge 685# undef fpurge
609# if HAVE_RAW_DECL_FPURGE 686# if HAVE_RAW_DECL_FPURGE
@@ -618,7 +695,7 @@ _GL_WARN_ON_USE (fpurge, "fpurge is not always present - "
618# undef fputc 695# undef fputc
619# define fputc rpl_fputc 696# define fputc rpl_fputc
620# endif 697# endif
621_GL_FUNCDECL_RPL (fputc, int, (int c, FILE *stream) _GL_ARG_NONNULL ((2))); 698_GL_FUNCDECL_RPL (fputc, int, (int c, FILE *stream), _GL_ARG_NONNULL ((2)));
622_GL_CXXALIAS_RPL (fputc, int, (int c, FILE *stream)); 699_GL_CXXALIAS_RPL (fputc, int, (int c, FILE *stream));
623# else 700# else
624_GL_CXXALIAS_SYS (fputc, int, (int c, FILE *stream)); 701_GL_CXXALIAS_SYS (fputc, int, (int c, FILE *stream));
@@ -635,7 +712,7 @@ _GL_CXXALIASWARN (fputc);
635# define fputs rpl_fputs 712# define fputs rpl_fputs
636# endif 713# endif
637_GL_FUNCDECL_RPL (fputs, int, 714_GL_FUNCDECL_RPL (fputs, int,
638 (const char *restrict string, FILE *restrict stream) 715 (const char *restrict string, FILE *restrict stream),
639 _GL_ARG_NONNULL ((1, 2))); 716 _GL_ARG_NONNULL ((1, 2)));
640_GL_CXXALIAS_RPL (fputs, int, 717_GL_CXXALIAS_RPL (fputs, int,
641 (const char *restrict string, FILE *restrict stream)); 718 (const char *restrict string, FILE *restrict stream));
@@ -656,8 +733,8 @@ _GL_CXXALIASWARN (fputs);
656# endif 733# endif
657_GL_FUNCDECL_RPL (fread, size_t, 734_GL_FUNCDECL_RPL (fread, size_t,
658 (void *restrict ptr, size_t s, size_t n, 735 (void *restrict ptr, size_t s, size_t n,
659 FILE *restrict stream) 736 FILE *restrict stream),
660 _GL_ARG_NONNULL ((4))); 737 _GL_ARG_NONNULL ((4)) _GL_ATTRIBUTE_NODISCARD);
661_GL_CXXALIAS_RPL (fread, size_t, 738_GL_CXXALIAS_RPL (fread, size_t,
662 (void *restrict ptr, size_t s, size_t n, 739 (void *restrict ptr, size_t s, size_t n,
663 FILE *restrict stream)); 740 FILE *restrict stream));
@@ -679,8 +756,8 @@ _GL_CXXALIASWARN (fread);
679# endif 756# endif
680_GL_FUNCDECL_RPL (freopen, FILE *, 757_GL_FUNCDECL_RPL (freopen, FILE *,
681 (const char *restrict filename, const char *restrict mode, 758 (const char *restrict filename, const char *restrict mode,
682 FILE *restrict stream) 759 FILE *restrict stream),
683 _GL_ARG_NONNULL ((2, 3))); 760 _GL_ARG_NONNULL ((2, 3)) _GL_ATTRIBUTE_NODISCARD);
684_GL_CXXALIAS_RPL (freopen, FILE *, 761_GL_CXXALIAS_RPL (freopen, FILE *,
685 (const char *restrict filename, const char *restrict mode, 762 (const char *restrict filename, const char *restrict mode,
686 FILE *restrict stream)); 763 FILE *restrict stream));
@@ -707,9 +784,9 @@ _GL_WARN_ON_USE (freopen,
707# define fscanf rpl_fscanf 784# define fscanf rpl_fscanf
708# endif 785# endif
709_GL_FUNCDECL_RPL (fscanf, int, 786_GL_FUNCDECL_RPL (fscanf, int,
710 (FILE *restrict stream, const char *restrict format, ...) 787 (FILE *restrict stream, const char *restrict format, ...),
711 _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (2, 3) 788 _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (2, 3)
712 _GL_ARG_NONNULL ((1, 2))); 789 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_NODISCARD);
713_GL_CXXALIAS_RPL (fscanf, int, 790_GL_CXXALIAS_RPL (fscanf, int,
714 (FILE *restrict stream, const char *restrict format, ...)); 791 (FILE *restrict stream, const char *restrict format, ...));
715# else 792# else
@@ -763,7 +840,7 @@ _GL_CXXALIASWARN (fscanf);
763# undef fseek 840# undef fseek
764# define fseek rpl_fseek 841# define fseek rpl_fseek
765# endif 842# endif
766_GL_FUNCDECL_RPL (fseek, int, (FILE *fp, long offset, int whence) 843_GL_FUNCDECL_RPL (fseek, int, (FILE *fp, long offset, int whence),
767 _GL_ARG_NONNULL ((1))); 844 _GL_ARG_NONNULL ((1)));
768_GL_CXXALIAS_RPL (fseek, int, (FILE *fp, long offset, int whence)); 845_GL_CXXALIAS_RPL (fseek, int, (FILE *fp, long offset, int whence));
769# else 846# else
@@ -786,12 +863,12 @@ _GL_CXXALIASWARN (fseek);
786# undef fseeko 863# undef fseeko
787# define fseeko rpl_fseeko 864# define fseeko rpl_fseeko
788# endif 865# endif
789_GL_FUNCDECL_RPL (fseeko, int, (FILE *fp, off_t offset, int whence) 866_GL_FUNCDECL_RPL (fseeko, int, (FILE *fp, off_t offset, int whence),
790 _GL_ARG_NONNULL ((1))); 867 _GL_ARG_NONNULL ((1)));
791_GL_CXXALIAS_RPL (fseeko, int, (FILE *fp, off_t offset, int whence)); 868_GL_CXXALIAS_RPL (fseeko, int, (FILE *fp, off_t offset, int whence));
792# else 869# else
793# if ! @HAVE_DECL_FSEEKO@ 870# if ! @HAVE_DECL_FSEEKO@
794_GL_FUNCDECL_SYS (fseeko, int, (FILE *fp, off_t offset, int whence) 871_GL_FUNCDECL_SYS (fseeko, int, (FILE *fp, off_t offset, int whence),
795 _GL_ARG_NONNULL ((1))); 872 _GL_ARG_NONNULL ((1)));
796# endif 873# endif
797_GL_CXXALIAS_SYS (fseeko, int, (FILE *fp, off_t offset, int whence)); 874_GL_CXXALIAS_SYS (fseeko, int, (FILE *fp, off_t offset, int whence));
@@ -829,7 +906,8 @@ _GL_WARN_ON_USE (fseek, "fseek cannot handle files larger than 4 GB "
829# undef ftell 906# undef ftell
830# define ftell rpl_ftell 907# define ftell rpl_ftell
831# endif 908# endif
832_GL_FUNCDECL_RPL (ftell, long, (FILE *fp) _GL_ARG_NONNULL ((1))); 909_GL_FUNCDECL_RPL (ftell, long, (FILE *fp),
910 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
833_GL_CXXALIAS_RPL (ftell, long, (FILE *fp)); 911_GL_CXXALIAS_RPL (ftell, long, (FILE *fp));
834# else 912# else
835_GL_CXXALIAS_SYS (ftell, long, (FILE *fp)); 913_GL_CXXALIAS_SYS (ftell, long, (FILE *fp));
@@ -849,11 +927,13 @@ _GL_CXXALIASWARN (ftell);
849# undef ftello 927# undef ftello
850# define ftello rpl_ftello 928# define ftello rpl_ftello
851# endif 929# endif
852_GL_FUNCDECL_RPL (ftello, off_t, (FILE *fp) _GL_ARG_NONNULL ((1))); 930_GL_FUNCDECL_RPL (ftello, off_t, (FILE *fp),
931 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
853_GL_CXXALIAS_RPL (ftello, off_t, (FILE *fp)); 932_GL_CXXALIAS_RPL (ftello, off_t, (FILE *fp));
854# else 933# else
855# if ! @HAVE_DECL_FTELLO@ 934# if ! @HAVE_DECL_FTELLO@
856_GL_FUNCDECL_SYS (ftello, off_t, (FILE *fp) _GL_ARG_NONNULL ((1))); 935_GL_FUNCDECL_SYS (ftello, off_t, (FILE *fp),
936 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
857# endif 937# endif
858_GL_CXXALIAS_SYS (ftello, off_t, (FILE *fp)); 938_GL_CXXALIAS_SYS (ftello, off_t, (FILE *fp));
859# endif 939# endif
@@ -886,7 +966,7 @@ _GL_WARN_ON_USE (ftell, "ftell cannot handle files larger than 4 GB "
886# endif 966# endif
887_GL_FUNCDECL_RPL (fwrite, size_t, 967_GL_FUNCDECL_RPL (fwrite, size_t,
888 (const void *restrict ptr, size_t s, size_t n, 968 (const void *restrict ptr, size_t s, size_t n,
889 FILE *restrict stream) 969 FILE *restrict stream),
890 _GL_ARG_NONNULL ((1, 4))); 970 _GL_ARG_NONNULL ((1, 4)));
891_GL_CXXALIAS_RPL (fwrite, size_t, 971_GL_CXXALIAS_RPL (fwrite, size_t,
892 (const void *restrict ptr, size_t s, size_t n, 972 (const void *restrict ptr, size_t s, size_t n,
@@ -901,9 +981,9 @@ _GL_CXXALIAS_SYS (fwrite, size_t,
901 which sometimes causes an unwanted diagnostic for fwrite calls. 981 which sometimes causes an unwanted diagnostic for fwrite calls.
902 This affects only function declaration attributes under certain 982 This affects only function declaration attributes under certain
903 versions of gcc and clang, and is not needed for C++. */ 983 versions of gcc and clang, and is not needed for C++. */
904# if (0 < __USE_FORTIFY_LEVEL \ 984# if (0 < __USE_FORTIFY_LEVEL \
905 && __GLIBC__ == 2 && 4 <= __GLIBC_MINOR__ && __GLIBC_MINOR__ <= 15 \ 985 && __GLIBC__ == 2 && 4 <= __GLIBC_MINOR__ && __GLIBC_MINOR__ <= 15 \
906 && 3 < __GNUC__ + (4 <= __GNUC_MINOR__) \ 986 && (3 < __GNUC__ + (4 <= __GNUC_MINOR__) || defined __clang__) \
907 && !defined __cplusplus) 987 && !defined __cplusplus)
908# undef fwrite 988# undef fwrite
909# undef fwrite_unlocked 989# undef fwrite_unlocked
@@ -922,6 +1002,11 @@ _GL_EXTERN_C size_t __REDIRECT (rpl_fwrite_unlocked,
922# if __GLIBC__ >= 2 1002# if __GLIBC__ >= 2
923_GL_CXXALIASWARN (fwrite); 1003_GL_CXXALIASWARN (fwrite);
924# endif 1004# endif
1005#elif (defined _WIN32 && !defined __CYGWIN__) && !defined _UCRT
1006# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1007# undef fwrite
1008# define fwrite gl_consolesafe_fwrite
1009# endif
925#endif 1010#endif
926 1011
927#if @GNULIB_GETC@ 1012#if @GNULIB_GETC@
@@ -930,7 +1015,7 @@ _GL_CXXALIASWARN (fwrite);
930# undef getc 1015# undef getc
931# define getc rpl_fgetc 1016# define getc rpl_fgetc
932# endif 1017# endif
933_GL_FUNCDECL_RPL (fgetc, int, (FILE *stream) _GL_ARG_NONNULL ((1))); 1018_GL_FUNCDECL_RPL (fgetc, int, (FILE *stream), _GL_ARG_NONNULL ((1)));
934_GL_CXXALIAS_RPL_1 (getc, rpl_fgetc, int, (FILE *stream)); 1019_GL_CXXALIAS_RPL_1 (getc, rpl_fgetc, int, (FILE *stream));
935# else 1020# else
936_GL_CXXALIAS_SYS (getc, int, (FILE *stream)); 1021_GL_CXXALIAS_SYS (getc, int, (FILE *stream));
@@ -946,7 +1031,7 @@ _GL_CXXALIASWARN (getc);
946# undef getchar 1031# undef getchar
947# define getchar rpl_getchar 1032# define getchar rpl_getchar
948# endif 1033# endif
949_GL_FUNCDECL_RPL (getchar, int, (void)); 1034_GL_FUNCDECL_RPL (getchar, int, (void), );
950_GL_CXXALIAS_RPL (getchar, int, (void)); 1035_GL_CXXALIAS_RPL (getchar, int, (void));
951# else 1036# else
952_GL_CXXALIAS_SYS (getchar, int, (void)); 1037_GL_CXXALIAS_SYS (getchar, int, (void));
@@ -971,8 +1056,8 @@ _GL_CXXALIASWARN (getchar);
971_GL_FUNCDECL_RPL (getdelim, ssize_t, 1056_GL_FUNCDECL_RPL (getdelim, ssize_t,
972 (char **restrict lineptr, size_t *restrict linesize, 1057 (char **restrict lineptr, size_t *restrict linesize,
973 int delimiter, 1058 int delimiter,
974 FILE *restrict stream) 1059 FILE *restrict stream),
975 _GL_ARG_NONNULL ((1, 2, 4))); 1060 _GL_ARG_NONNULL ((1, 2, 4)) _GL_ATTRIBUTE_NODISCARD);
976_GL_CXXALIAS_RPL (getdelim, ssize_t, 1061_GL_CXXALIAS_RPL (getdelim, ssize_t,
977 (char **restrict lineptr, size_t *restrict linesize, 1062 (char **restrict lineptr, size_t *restrict linesize,
978 int delimiter, 1063 int delimiter,
@@ -982,8 +1067,8 @@ _GL_CXXALIAS_RPL (getdelim, ssize_t,
982_GL_FUNCDECL_SYS (getdelim, ssize_t, 1067_GL_FUNCDECL_SYS (getdelim, ssize_t,
983 (char **restrict lineptr, size_t *restrict linesize, 1068 (char **restrict lineptr, size_t *restrict linesize,
984 int delimiter, 1069 int delimiter,
985 FILE *restrict stream) 1070 FILE *restrict stream),
986 _GL_ARG_NONNULL ((1, 2, 4))); 1071 _GL_ARG_NONNULL ((1, 2, 4)) _GL_ATTRIBUTE_NODISCARD);
987# endif 1072# endif
988_GL_CXXALIAS_SYS (getdelim, ssize_t, 1073_GL_CXXALIAS_SYS (getdelim, ssize_t,
989 (char **restrict lineptr, size_t *restrict linesize, 1074 (char **restrict lineptr, size_t *restrict linesize,
@@ -1015,8 +1100,8 @@ _GL_WARN_ON_USE (getdelim, "getdelim is unportable - "
1015# endif 1100# endif
1016_GL_FUNCDECL_RPL (getline, ssize_t, 1101_GL_FUNCDECL_RPL (getline, ssize_t,
1017 (char **restrict lineptr, size_t *restrict linesize, 1102 (char **restrict lineptr, size_t *restrict linesize,
1018 FILE *restrict stream) 1103 FILE *restrict stream),
1019 _GL_ARG_NONNULL ((1, 2, 3))); 1104 _GL_ARG_NONNULL ((1, 2, 3)) _GL_ATTRIBUTE_NODISCARD);
1020_GL_CXXALIAS_RPL (getline, ssize_t, 1105_GL_CXXALIAS_RPL (getline, ssize_t,
1021 (char **restrict lineptr, size_t *restrict linesize, 1106 (char **restrict lineptr, size_t *restrict linesize,
1022 FILE *restrict stream)); 1107 FILE *restrict stream));
@@ -1024,8 +1109,8 @@ _GL_CXXALIAS_RPL (getline, ssize_t,
1024# if !@HAVE_DECL_GETLINE@ 1109# if !@HAVE_DECL_GETLINE@
1025_GL_FUNCDECL_SYS (getline, ssize_t, 1110_GL_FUNCDECL_SYS (getline, ssize_t,
1026 (char **restrict lineptr, size_t *restrict linesize, 1111 (char **restrict lineptr, size_t *restrict linesize,
1027 FILE *restrict stream) 1112 FILE *restrict stream),
1028 _GL_ARG_NONNULL ((1, 2, 3))); 1113 _GL_ARG_NONNULL ((1, 2, 3)) _GL_ATTRIBUTE_NODISCARD);
1029# endif 1114# endif
1030_GL_CXXALIAS_SYS (getline, ssize_t, 1115_GL_CXXALIAS_SYS (getline, ssize_t,
1031 (char **restrict lineptr, size_t *restrict linesize, 1116 (char **restrict lineptr, size_t *restrict linesize,
@@ -1064,7 +1149,7 @@ _GL_CXXALIAS_MDA (getw, int, (FILE *restrict stream));
1064# if @HAVE_DECL_GETW@ 1149# if @HAVE_DECL_GETW@
1065# if defined __APPLE__ && defined __MACH__ 1150# if defined __APPLE__ && defined __MACH__
1066/* The presence of the declaration depends on _POSIX_C_SOURCE. */ 1151/* The presence of the declaration depends on _POSIX_C_SOURCE. */
1067_GL_FUNCDECL_SYS (getw, int, (FILE *restrict stream)); 1152_GL_FUNCDECL_SYS (getw, int, (FILE *restrict stream), );
1068# endif 1153# endif
1069_GL_CXXALIAS_SYS (getw, int, (FILE *restrict stream)); 1154_GL_CXXALIAS_SYS (getw, int, (FILE *restrict stream));
1070# endif 1155# endif
@@ -1074,19 +1159,45 @@ _GL_CXXALIASWARN (getw);
1074# endif 1159# endif
1075#endif 1160#endif
1076 1161
1162#if @GNULIB_OBSTACK_ZPRINTF@
1163struct obstack;
1164/* Grows an obstack with formatted output. Returns the number of
1165 bytes added to OBS. No trailing nul byte is added, and the
1166 object should be closed with obstack_finish before use.
1167 Upon memory allocation error, calls obstack_alloc_failed_handler.
1168 Upon other error, returns -1 with errno set.
1169
1170 Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
1171 Therefore, if the format string is valid and does not use %ls/%lc
1172 directives nor widths, the only possible failure code is through
1173 obstack_alloc_failed_handler. */
1174_GL_FUNCDECL_SYS (obstack_zprintf, ptrdiff_t,
1175 (struct obstack *obs, const char *format, ...),
1176 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
1177 _GL_ARG_NONNULL ((1, 2)));
1178_GL_CXXALIAS_SYS (obstack_zprintf, ptrdiff_t,
1179 (struct obstack *obs, const char *format, ...));
1180_GL_FUNCDECL_SYS (obstack_vzprintf, ptrdiff_t,
1181 (struct obstack *obs, const char *format, va_list args),
1182 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
1183 _GL_ARG_NONNULL ((1, 2)));
1184_GL_CXXALIAS_SYS (obstack_vzprintf, ptrdiff_t,
1185 (struct obstack *obs, const char *format, va_list args));
1186#endif
1187
1077#if @GNULIB_OBSTACK_PRINTF@ || @GNULIB_OBSTACK_PRINTF_POSIX@ 1188#if @GNULIB_OBSTACK_PRINTF@ || @GNULIB_OBSTACK_PRINTF_POSIX@
1078struct obstack; 1189struct obstack;
1079/* Grow an obstack with formatted output. Return the number of 1190/* Grows an obstack with formatted output. Returns the number of
1080 bytes added to OBS. No trailing nul byte is added, and the 1191 bytes added to OBS. No trailing nul byte is added, and the
1081 object should be closed with obstack_finish before use. Upon 1192 object should be closed with obstack_finish before use.
1082 memory allocation error, call obstack_alloc_failed_handler. Upon 1193 Upon memory allocation error, calls obstack_alloc_failed_handler.
1083 other error, return -1. */ 1194 Upon other error, returns -1. */
1084# if @REPLACE_OBSTACK_PRINTF@ 1195# if @REPLACE_OBSTACK_PRINTF@
1085# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1196# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1086# define obstack_printf rpl_obstack_printf 1197# define obstack_printf rpl_obstack_printf
1087# endif 1198# endif
1088_GL_FUNCDECL_RPL (obstack_printf, int, 1199_GL_FUNCDECL_RPL (obstack_printf, int,
1089 (struct obstack *obs, const char *format, ...) 1200 (struct obstack *obs, const char *format, ...),
1090 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) 1201 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
1091 _GL_ARG_NONNULL ((1, 2))); 1202 _GL_ARG_NONNULL ((1, 2)));
1092_GL_CXXALIAS_RPL (obstack_printf, int, 1203_GL_CXXALIAS_RPL (obstack_printf, int,
@@ -1094,7 +1205,7 @@ _GL_CXXALIAS_RPL (obstack_printf, int,
1094# else 1205# else
1095# if !@HAVE_DECL_OBSTACK_PRINTF@ 1206# if !@HAVE_DECL_OBSTACK_PRINTF@
1096_GL_FUNCDECL_SYS (obstack_printf, int, 1207_GL_FUNCDECL_SYS (obstack_printf, int,
1097 (struct obstack *obs, const char *format, ...) 1208 (struct obstack *obs, const char *format, ...),
1098 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) 1209 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
1099 _GL_ARG_NONNULL ((1, 2))); 1210 _GL_ARG_NONNULL ((1, 2)));
1100# endif 1211# endif
@@ -1107,7 +1218,7 @@ _GL_CXXALIASWARN (obstack_printf);
1107# define obstack_vprintf rpl_obstack_vprintf 1218# define obstack_vprintf rpl_obstack_vprintf
1108# endif 1219# endif
1109_GL_FUNCDECL_RPL (obstack_vprintf, int, 1220_GL_FUNCDECL_RPL (obstack_vprintf, int,
1110 (struct obstack *obs, const char *format, va_list args) 1221 (struct obstack *obs, const char *format, va_list args),
1111 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) 1222 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
1112 _GL_ARG_NONNULL ((1, 2))); 1223 _GL_ARG_NONNULL ((1, 2)));
1113_GL_CXXALIAS_RPL (obstack_vprintf, int, 1224_GL_CXXALIAS_RPL (obstack_vprintf, int,
@@ -1115,7 +1226,7 @@ _GL_CXXALIAS_RPL (obstack_vprintf, int,
1115# else 1226# else
1116# if !@HAVE_DECL_OBSTACK_PRINTF@ 1227# if !@HAVE_DECL_OBSTACK_PRINTF@
1117_GL_FUNCDECL_SYS (obstack_vprintf, int, 1228_GL_FUNCDECL_SYS (obstack_vprintf, int,
1118 (struct obstack *obs, const char *format, va_list args) 1229 (struct obstack *obs, const char *format, va_list args),
1119 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) 1230 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
1120 _GL_ARG_NONNULL ((1, 2))); 1231 _GL_ARG_NONNULL ((1, 2)));
1121# endif 1232# endif
@@ -1127,7 +1238,7 @@ _GL_CXXALIASWARN (obstack_vprintf);
1127 1238
1128#if @GNULIB_PCLOSE@ 1239#if @GNULIB_PCLOSE@
1129# if !@HAVE_PCLOSE@ 1240# if !@HAVE_PCLOSE@
1130_GL_FUNCDECL_SYS (pclose, int, (FILE *stream) _GL_ARG_NONNULL ((1))); 1241_GL_FUNCDECL_SYS (pclose, int, (FILE *stream), _GL_ARG_NONNULL ((1)));
1131# endif 1242# endif
1132_GL_CXXALIAS_SYS (pclose, int, (FILE *stream)); 1243_GL_CXXALIAS_SYS (pclose, int, (FILE *stream));
1133_GL_CXXALIASWARN (pclose); 1244_GL_CXXALIASWARN (pclose);
@@ -1147,7 +1258,7 @@ _GL_WARN_ON_USE (pclose, "pclose is unportable - "
1147# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1258# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1148# define perror rpl_perror 1259# define perror rpl_perror
1149# endif 1260# endif
1150_GL_FUNCDECL_RPL (perror, void, (const char *string)); 1261_GL_FUNCDECL_RPL (perror, void, (const char *string), );
1151_GL_CXXALIAS_RPL (perror, void, (const char *string)); 1262_GL_CXXALIAS_RPL (perror, void, (const char *string));
1152# else 1263# else
1153_GL_CXXALIAS_SYS (perror, void, (const char *string)); 1264_GL_CXXALIAS_SYS (perror, void, (const char *string));
@@ -1169,25 +1280,26 @@ _GL_WARN_ON_USE (perror, "perror is not always POSIX compliant - "
1169# define popen rpl_popen 1280# define popen rpl_popen
1170# endif 1281# endif
1171_GL_FUNCDECL_RPL (popen, FILE *, 1282_GL_FUNCDECL_RPL (popen, FILE *,
1172 (const char *cmd, const char *mode) 1283 (const char *cmd, const char *mode),
1173 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1) 1284 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1)
1174 _GL_ATTRIBUTE_MALLOC); 1285 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_NODISCARD);
1175_GL_CXXALIAS_RPL (popen, FILE *, (const char *cmd, const char *mode)); 1286_GL_CXXALIAS_RPL (popen, FILE *, (const char *cmd, const char *mode));
1176# else 1287# else
1177# if !@HAVE_POPEN@ || __GNUC__ >= 11 1288# if !@HAVE_POPEN@ || (__GNUC__ >= 11 && !defined __clang__)
1178_GL_FUNCDECL_SYS (popen, FILE *, 1289_GL_FUNCDECL_SYS (popen, FILE *,
1179 (const char *cmd, const char *mode) 1290 (const char *cmd, const char *mode),
1180 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1) 1291 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1)
1181 _GL_ATTRIBUTE_MALLOC); 1292 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_NODISCARD);
1182# endif 1293# endif
1183_GL_CXXALIAS_SYS (popen, FILE *, (const char *cmd, const char *mode)); 1294_GL_CXXALIAS_SYS (popen, FILE *, (const char *cmd, const char *mode));
1184# endif 1295# endif
1185_GL_CXXALIASWARN (popen); 1296_GL_CXXALIASWARN (popen);
1186#else 1297#else
1187# if @GNULIB_PCLOSE@ && __GNUC__ >= 11 && !defined popen 1298# if @GNULIB_PCLOSE@ \
1299 && (__GNUC__ >= 11 && !defined __clang__) && !defined popen
1188/* For -Wmismatched-dealloc: Associate popen with pclose or rpl_pclose. */ 1300/* For -Wmismatched-dealloc: Associate popen with pclose or rpl_pclose. */
1189_GL_FUNCDECL_SYS (popen, FILE *, 1301_GL_FUNCDECL_SYS (popen, FILE *,
1190 (const char *cmd, const char *mode) 1302 (const char *cmd, const char *mode),
1191 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1) 1303 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1)
1192 _GL_ATTRIBUTE_MALLOC); 1304 _GL_ATTRIBUTE_MALLOC);
1193# endif 1305# endif
@@ -1200,7 +1312,24 @@ _GL_WARN_ON_USE (popen, "popen is buggy on some platforms - "
1200# endif 1312# endif
1201#endif 1313#endif
1202 1314
1315#if @GNULIB_ZPRINTF@
1316/* Prints formatted output to standard output.
1317 Returns the number of bytes written to standard output. Upon failure,
1318 returns -1 with stdout's error indicator set.
1319 Failure cause EOVERFLOW can only occur when a width > INT_MAX is used.
1320 Therefore, if the format string is valid and does not use %ls/%lc
1321 directives nor widths, the only possible failure causes are ENOMEM
1322 and the possible failure causes from fwrite(). */
1323_GL_FUNCDECL_SYS (zprintf, off64_t, (const char *restrict format, ...),
1324 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 2)
1325 _GL_ARG_NONNULL ((1)));
1326_GL_CXXALIAS_SYS (zprintf, off64_t, (const char *restrict format, ...));
1327#endif
1328
1203#if @GNULIB_PRINTF_POSIX@ || @GNULIB_PRINTF@ 1329#if @GNULIB_PRINTF_POSIX@ || @GNULIB_PRINTF@
1330/* Prints formatted output to standard output.
1331 Returns the number of bytes written to standard output. Upon failure,
1332 returns a negative value with stdout's error indicator set. */
1204# if (@GNULIB_PRINTF_POSIX@ && @REPLACE_PRINTF@) \ 1333# if (@GNULIB_PRINTF_POSIX@ && @REPLACE_PRINTF@) \
1205 || (@GNULIB_PRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)) 1334 || (@GNULIB_PRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@))
1206# if defined __GNUC__ || defined __clang__ 1335# if defined __GNUC__ || defined __clang__
@@ -1212,14 +1341,14 @@ _GL_WARN_ON_USE (popen, "popen is buggy on some platforms - "
1212_GL_FUNCDECL_RPL_1 (__printf__, int, 1341_GL_FUNCDECL_RPL_1 (__printf__, int,
1213 (const char *restrict format, ...) 1342 (const char *restrict format, ...)
1214 __asm__ (@ASM_SYMBOL_PREFIX@ 1343 __asm__ (@ASM_SYMBOL_PREFIX@
1215 _GL_STDIO_MACROEXPAND_AND_STRINGIZE(rpl_printf)) 1344 _GL_STDIO_MACROEXPAND_AND_STRINGIZE(rpl_printf)),
1216 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 2) 1345 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 2)
1217 _GL_ARG_NONNULL ((1))); 1346 _GL_ARG_NONNULL ((1)));
1218# else 1347# else
1219_GL_FUNCDECL_RPL_1 (__printf__, int, 1348_GL_FUNCDECL_RPL_1 (__printf__, int,
1220 (const char *restrict format, ...) 1349 (const char *restrict format, ...)
1221 __asm__ (@ASM_SYMBOL_PREFIX@ 1350 __asm__ (@ASM_SYMBOL_PREFIX@
1222 _GL_STDIO_MACROEXPAND_AND_STRINGIZE(rpl_printf)) 1351 _GL_STDIO_MACROEXPAND_AND_STRINGIZE(rpl_printf)),
1223 _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (1, 2) 1352 _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (1, 2)
1224 _GL_ARG_NONNULL ((1))); 1353 _GL_ARG_NONNULL ((1)));
1225# endif 1354# endif
@@ -1229,7 +1358,7 @@ _GL_CXXALIAS_RPL_1 (printf, __printf__, int, (const char *format, ...));
1229# define printf rpl_printf 1358# define printf rpl_printf
1230# endif 1359# endif
1231_GL_FUNCDECL_RPL (printf, int, 1360_GL_FUNCDECL_RPL (printf, int,
1232 (const char *restrict format, ...) 1361 (const char *restrict format, ...),
1233 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 2) 1362 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 2)
1234 _GL_ARG_NONNULL ((1))); 1363 _GL_ARG_NONNULL ((1)));
1235_GL_CXXALIAS_RPL (printf, int, (const char *restrict format, ...)); 1364_GL_CXXALIAS_RPL (printf, int, (const char *restrict format, ...));
@@ -1241,6 +1370,11 @@ _GL_CXXALIAS_SYS (printf, int, (const char *restrict format, ...));
1241# if __GLIBC__ >= 2 1370# if __GLIBC__ >= 2
1242_GL_CXXALIASWARN (printf); 1371_GL_CXXALIASWARN (printf);
1243# endif 1372# endif
1373#elif defined __MINGW32__ && !defined _UCRT && __USE_MINGW_ANSI_STDIO
1374# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1375# undef printf
1376# define printf gl_consolesafe_printf
1377# endif
1244#endif 1378#endif
1245#if !@GNULIB_PRINTF_POSIX@ && defined GNULIB_POSIXCHECK 1379#if !@GNULIB_PRINTF_POSIX@ && defined GNULIB_POSIXCHECK
1246# if !GNULIB_overrides_printf 1380# if !GNULIB_overrides_printf
@@ -1258,7 +1392,7 @@ _GL_WARN_ON_USE (printf, "printf is not always POSIX compliant - "
1258# undef putc 1392# undef putc
1259# define putc rpl_fputc 1393# define putc rpl_fputc
1260# endif 1394# endif
1261_GL_FUNCDECL_RPL (fputc, int, (int c, FILE *stream) _GL_ARG_NONNULL ((2))); 1395_GL_FUNCDECL_RPL (fputc, int, (int c, FILE *stream), _GL_ARG_NONNULL ((2)));
1262_GL_CXXALIAS_RPL_1 (putc, rpl_fputc, int, (int c, FILE *stream)); 1396_GL_CXXALIAS_RPL_1 (putc, rpl_fputc, int, (int c, FILE *stream));
1263# else 1397# else
1264_GL_CXXALIAS_SYS (putc, int, (int c, FILE *stream)); 1398_GL_CXXALIAS_SYS (putc, int, (int c, FILE *stream));
@@ -1274,7 +1408,7 @@ _GL_CXXALIASWARN (putc);
1274# undef putchar 1408# undef putchar
1275# define putchar rpl_putchar 1409# define putchar rpl_putchar
1276# endif 1410# endif
1277_GL_FUNCDECL_RPL (putchar, int, (int c)); 1411_GL_FUNCDECL_RPL (putchar, int, (int c), );
1278_GL_CXXALIAS_RPL (putchar, int, (int c)); 1412_GL_CXXALIAS_RPL (putchar, int, (int c));
1279# else 1413# else
1280_GL_CXXALIAS_SYS (putchar, int, (int c)); 1414_GL_CXXALIAS_SYS (putchar, int, (int c));
@@ -1290,7 +1424,7 @@ _GL_CXXALIASWARN (putchar);
1290# undef puts 1424# undef puts
1291# define puts rpl_puts 1425# define puts rpl_puts
1292# endif 1426# endif
1293_GL_FUNCDECL_RPL (puts, int, (const char *string) _GL_ARG_NONNULL ((1))); 1427_GL_FUNCDECL_RPL (puts, int, (const char *string), _GL_ARG_NONNULL ((1)));
1294_GL_CXXALIAS_RPL (puts, int, (const char *string)); 1428_GL_CXXALIAS_RPL (puts, int, (const char *string));
1295# else 1429# else
1296_GL_CXXALIAS_SYS (puts, int, (const char *string)); 1430_GL_CXXALIAS_SYS (puts, int, (const char *string));
@@ -1314,7 +1448,7 @@ _GL_CXXALIAS_MDA (putw, int, (int w, FILE *restrict stream));
1314# if @HAVE_DECL_PUTW@ 1448# if @HAVE_DECL_PUTW@
1315# if defined __APPLE__ && defined __MACH__ 1449# if defined __APPLE__ && defined __MACH__
1316/* The presence of the declaration depends on _POSIX_C_SOURCE. */ 1450/* The presence of the declaration depends on _POSIX_C_SOURCE. */
1317_GL_FUNCDECL_SYS (putw, int, (int w, FILE *restrict stream)); 1451_GL_FUNCDECL_SYS (putw, int, (int w, FILE *restrict stream), );
1318# endif 1452# endif
1319_GL_CXXALIAS_SYS (putw, int, (int w, FILE *restrict stream)); 1453_GL_CXXALIAS_SYS (putw, int, (int w, FILE *restrict stream));
1320# endif 1454# endif
@@ -1330,7 +1464,7 @@ _GL_CXXALIASWARN (putw);
1330# undef remove 1464# undef remove
1331# define remove rpl_remove 1465# define remove rpl_remove
1332# endif 1466# endif
1333_GL_FUNCDECL_RPL (remove, int, (const char *name) _GL_ARG_NONNULL ((1))); 1467_GL_FUNCDECL_RPL (remove, int, (const char *name), _GL_ARG_NONNULL ((1)));
1334_GL_CXXALIAS_RPL (remove, int, (const char *name)); 1468_GL_CXXALIAS_RPL (remove, int, (const char *name));
1335# else 1469# else
1336_GL_CXXALIAS_SYS (remove, int, (const char *name)); 1470_GL_CXXALIAS_SYS (remove, int, (const char *name));
@@ -1352,7 +1486,7 @@ _GL_WARN_ON_USE (remove, "remove cannot handle directories on some platforms - "
1352# define rename rpl_rename 1486# define rename rpl_rename
1353# endif 1487# endif
1354_GL_FUNCDECL_RPL (rename, int, 1488_GL_FUNCDECL_RPL (rename, int,
1355 (const char *old_filename, const char *new_filename) 1489 (const char *old_filename, const char *new_filename),
1356 _GL_ARG_NONNULL ((1, 2))); 1490 _GL_ARG_NONNULL ((1, 2)));
1357_GL_CXXALIAS_RPL (rename, int, 1491_GL_CXXALIAS_RPL (rename, int,
1358 (const char *old_filename, const char *new_filename)); 1492 (const char *old_filename, const char *new_filename));
@@ -1377,14 +1511,14 @@ _GL_WARN_ON_USE (rename, "rename is buggy on some platforms - "
1377# define renameat rpl_renameat 1511# define renameat rpl_renameat
1378# endif 1512# endif
1379_GL_FUNCDECL_RPL (renameat, int, 1513_GL_FUNCDECL_RPL (renameat, int,
1380 (int fd1, char const *file1, int fd2, char const *file2) 1514 (int fd1, char const *file1, int fd2, char const *file2),
1381 _GL_ARG_NONNULL ((2, 4))); 1515 _GL_ARG_NONNULL ((2, 4)));
1382_GL_CXXALIAS_RPL (renameat, int, 1516_GL_CXXALIAS_RPL (renameat, int,
1383 (int fd1, char const *file1, int fd2, char const *file2)); 1517 (int fd1, char const *file1, int fd2, char const *file2));
1384# else 1518# else
1385# if !@HAVE_RENAMEAT@ 1519# if !@HAVE_RENAMEAT@
1386_GL_FUNCDECL_SYS (renameat, int, 1520_GL_FUNCDECL_SYS (renameat, int,
1387 (int fd1, char const *file1, int fd2, char const *file2) 1521 (int fd1, char const *file1, int fd2, char const *file2),
1388 _GL_ARG_NONNULL ((2, 4))); 1522 _GL_ARG_NONNULL ((2, 4)));
1389# endif 1523# endif
1390_GL_CXXALIAS_SYS (renameat, int, 1524_GL_CXXALIAS_SYS (renameat, int,
@@ -1410,18 +1544,18 @@ _GL_WARN_ON_USE (renameat, "renameat is not portable - "
1410_GL_FUNCDECL_RPL_1 (__scanf__, int, 1544_GL_FUNCDECL_RPL_1 (__scanf__, int,
1411 (const char *restrict format, ...) 1545 (const char *restrict format, ...)
1412 __asm__ (@ASM_SYMBOL_PREFIX@ 1546 __asm__ (@ASM_SYMBOL_PREFIX@
1413 _GL_STDIO_MACROEXPAND_AND_STRINGIZE(rpl_scanf)) 1547 _GL_STDIO_MACROEXPAND_AND_STRINGIZE(rpl_scanf)),
1414 _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (1, 2) 1548 _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (1, 2)
1415 _GL_ARG_NONNULL ((1))); 1549 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
1416_GL_CXXALIAS_RPL_1 (scanf, __scanf__, int, (const char *restrict format, ...)); 1550_GL_CXXALIAS_RPL_1 (scanf, __scanf__, int, (const char *restrict format, ...));
1417# else 1551# else
1418# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1552# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1419# undef scanf 1553# undef scanf
1420# define scanf rpl_scanf 1554# define scanf rpl_scanf
1421# endif 1555# endif
1422_GL_FUNCDECL_RPL (scanf, int, (const char *restrict format, ...) 1556_GL_FUNCDECL_RPL (scanf, int, (const char *restrict format, ...),
1423 _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (1, 2) 1557 _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (1, 2)
1424 _GL_ARG_NONNULL ((1))); 1558 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
1425_GL_CXXALIAS_RPL (scanf, int, (const char *restrict format, ...)); 1559_GL_CXXALIAS_RPL (scanf, int, (const char *restrict format, ...));
1426# endif 1560# endif
1427# else 1561# else
@@ -1432,7 +1566,31 @@ _GL_CXXALIASWARN (scanf);
1432# endif 1566# endif
1433#endif 1567#endif
1434 1568
1569#if @GNULIB_SNZPRINTF@
1570/* Prints formatted output to string STR. Similar to sprintf, but the
1571 additional parameter SIZE limits how much is written into STR.
1572 STR may be NULL, in which case nothing will be written.
1573 Returns the string length of the formatted string (which may be larger
1574 than SIZE). Upon failure, returns -1 with errno set.
1575 Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
1576 Therefore, if the format string is valid and does not use %ls/%lc
1577 directives nor widths, the only possible failure code is ENOMEM. */
1578_GL_FUNCDECL_SYS (snzprintf, ptrdiff_t,
1579 (char *restrict str, size_t size,
1580 const char *restrict format, ...),
1581 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 4)
1582 _GL_ARG_NONNULL ((3)));
1583_GL_CXXALIAS_SYS (snzprintf, ptrdiff_t,
1584 (char *restrict str, size_t size,
1585 const char *restrict format, ...));
1586#endif
1587
1435#if @GNULIB_SNPRINTF@ 1588#if @GNULIB_SNPRINTF@
1589/* Prints formatted output to string STR. Similar to sprintf, but the
1590 additional parameter SIZE limits how much is written into STR.
1591 STR may be NULL, in which case nothing will be written.
1592 Returns the string length of the formatted string (which may be larger
1593 than SIZE). Upon failure, returns a negative value. */
1436# if @REPLACE_SNPRINTF@ 1594# if @REPLACE_SNPRINTF@
1437# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1595# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1438# define snprintf rpl_snprintf 1596# define snprintf rpl_snprintf
@@ -1440,7 +1598,7 @@ _GL_CXXALIASWARN (scanf);
1440# define GNULIB_overrides_snprintf 1 1598# define GNULIB_overrides_snprintf 1
1441_GL_FUNCDECL_RPL (snprintf, int, 1599_GL_FUNCDECL_RPL (snprintf, int,
1442 (char *restrict str, size_t size, 1600 (char *restrict str, size_t size,
1443 const char *restrict format, ...) 1601 const char *restrict format, ...),
1444 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 4) 1602 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 4)
1445 _GL_ARG_NONNULL ((3))); 1603 _GL_ARG_NONNULL ((3)));
1446_GL_CXXALIAS_RPL (snprintf, int, 1604_GL_CXXALIAS_RPL (snprintf, int,
@@ -1450,7 +1608,7 @@ _GL_CXXALIAS_RPL (snprintf, int,
1450# if !@HAVE_DECL_SNPRINTF@ 1608# if !@HAVE_DECL_SNPRINTF@
1451_GL_FUNCDECL_SYS (snprintf, int, 1609_GL_FUNCDECL_SYS (snprintf, int,
1452 (char *restrict str, size_t size, 1610 (char *restrict str, size_t size,
1453 const char *restrict format, ...) 1611 const char *restrict format, ...),
1454 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 4) 1612 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 4)
1455 _GL_ARG_NONNULL ((3))); 1613 _GL_ARG_NONNULL ((3)));
1456# endif 1614# endif
@@ -1469,6 +1627,23 @@ _GL_WARN_ON_USE (snprintf, "snprintf is unportable - "
1469# endif 1627# endif
1470#endif 1628#endif
1471 1629
1630#if @GNULIB_SZPRINTF@
1631/* Prints formatted output to string STR.
1632 Returns the string length of the formatted string. Upon failure,
1633 returns -1 with errno set.
1634 Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
1635 Therefore, if the format string is valid and does not use %ls/%lc
1636 directives nor widths, the only possible failure code is ENOMEM. */
1637_GL_FUNCDECL_SYS (szprintf, ptrdiff_t,
1638 (char *restrict str,
1639 const char *restrict format, ...),
1640 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
1641 _GL_ARG_NONNULL ((1, 2)));
1642_GL_CXXALIAS_SYS (szprintf, ptrdiff_t,
1643 (char *restrict str,
1644 const char *restrict format, ...));
1645#endif
1646
1472/* Some people would argue that all sprintf uses should be warned about 1647/* Some people would argue that all sprintf uses should be warned about
1473 (for example, OpenBSD issues a link warning for it), 1648 (for example, OpenBSD issues a link warning for it),
1474 since it can cause security holes due to buffer overruns. 1649 since it can cause security holes due to buffer overruns.
@@ -1479,13 +1654,16 @@ _GL_WARN_ON_USE (snprintf, "snprintf is unportable - "
1479 GNULIB_POSIXCHECK is defined. */ 1654 GNULIB_POSIXCHECK is defined. */
1480 1655
1481#if @GNULIB_SPRINTF_POSIX@ 1656#if @GNULIB_SPRINTF_POSIX@
1657/* Prints formatted output to string STR.
1658 Returns the string length of the formatted string. Upon failure,
1659 returns a negative value. */
1482# if @REPLACE_SPRINTF@ 1660# if @REPLACE_SPRINTF@
1483# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1661# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1484# define sprintf rpl_sprintf 1662# define sprintf rpl_sprintf
1485# endif 1663# endif
1486# define GNULIB_overrides_sprintf 1 1664# define GNULIB_overrides_sprintf 1
1487_GL_FUNCDECL_RPL (sprintf, int, 1665_GL_FUNCDECL_RPL (sprintf, int,
1488 (char *restrict str, const char *restrict format, ...) 1666 (char *restrict str, const char *restrict format, ...),
1489 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) 1667 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
1490 _GL_ARG_NONNULL ((1, 2))); 1668 _GL_ARG_NONNULL ((1, 2)));
1491_GL_CXXALIAS_RPL (sprintf, int, 1669_GL_CXXALIAS_RPL (sprintf, int,
@@ -1526,16 +1704,18 @@ _GL_CXXALIASWARN (tempnam);
1526# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1704# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1527# define tmpfile rpl_tmpfile 1705# define tmpfile rpl_tmpfile
1528# endif 1706# endif
1529_GL_FUNCDECL_RPL (tmpfile, FILE *, (void) 1707_GL_FUNCDECL_RPL (tmpfile, FILE *, (void),
1530 _GL_ATTRIBUTE_DEALLOC (fclose, 1) 1708 _GL_ATTRIBUTE_DEALLOC (fclose, 1)
1531 _GL_ATTRIBUTE_MALLOC); 1709 _GL_ATTRIBUTE_MALLOC
1710 _GL_ATTRIBUTE_NODISCARD);
1532_GL_CXXALIAS_RPL (tmpfile, FILE *, (void)); 1711_GL_CXXALIAS_RPL (tmpfile, FILE *, (void));
1533# else 1712# else
1534# if __GNUC__ >= 11 1713# if __GNUC__ >= 11 && !defined __clang__
1535/* For -Wmismatched-dealloc: Associate tmpfile with fclose or rpl_fclose. */ 1714/* For -Wmismatched-dealloc: Associate tmpfile with fclose or rpl_fclose. */
1536_GL_FUNCDECL_SYS (tmpfile, FILE *, (void) 1715_GL_FUNCDECL_SYS (tmpfile, FILE *, (void),
1537 _GL_ATTRIBUTE_DEALLOC (fclose, 1) 1716 _GL_ATTRIBUTE_DEALLOC (fclose, 1)
1538 _GL_ATTRIBUTE_MALLOC); 1717 _GL_ATTRIBUTE_MALLOC
1718 _GL_ATTRIBUTE_NODISCARD);
1539# endif 1719# endif
1540_GL_CXXALIAS_SYS (tmpfile, FILE *, (void)); 1720_GL_CXXALIAS_SYS (tmpfile, FILE *, (void));
1541# endif 1721# endif
@@ -1543,9 +1723,10 @@ _GL_CXXALIAS_SYS (tmpfile, FILE *, (void));
1543_GL_CXXALIASWARN (tmpfile); 1723_GL_CXXALIASWARN (tmpfile);
1544# endif 1724# endif
1545#else 1725#else
1546# if @GNULIB_FCLOSE@ && __GNUC__ >= 11 && !defined tmpfile 1726# if @GNULIB_FCLOSE@ \
1727 && (__GNUC__ >= 11 && !defined __clang__) && !defined tmpfile
1547/* For -Wmismatched-dealloc: Associate tmpfile with fclose or rpl_fclose. */ 1728/* For -Wmismatched-dealloc: Associate tmpfile with fclose or rpl_fclose. */
1548_GL_FUNCDECL_SYS (tmpfile, FILE *, (void) 1729_GL_FUNCDECL_SYS (tmpfile, FILE *, (void),
1549 _GL_ATTRIBUTE_DEALLOC (fclose, 1) 1730 _GL_ATTRIBUTE_DEALLOC (fclose, 1)
1550 _GL_ATTRIBUTE_MALLOC); 1731 _GL_ATTRIBUTE_MALLOC);
1551# endif 1732# endif
@@ -1558,6 +1739,31 @@ _GL_WARN_ON_USE (tmpfile, "tmpfile is not usable on mingw - "
1558# endif 1739# endif
1559#endif 1740#endif
1560 1741
1742#if @GNULIB_VASZPRINTF@
1743/* Prints formatted output to a string dynamically allocated with malloc().
1744 If the memory allocation succeeds, it stores the address of the string in
1745 *RESULT and returns the number of resulting bytes, excluding the trailing
1746 NUL. Upon memory allocation error, or some other error, it returns -1
1747 with errno set.
1748 Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
1749 Therefore, if the format string is valid and does not use %ls/%lc
1750 directives nor widths, the only possible failure code is ENOMEM. */
1751_GL_FUNCDECL_SYS (aszprintf, ptrdiff_t,
1752 (char **result, const char *format, ...),
1753 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
1754 _GL_ARG_NONNULL ((1, 2))
1755 _GL_ATTRIBUTE_NODISCARD);
1756_GL_CXXALIAS_SYS (aszprintf, ptrdiff_t,
1757 (char **result, const char *format, ...));
1758_GL_FUNCDECL_SYS (vaszprintf, ptrdiff_t,
1759 (char **result, const char *format, va_list args),
1760 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
1761 _GL_ARG_NONNULL ((1, 2))
1762 _GL_ATTRIBUTE_NODISCARD);
1763_GL_CXXALIAS_SYS (vaszprintf, ptrdiff_t,
1764 (char **result, const char *format, va_list args));
1765#endif
1766
1561#if @GNULIB_VASPRINTF@ 1767#if @GNULIB_VASPRINTF@
1562/* Write formatted output to a string dynamically allocated with malloc(). 1768/* Write formatted output to a string dynamically allocated with malloc().
1563 If the memory allocation succeeds, store the address of the string in 1769 If the memory allocation succeeds, store the address of the string in
@@ -1569,17 +1775,19 @@ _GL_WARN_ON_USE (tmpfile, "tmpfile is not usable on mingw - "
1569# endif 1775# endif
1570# define GNULIB_overrides_asprintf 1776# define GNULIB_overrides_asprintf
1571_GL_FUNCDECL_RPL (asprintf, int, 1777_GL_FUNCDECL_RPL (asprintf, int,
1572 (char **result, const char *format, ...) 1778 (char **result, const char *format, ...),
1573 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) 1779 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
1574 _GL_ARG_NONNULL ((1, 2))); 1780 _GL_ARG_NONNULL ((1, 2))
1781 _GL_ATTRIBUTE_NODISCARD);
1575_GL_CXXALIAS_RPL (asprintf, int, 1782_GL_CXXALIAS_RPL (asprintf, int,
1576 (char **result, const char *format, ...)); 1783 (char **result, const char *format, ...));
1577# else 1784# else
1578# if !@HAVE_VASPRINTF@ 1785# if !@HAVE_VASPRINTF@
1579_GL_FUNCDECL_SYS (asprintf, int, 1786_GL_FUNCDECL_SYS (asprintf, int,
1580 (char **result, const char *format, ...) 1787 (char **result, const char *format, ...),
1581 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) 1788 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
1582 _GL_ARG_NONNULL ((1, 2))); 1789 _GL_ARG_NONNULL ((1, 2))
1790 _GL_ATTRIBUTE_NODISCARD);
1583# endif 1791# endif
1584_GL_CXXALIAS_SYS (asprintf, int, 1792_GL_CXXALIAS_SYS (asprintf, int,
1585 (char **result, const char *format, ...)); 1793 (char **result, const char *format, ...));
@@ -1591,17 +1799,19 @@ _GL_CXXALIASWARN (asprintf);
1591# endif 1799# endif
1592# define GNULIB_overrides_vasprintf 1 1800# define GNULIB_overrides_vasprintf 1
1593_GL_FUNCDECL_RPL (vasprintf, int, 1801_GL_FUNCDECL_RPL (vasprintf, int,
1594 (char **result, const char *format, va_list args) 1802 (char **result, const char *format, va_list args),
1595 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) 1803 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
1596 _GL_ARG_NONNULL ((1, 2))); 1804 _GL_ARG_NONNULL ((1, 2))
1805 _GL_ATTRIBUTE_NODISCARD);
1597_GL_CXXALIAS_RPL (vasprintf, int, 1806_GL_CXXALIAS_RPL (vasprintf, int,
1598 (char **result, const char *format, va_list args)); 1807 (char **result, const char *format, va_list args));
1599# else 1808# else
1600# if !@HAVE_VASPRINTF@ 1809# if !@HAVE_VASPRINTF@
1601_GL_FUNCDECL_SYS (vasprintf, int, 1810_GL_FUNCDECL_SYS (vasprintf, int,
1602 (char **result, const char *format, va_list args) 1811 (char **result, const char *format, va_list args),
1603 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) 1812 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
1604 _GL_ARG_NONNULL ((1, 2))); 1813 _GL_ARG_NONNULL ((1, 2))
1814 _GL_ATTRIBUTE_NODISCARD);
1605# endif 1815# endif
1606_GL_CXXALIAS_SYS (vasprintf, int, 1816_GL_CXXALIAS_SYS (vasprintf, int,
1607 (char **result, const char *format, va_list args)); 1817 (char **result, const char *format, va_list args));
@@ -1609,13 +1819,32 @@ _GL_CXXALIAS_SYS (vasprintf, int,
1609_GL_CXXALIASWARN (vasprintf); 1819_GL_CXXALIASWARN (vasprintf);
1610#endif 1820#endif
1611 1821
1822#if @GNULIB_VDZPRINTF@
1823/* Prints formatted output to file descriptor FD.
1824 Returns the number of bytes written to the file descriptor. Upon
1825 failure, returns -1 with errno set.
1826 Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
1827 Therefore, if the format string is valid and does not use %ls/%lc
1828 directives nor widths, the only possible failure codes are ENOMEM
1829 and the possible failure codes from write(), excluding EINTR. */
1830_GL_FUNCDECL_SYS (vdzprintf, off64_t,
1831 (int fd, const char *restrict format, va_list args),
1832 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
1833 _GL_ARG_NONNULL ((2)));
1834_GL_CXXALIAS_SYS (vdzprintf, off64_t,
1835 (int fd, const char *restrict format, va_list args));
1836#endif
1837
1612#if @GNULIB_VDPRINTF@ 1838#if @GNULIB_VDPRINTF@
1839/* Prints formatted output to file descriptor FD.
1840 Returns the number of bytes written to the file descriptor. Upon
1841 failure, returns a negative value. */
1613# if @REPLACE_VDPRINTF@ 1842# if @REPLACE_VDPRINTF@
1614# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1843# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1615# define vdprintf rpl_vdprintf 1844# define vdprintf rpl_vdprintf
1616# endif 1845# endif
1617_GL_FUNCDECL_RPL (vdprintf, int, 1846_GL_FUNCDECL_RPL (vdprintf, int,
1618 (int fd, const char *restrict format, va_list args) 1847 (int fd, const char *restrict format, va_list args),
1619 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) 1848 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
1620 _GL_ARG_NONNULL ((2))); 1849 _GL_ARG_NONNULL ((2)));
1621_GL_CXXALIAS_RPL (vdprintf, int, 1850_GL_CXXALIAS_RPL (vdprintf, int,
@@ -1623,7 +1852,7 @@ _GL_CXXALIAS_RPL (vdprintf, int,
1623# else 1852# else
1624# if !@HAVE_VDPRINTF@ 1853# if !@HAVE_VDPRINTF@
1625_GL_FUNCDECL_SYS (vdprintf, int, 1854_GL_FUNCDECL_SYS (vdprintf, int,
1626 (int fd, const char *restrict format, va_list args) 1855 (int fd, const char *restrict format, va_list args),
1627 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) 1856 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
1628 _GL_ARG_NONNULL ((2))); 1857 _GL_ARG_NONNULL ((2)));
1629# endif 1858# endif
@@ -1643,7 +1872,28 @@ _GL_WARN_ON_USE (vdprintf, "vdprintf is unportable - "
1643# endif 1872# endif
1644#endif 1873#endif
1645 1874
1875#if @GNULIB_VFZPRINTF@
1876/* Prints formatted output to stream FP.
1877 Returns the number of bytes written to the stream. Upon failure,
1878 returns -1 with the stream's error indicator set.
1879 Failure cause EOVERFLOW can only occur when a width > INT_MAX is used.
1880 Therefore, if the format string is valid and does not use %ls/%lc
1881 directives nor widths, the only possible failure causes are ENOMEM
1882 and the possible failure causes from fwrite(). */
1883_GL_FUNCDECL_SYS (vfzprintf, off64_t,
1884 (FILE *restrict fp,
1885 const char *restrict format, va_list args),
1886 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
1887 _GL_ARG_NONNULL ((1, 2)));
1888_GL_CXXALIAS_SYS (vfzprintf, off64_t,
1889 (FILE *restrict fp,
1890 const char *restrict format, va_list args));
1891#endif
1892
1646#if @GNULIB_VFPRINTF_POSIX@ || @GNULIB_VFPRINTF@ 1893#if @GNULIB_VFPRINTF_POSIX@ || @GNULIB_VFPRINTF@
1894/* Prints formatted output to stream FP.
1895 Returns the number of bytes written to the stream. Upon failure,
1896 returns a negative value with the stream's error indicator set. */
1647# if (@GNULIB_VFPRINTF_POSIX@ && @REPLACE_VFPRINTF@) \ 1897# if (@GNULIB_VFPRINTF_POSIX@ && @REPLACE_VFPRINTF@) \
1648 || (@GNULIB_VFPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)) 1898 || (@GNULIB_VFPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@))
1649# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1899# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -1653,13 +1903,13 @@ _GL_WARN_ON_USE (vdprintf, "vdprintf is unportable - "
1653# if @GNULIB_VFPRINTF_POSIX@ 1903# if @GNULIB_VFPRINTF_POSIX@
1654_GL_FUNCDECL_RPL (vfprintf, int, 1904_GL_FUNCDECL_RPL (vfprintf, int,
1655 (FILE *restrict fp, 1905 (FILE *restrict fp,
1656 const char *restrict format, va_list args) 1906 const char *restrict format, va_list args),
1657 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) 1907 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
1658 _GL_ARG_NONNULL ((1, 2))); 1908 _GL_ARG_NONNULL ((1, 2)));
1659# else 1909# else
1660_GL_FUNCDECL_RPL (vfprintf, int, 1910_GL_FUNCDECL_RPL (vfprintf, int,
1661 (FILE *restrict fp, 1911 (FILE *restrict fp,
1662 const char *restrict format, va_list args) 1912 const char *restrict format, va_list args),
1663 _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (2, 0) 1913 _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (2, 0)
1664 _GL_ARG_NONNULL ((1, 2))); 1914 _GL_ARG_NONNULL ((1, 2)));
1665# endif 1915# endif
@@ -1677,6 +1927,11 @@ _GL_CXXALIAS_SYS_CAST (vfprintf, int,
1677# if __GLIBC__ >= 2 1927# if __GLIBC__ >= 2
1678_GL_CXXALIASWARN (vfprintf); 1928_GL_CXXALIASWARN (vfprintf);
1679# endif 1929# endif
1930#elif defined __MINGW32__ && !defined _UCRT && __USE_MINGW_ANSI_STDIO
1931# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1932# undef vfprintf
1933# define vfprintf gl_consolesafe_vfprintf
1934# endif
1680#endif 1935#endif
1681#if !@GNULIB_VFPRINTF_POSIX@ && defined GNULIB_POSIXCHECK 1936#if !@GNULIB_VFPRINTF_POSIX@ && defined GNULIB_POSIXCHECK
1682# if !GNULIB_overrides_vfprintf 1937# if !GNULIB_overrides_vfprintf
@@ -1696,9 +1951,9 @@ _GL_WARN_ON_USE (vfprintf, "vfprintf is not always POSIX compliant - "
1696# endif 1951# endif
1697_GL_FUNCDECL_RPL (vfscanf, int, 1952_GL_FUNCDECL_RPL (vfscanf, int,
1698 (FILE *restrict stream, 1953 (FILE *restrict stream,
1699 const char *restrict format, va_list args) 1954 const char *restrict format, va_list args),
1700 _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (2, 0) 1955 _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (2, 0)
1701 _GL_ARG_NONNULL ((1, 2))); 1956 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_NODISCARD);
1702_GL_CXXALIAS_RPL (vfscanf, int, 1957_GL_CXXALIAS_RPL (vfscanf, int,
1703 (FILE *restrict stream, 1958 (FILE *restrict stream,
1704 const char *restrict format, va_list args)); 1959 const char *restrict format, va_list args));
@@ -1712,7 +1967,26 @@ _GL_CXXALIASWARN (vfscanf);
1712# endif 1967# endif
1713#endif 1968#endif
1714 1969
1970#if @GNULIB_VZPRINTF@
1971/* Prints formatted output to standard output.
1972 Returns the number of bytes written to standard output. Upon failure,
1973 returns -1 with stdout's error indicator set.
1974 Failure cause EOVERFLOW can only occur when a width > INT_MAX is used.
1975 Therefore, if the format string is valid and does not use %ls/%lc
1976 directives nor widths, the only possible failure causes are ENOMEM
1977 and the possible failure causes from fwrite(). */
1978_GL_FUNCDECL_SYS (vzprintf, off64_t,
1979 (const char *restrict format, va_list args),
1980 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 0)
1981 _GL_ARG_NONNULL ((1)));
1982_GL_CXXALIAS_SYS (vzprintf, off64_t,
1983 (const char *restrict format, va_list args));
1984#endif
1985
1715#if @GNULIB_VPRINTF_POSIX@ || @GNULIB_VPRINTF@ 1986#if @GNULIB_VPRINTF_POSIX@ || @GNULIB_VPRINTF@
1987/* Prints formatted output to standard output.
1988 Returns the number of bytes written to standard output. Upon failure,
1989 returns a negative value with stdout's error indicator set. */
1716# if (@GNULIB_VPRINTF_POSIX@ && @REPLACE_VPRINTF@) \ 1990# if (@GNULIB_VPRINTF_POSIX@ && @REPLACE_VPRINTF@) \
1717 || (@GNULIB_VPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)) 1991 || (@GNULIB_VPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@))
1718# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1992# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -1720,11 +1994,11 @@ _GL_CXXALIASWARN (vfscanf);
1720# endif 1994# endif
1721# define GNULIB_overrides_vprintf 1 1995# define GNULIB_overrides_vprintf 1
1722# if @GNULIB_VPRINTF_POSIX@ || @GNULIB_VFPRINTF_POSIX@ 1996# if @GNULIB_VPRINTF_POSIX@ || @GNULIB_VFPRINTF_POSIX@
1723_GL_FUNCDECL_RPL (vprintf, int, (const char *restrict format, va_list args) 1997_GL_FUNCDECL_RPL (vprintf, int, (const char *restrict format, va_list args),
1724 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 0) 1998 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 0)
1725 _GL_ARG_NONNULL ((1))); 1999 _GL_ARG_NONNULL ((1)));
1726# else 2000# else
1727_GL_FUNCDECL_RPL (vprintf, int, (const char *restrict format, va_list args) 2001_GL_FUNCDECL_RPL (vprintf, int, (const char *restrict format, va_list args),
1728 _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (1, 0) 2002 _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (1, 0)
1729 _GL_ARG_NONNULL ((1))); 2003 _GL_ARG_NONNULL ((1)));
1730# endif 2004# endif
@@ -1739,6 +2013,11 @@ _GL_CXXALIAS_SYS_CAST (vprintf, int,
1739# if __GLIBC__ >= 2 2013# if __GLIBC__ >= 2
1740_GL_CXXALIASWARN (vprintf); 2014_GL_CXXALIASWARN (vprintf);
1741# endif 2015# endif
2016#elif defined __MINGW32__ && !defined _UCRT && __USE_MINGW_ANSI_STDIO
2017# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2018# undef vprintf
2019# define vprintf gl_consolesafe_vprintf
2020# endif
1742#endif 2021#endif
1743#if !@GNULIB_VPRINTF_POSIX@ && defined GNULIB_POSIXCHECK 2022#if !@GNULIB_VPRINTF_POSIX@ && defined GNULIB_POSIXCHECK
1744# if !GNULIB_overrides_vprintf 2023# if !GNULIB_overrides_vprintf
@@ -1756,9 +2035,9 @@ _GL_WARN_ON_USE (vprintf, "vprintf is not always POSIX compliant - "
1756# undef vscanf 2035# undef vscanf
1757# define vscanf rpl_vscanf 2036# define vscanf rpl_vscanf
1758# endif 2037# endif
1759_GL_FUNCDECL_RPL (vscanf, int, (const char *restrict format, va_list args) 2038_GL_FUNCDECL_RPL (vscanf, int, (const char *restrict format, va_list args),
1760 _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (1, 0) 2039 _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (1, 0)
1761 _GL_ARG_NONNULL ((1))); 2040 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
1762_GL_CXXALIAS_RPL (vscanf, int, (const char *restrict format, va_list args)); 2041_GL_CXXALIAS_RPL (vscanf, int, (const char *restrict format, va_list args));
1763# else 2042# else
1764_GL_CXXALIAS_SYS (vscanf, int, (const char *restrict format, va_list args)); 2043_GL_CXXALIAS_SYS (vscanf, int, (const char *restrict format, va_list args));
@@ -1768,7 +2047,31 @@ _GL_CXXALIASWARN (vscanf);
1768# endif 2047# endif
1769#endif 2048#endif
1770 2049
2050#if @GNULIB_VSNZPRINTF@
2051/* Prints formatted output to string STR. Similar to sprintf, but the
2052 additional parameter SIZE limits how much is written into STR.
2053 STR may be NULL, in which case nothing will be written.
2054 Returns the string length of the formatted string (which may be larger
2055 than SIZE). Upon failure, returns -1 with errno set.
2056 Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
2057 Therefore, if the format string is valid and does not use %ls/%lc
2058 directives nor widths, the only possible failure code is ENOMEM. */
2059_GL_FUNCDECL_SYS (vsnzprintf, ptrdiff_t,
2060 (char *restrict str, size_t size,
2061 const char *restrict format, va_list args),
2062 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 0)
2063 _GL_ARG_NONNULL ((3)));
2064_GL_CXXALIAS_SYS (vsnzprintf, ptrdiff_t,
2065 (char *restrict str, size_t size,
2066 const char *restrict format, va_list args));
2067#endif
2068
1771#if @GNULIB_VSNPRINTF@ 2069#if @GNULIB_VSNPRINTF@
2070/* Prints formatted output to string STR. Similar to vsprintf, but the
2071 additional parameter SIZE limits how much is written into STR.
2072 STR may be NULL, in which case nothing will be written.
2073 Returns the string length of the formatted string (which may be larger
2074 than SIZE). Upon failure, returns a negative value. */
1772# if @REPLACE_VSNPRINTF@ 2075# if @REPLACE_VSNPRINTF@
1773# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 2076# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1774# define vsnprintf rpl_vsnprintf 2077# define vsnprintf rpl_vsnprintf
@@ -1776,7 +2079,7 @@ _GL_CXXALIASWARN (vscanf);
1776# define GNULIB_overrides_vsnprintf 1 2079# define GNULIB_overrides_vsnprintf 1
1777_GL_FUNCDECL_RPL (vsnprintf, int, 2080_GL_FUNCDECL_RPL (vsnprintf, int,
1778 (char *restrict str, size_t size, 2081 (char *restrict str, size_t size,
1779 const char *restrict format, va_list args) 2082 const char *restrict format, va_list args),
1780 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 0) 2083 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 0)
1781 _GL_ARG_NONNULL ((3))); 2084 _GL_ARG_NONNULL ((3)));
1782_GL_CXXALIAS_RPL (vsnprintf, int, 2085_GL_CXXALIAS_RPL (vsnprintf, int,
@@ -1786,7 +2089,7 @@ _GL_CXXALIAS_RPL (vsnprintf, int,
1786# if !@HAVE_DECL_VSNPRINTF@ 2089# if !@HAVE_DECL_VSNPRINTF@
1787_GL_FUNCDECL_SYS (vsnprintf, int, 2090_GL_FUNCDECL_SYS (vsnprintf, int,
1788 (char *restrict str, size_t size, 2091 (char *restrict str, size_t size,
1789 const char *restrict format, va_list args) 2092 const char *restrict format, va_list args),
1790 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 0) 2093 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 0)
1791 _GL_ARG_NONNULL ((3))); 2094 _GL_ARG_NONNULL ((3)));
1792# endif 2095# endif
@@ -1805,7 +2108,27 @@ _GL_WARN_ON_USE (vsnprintf, "vsnprintf is unportable - "
1805# endif 2108# endif
1806#endif 2109#endif
1807 2110
2111#if @GNULIB_VSZPRINTF@
2112/* Prints formatted output to string STR.
2113 Returns the string length of the formatted string. Upon failure,
2114 returns -1 with errno set.
2115 Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
2116 Therefore, if the format string is valid and does not use %ls/%lc
2117 directives nor widths, the only possible failure code is ENOMEM. */
2118_GL_FUNCDECL_SYS (vszprintf, ptrdiff_t,
2119 (char *restrict str,
2120 const char *restrict format, va_list args),
2121 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
2122 _GL_ARG_NONNULL ((1, 2)));
2123_GL_CXXALIAS_SYS (vszprintf, ptrdiff_t,
2124 (char *restrict str,
2125 const char *restrict format, va_list args));
2126#endif
2127
1808#if @GNULIB_VSPRINTF_POSIX@ 2128#if @GNULIB_VSPRINTF_POSIX@
2129/* Prints formatted output to string STR.
2130 Returns the string length of the formatted string. Upon failure,
2131 returns a negative value. */
1809# if @REPLACE_VSPRINTF@ 2132# if @REPLACE_VSPRINTF@
1810# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 2133# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1811# define vsprintf rpl_vsprintf 2134# define vsprintf rpl_vsprintf
@@ -1813,7 +2136,7 @@ _GL_WARN_ON_USE (vsnprintf, "vsnprintf is unportable - "
1813# define GNULIB_overrides_vsprintf 1 2136# define GNULIB_overrides_vsprintf 1
1814_GL_FUNCDECL_RPL (vsprintf, int, 2137_GL_FUNCDECL_RPL (vsprintf, int,
1815 (char *restrict str, 2138 (char *restrict str,
1816 const char *restrict format, va_list args) 2139 const char *restrict format, va_list args),
1817 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) 2140 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
1818 _GL_ARG_NONNULL ((1, 2))); 2141 _GL_ARG_NONNULL ((1, 2)));
1819_GL_CXXALIAS_RPL (vsprintf, int, 2142_GL_CXXALIAS_RPL (vsprintf, int,
diff --git a/gl/stdlib.c b/gl/stdlib.c
new file mode 100644
index 00000000..6a06f5ba
--- /dev/null
+++ b/gl/stdlib.c
@@ -0,0 +1,21 @@
1/* Inline functions for <stdlib.h>.
2
3 Copyright (C) 2024-2025 Free Software Foundation, Inc.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#define _GL_STDLIB_INLINE _GL_EXTERN_INLINE
19#include <config.h>
20
21#include <stdlib.h>
diff --git a/gl/stdlib.in.h b/gl/stdlib.in.h
index e74e7c18..1342db48 100644
--- a/gl/stdlib.in.h
+++ b/gl/stdlib.in.h
@@ -1,6 +1,6 @@
1/* A GNU-like <stdlib.h>. 1/* A GNU-like <stdlib.h>.
2 2
3 Copyright (C) 1995, 2001-2004, 2006-2024 Free Software Foundation, Inc. 3 Copyright (C) 1995, 2001-2004, 2006-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -20,12 +20,27 @@
20#endif 20#endif
21@PRAGMA_COLUMNS@ 21@PRAGMA_COLUMNS@
22 22
23#if defined __need_system_stdlib_h || defined __need_malloc_and_calloc 23#if ((defined __need_system_stdlib_h && !defined _GLIBCXX_STDLIB_H) \
24 || defined __need_malloc_and_calloc) \
25 && !defined __SUNPRO_CC
24/* Special invocation conventions inside some gnulib header files, 26/* Special invocation conventions inside some gnulib header files,
25 and inside some glibc header files, respectively. */ 27 and inside some glibc header files, respectively.
28 Do not recognize this special invocation convention when GCC's
29 c++/11/stdlib.h is being included or has been included. This is needed
30 to support the use of clang+llvm binaries on Ubuntu 22.04 with
31 CXX="$clangdir/bin/clang++ -I/usr/include/c++/11 \
32 -I/usr/include/x86_64-linux-gnu/c++/11
33 -L/usr/lib/gcc/x86_64-linux-gnu/11
34 -Wl,-rpath,$clangdir/lib"
35 because in this case /usr/include/c++/11/stdlib.h (which does not support
36 the convention) is seen before the gnulib-generated stdlib.h. */
26 37
27#@INCLUDE_NEXT@ @NEXT_STDLIB_H@ 38#@INCLUDE_NEXT@ @NEXT_STDLIB_H@
28 39
40/* Make sure that the macros that indicate the special invocation convention
41 get undefined. This is needed at least on CentOS 7. */
42#undef __need_malloc_and_calloc
43
29#else 44#else
30/* Normal invocation convention. */ 45/* Normal invocation convention. */
31 46
@@ -38,8 +53,8 @@
38#define _@GUARD_PREFIX@_STDLIB_H 53#define _@GUARD_PREFIX@_STDLIB_H
39 54
40/* This file uses _Noreturn, _GL_ATTRIBUTE_DEALLOC, _GL_ATTRIBUTE_MALLOC, 55/* This file uses _Noreturn, _GL_ATTRIBUTE_DEALLOC, _GL_ATTRIBUTE_MALLOC,
41 _GL_ATTRIBUTE_NOTHROW, _GL_ATTRIBUTE_PURE, GNULIB_POSIXCHECK, 56 _GL_ATTRIBUTE_NODISCARD, _GL_ATTRIBUTE_NOTHROW, _GL_ATTRIBUTE_PURE,
42 HAVE_RAW_DECL_*. */ 57 _GL_INLINE_HEADER_BEGIN, GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
43#if !_GL_CONFIG_H_INCLUDED 58#if !_GL_CONFIG_H_INCLUDED
44 #error "Please include config.h first." 59 #error "Please include config.h first."
45#endif 60#endif
@@ -47,8 +62,9 @@
47/* NetBSD 5.0 mis-defines NULL. */ 62/* NetBSD 5.0 mis-defines NULL. */
48#include <stddef.h> 63#include <stddef.h>
49 64
50/* MirBSD 10 defines WEXITSTATUS in <sys/wait.h>, not in <stdlib.h>. */ 65/* MirBSD 10 defines WEXITSTATUS in <sys/wait.h>, not in <stdlib.h>.
51#if @GNULIB_SYSTEM_POSIX@ && !defined WEXITSTATUS 66 glibc 2.41 defines WCOREDUMP in <sys/wait.h>, not in <stdlib.h>. */
67#if @GNULIB_SYSTEM_POSIX@ && !(defined WEXITSTATUS && defined WCOREDUMP)
52# include <sys/wait.h> 68# include <sys/wait.h>
53#endif 69#endif
54 70
@@ -104,11 +120,30 @@ struct random_data
104# include <unistd.h> 120# include <unistd.h>
105#endif 121#endif
106 122
123#if ((@GNULIB_STRTOL@ && @REPLACE_STRTOL@) || (@GNULIB_STRTOLL@ && @REPLACE_STRTOLL@) || (@GNULIB_STRTOUL@ && @REPLACE_STRTOUL@) || (@GNULIB_STRTOULL@ && @REPLACE_STRTOULL@)) && defined __cplusplus && !defined GNULIB_NAMESPACE && defined __GNUG__ && !defined __clang__ && (defined __sun || defined _AIX)
124/* When strtol, strtoll, strtoul, or strtoull is going to be defined as a macro
125 below, this may cause compilation errors later in the libstdc++ header files
126 (that are part of GCC), such as:
127 error: 'rpl_strtol' is not a member of 'std'
128 To avoid this, include the relevant header files here, before these symbols
129 get defined as macros. But do so only on Solaris 11 and AIX (where it is
130 needed), not on mingw (where it would cause other compilation errors). */
131# include <string>
132#endif
133
134_GL_INLINE_HEADER_BEGIN
135#ifndef _GL_STDLIB_INLINE
136# define _GL_STDLIB_INLINE _GL_INLINE
137#endif
138#ifndef _GL_REALLOC_INLINE
139# define _GL_REALLOC_INLINE _GL_INLINE
140#endif
141
107/* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers 142/* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers
108 that can be freed by passing them as the Ith argument to the 143 that can be freed by passing them as the Ith argument to the
109 function F. */ 144 function F. */
110#ifndef _GL_ATTRIBUTE_DEALLOC 145#ifndef _GL_ATTRIBUTE_DEALLOC
111# if __GNUC__ >= 11 146# if __GNUC__ >= 11 && !defined __clang__
112# define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i))) 147# define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i)))
113# else 148# else
114# define _GL_ATTRIBUTE_DEALLOC(f, i) 149# define _GL_ATTRIBUTE_DEALLOC(f, i)
@@ -133,11 +168,23 @@ struct random_data
133# endif 168# endif
134#endif 169#endif
135 170
171/* _GL_ATTRIBUTE_NONNULL_IF_NONZERO (NP, NI) declares that the argument NP
172 (a pointer) must not be NULL if the argument NI (an integer) is != 0. */
173/* Applies to: functions. */
174#ifndef _GL_ATTRIBUTE_NONNULL_IF_NONZERO
175# if __GNUC__ >= 15 && !defined __clang__
176# define _GL_ATTRIBUTE_NONNULL_IF_NONZERO(np, ni) \
177 __attribute__ ((__nonnull_if_nonzero__ (np, ni)))
178# else
179# define _GL_ATTRIBUTE_NONNULL_IF_NONZERO(np, ni)
180# endif
181#endif
182
136/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions. 183/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions.
137 */ 184 */
138#ifndef _GL_ATTRIBUTE_NOTHROW 185#ifndef _GL_ATTRIBUTE_NOTHROW
139# if defined __cplusplus 186# if defined __cplusplus
140# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major >= 4 187# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major__ >= 4
141# if __cplusplus >= 201103L 188# if __cplusplus >= 201103L
142# define _GL_ATTRIBUTE_NOTHROW noexcept (true) 189# define _GL_ATTRIBUTE_NOTHROW noexcept (true)
143# else 190# else
@@ -188,6 +235,18 @@ struct random_data
188#endif 235#endif
189 236
190 237
238/* Declarations for ISO C N3322. */
239#if defined __GNUC__ && __GNUC__ >= 15 && !defined __clang__
240_GL_EXTERN_C void *bsearch (const void *__key,
241 const void *__base, size_t __nmemb, size_t __size,
242 int (*__compare) (const void *, const void *))
243 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3) _GL_ARG_NONNULL ((5));
244_GL_EXTERN_C void qsort (void *__base, size_t __nmemb, size_t __size,
245 int (*__compare) (const void *, const void *))
246 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 2) _GL_ARG_NONNULL ((4));
247#endif
248
249
191#if @GNULIB__EXIT@ 250#if @GNULIB__EXIT@
192/* Terminate the current process with the given return code, without running 251/* Terminate the current process with the given return code, without running
193 the 'atexit' handlers. */ 252 the 'atexit' handlers. */
@@ -196,11 +255,11 @@ struct random_data
196# undef _Exit 255# undef _Exit
197# define _Exit rpl__Exit 256# define _Exit rpl__Exit
198# endif 257# endif
199_GL_FUNCDECL_RPL (_Exit, _Noreturn void, (int status)); 258_GL_FUNCDECL_RPL (_Exit, _Noreturn void, (int status), );
200_GL_CXXALIAS_RPL (_Exit, void, (int status)); 259_GL_CXXALIAS_RPL (_Exit, void, (int status));
201# else 260# else
202# if !@HAVE__EXIT@ 261# if !@HAVE__EXIT@
203_GL_FUNCDECL_SYS (_Exit, _Noreturn void, (int status)); 262_GL_FUNCDECL_SYS (_Exit, _Noreturn void, (int status), );
204# endif 263# endif
205_GL_CXXALIAS_SYS (_Exit, void, (int status)); 264_GL_CXXALIAS_SYS (_Exit, void, (int status));
206# endif 265# endif
@@ -216,6 +275,26 @@ _GL_WARN_ON_USE (_Exit, "_Exit is unportable - "
216#endif 275#endif
217 276
218 277
278#if @GNULIB_ABORT_DEBUG@
279/* Terminates the current process with signal SIGABRT.
280 Note: While the original abort() function is safe to call in signal handlers,
281 the overridden abort() function is not. */
282# if @REPLACE_ABORT@
283# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
284# undef abort
285# define abort rpl_abort
286# endif
287_GL_FUNCDECL_RPL (abort, _Noreturn void, (void), );
288_GL_CXXALIAS_RPL (abort, void, (void));
289# else
290_GL_CXXALIAS_SYS (abort, void, (void));
291# endif
292# if __GLIBC__ >= 2
293_GL_CXXALIASWARN (abort);
294# endif
295#endif
296
297
219#if @GNULIB_FREE_POSIX@ 298#if @GNULIB_FREE_POSIX@
220# if @REPLACE_FREE@ 299# if @REPLACE_FREE@
221# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 300# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -223,9 +302,9 @@ _GL_WARN_ON_USE (_Exit, "_Exit is unportable - "
223# define free rpl_free 302# define free rpl_free
224# endif 303# endif
225# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2) 304# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2)
226_GL_FUNCDECL_RPL (free, void, (void *ptr) _GL_ATTRIBUTE_NOTHROW); 305_GL_FUNCDECL_RPL (free, void, (void *ptr), ) _GL_ATTRIBUTE_NOTHROW;
227# else 306# else
228_GL_FUNCDECL_RPL (free, void, (void *ptr)); 307_GL_FUNCDECL_RPL (free, void, (void *ptr), );
229# endif 308# endif
230_GL_CXXALIAS_RPL (free, void, (void *ptr)); 309_GL_CXXALIAS_RPL (free, void, (void *ptr));
231# else 310# else
@@ -237,8 +316,8 @@ _GL_CXXALIASWARN (free);
237#elif defined GNULIB_POSIXCHECK 316#elif defined GNULIB_POSIXCHECK
238# undef free 317# undef free
239/* Assume free is always declared. */ 318/* Assume free is always declared. */
240_GL_WARN_ON_USE (free, "free is not future POSIX compliant everywhere - " 319_GL_WARN_ON_USE (free, "free is not POSIX:2024 compliant everywhere - "
241 "use gnulib module free for portability"); 320 "use gnulib module free-posix for portability");
242#endif 321#endif
243 322
244 323
@@ -250,22 +329,25 @@ _GL_WARN_ON_USE (free, "free is not future POSIX compliant everywhere - "
250# define aligned_alloc rpl_aligned_alloc 329# define aligned_alloc rpl_aligned_alloc
251# endif 330# endif
252_GL_FUNCDECL_RPL (aligned_alloc, void *, 331_GL_FUNCDECL_RPL (aligned_alloc, void *,
253 (size_t alignment, size_t size) 332 (size_t alignment, size_t size),
254 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 333 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
334 _GL_ATTRIBUTE_NODISCARD);
255_GL_CXXALIAS_RPL (aligned_alloc, void *, (size_t alignment, size_t size)); 335_GL_CXXALIAS_RPL (aligned_alloc, void *, (size_t alignment, size_t size));
256# else 336# else
257# if @HAVE_ALIGNED_ALLOC@ 337# if @HAVE_ALIGNED_ALLOC@
258# if __GNUC__ >= 11 338# if __GNUC__ >= 11 && !defined __clang__
259/* For -Wmismatched-dealloc: Associate aligned_alloc with free or rpl_free. */ 339/* For -Wmismatched-dealloc: Associate aligned_alloc with free or rpl_free. */
260# if __GLIBC__ + (__GLIBC_MINOR__ >= 16) > 2 340# if __GLIBC__ + (__GLIBC_MINOR__ >= 16) > 2
261_GL_FUNCDECL_SYS (aligned_alloc, void *, 341_GL_FUNCDECL_SYS (aligned_alloc, void *,
262 (size_t alignment, size_t size) 342 (size_t alignment, size_t size),
263 _GL_ATTRIBUTE_NOTHROW 343 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
264 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 344 _GL_ATTRIBUTE_NODISCARD)
345 _GL_ATTRIBUTE_NOTHROW;
265# else 346# else
266_GL_FUNCDECL_SYS (aligned_alloc, void *, 347_GL_FUNCDECL_SYS (aligned_alloc, void *,
267 (size_t alignment, size_t size) 348 (size_t alignment, size_t size),
268 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 349 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
350 _GL_ATTRIBUTE_NODISCARD);
269# endif 351# endif
270# endif 352# endif
271_GL_CXXALIAS_SYS (aligned_alloc, void *, (size_t alignment, size_t size)); 353_GL_CXXALIAS_SYS (aligned_alloc, void *, (size_t alignment, size_t size));
@@ -275,16 +357,17 @@ _GL_CXXALIAS_SYS (aligned_alloc, void *, (size_t alignment, size_t size));
275_GL_CXXALIASWARN (aligned_alloc); 357_GL_CXXALIASWARN (aligned_alloc);
276# endif 358# endif
277#else 359#else
278# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined aligned_alloc 360# if @GNULIB_FREE_POSIX@ \
361 && (__GNUC__ >= 11 && !defined __clang__) && !defined aligned_alloc
279/* For -Wmismatched-dealloc: Associate aligned_alloc with free or rpl_free. */ 362/* For -Wmismatched-dealloc: Associate aligned_alloc with free or rpl_free. */
280# if __GLIBC__ + (__GLIBC_MINOR__ >= 16) > 2 363# if __GLIBC__ + (__GLIBC_MINOR__ >= 16) > 2
281_GL_FUNCDECL_SYS (aligned_alloc, void *, 364_GL_FUNCDECL_SYS (aligned_alloc, void *,
282 (size_t alignment, size_t size) 365 (size_t alignment, size_t size),
283 _GL_ATTRIBUTE_NOTHROW 366 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE)
284 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 367 _GL_ATTRIBUTE_NOTHROW;
285# else 368# else
286_GL_FUNCDECL_SYS (aligned_alloc, void *, 369_GL_FUNCDECL_SYS (aligned_alloc, void *,
287 (size_t alignment, size_t size) 370 (size_t alignment, size_t size),
288 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 371 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
289# endif 372# endif
290# endif 373# endif
@@ -301,9 +384,10 @@ _GL_WARN_ON_USE (aligned_alloc, "aligned_alloc is not portable - "
301/* Parse a signed decimal integer. 384/* Parse a signed decimal integer.
302 Returns the value of the integer. Errors are not detected. */ 385 Returns the value of the integer. Errors are not detected. */
303# if !@HAVE_ATOLL@ 386# if !@HAVE_ATOLL@
304_GL_FUNCDECL_SYS (atoll, long long, (const char *string) 387_GL_FUNCDECL_SYS (atoll, long long,
305 _GL_ATTRIBUTE_PURE 388 (const char *string),
306 _GL_ARG_NONNULL ((1))); 389 _GL_ATTRIBUTE_PURE
390 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
307# endif 391# endif
308_GL_CXXALIAS_SYS (atoll, long long, (const char *string)); 392_GL_CXXALIAS_SYS (atoll, long long, (const char *string));
309_GL_CXXALIASWARN (atoll); 393_GL_CXXALIASWARN (atoll);
@@ -316,28 +400,32 @@ _GL_WARN_ON_USE (atoll, "atoll is unportable - "
316#endif 400#endif
317 401
318#if @GNULIB_CALLOC_POSIX@ 402#if @GNULIB_CALLOC_POSIX@
319# if (@GNULIB_CALLOC_POSIX@ && @REPLACE_CALLOC_FOR_CALLOC_POSIX@) \ 403# if @REPLACE_CALLOC_FOR_CALLOC_POSIX@ \
320 || (@GNULIB_CALLOC_GNU@ && @REPLACE_CALLOC_FOR_CALLOC_GNU@) 404 || (@GNULIB_CALLOC_GNU@ && @REPLACE_CALLOC_FOR_CALLOC_GNU@)
321# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 405# if !((defined __cplusplus && defined GNULIB_NAMESPACE) \
406 || _GL_USE_STDLIB_ALLOC)
322# undef calloc 407# undef calloc
323# define calloc rpl_calloc 408# define calloc rpl_calloc
324# endif 409# endif
325_GL_FUNCDECL_RPL (calloc, void *, 410_GL_FUNCDECL_RPL (calloc, void *,
326 (size_t nmemb, size_t size) 411 (size_t nmemb, size_t size),
327 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 412 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
413 _GL_ATTRIBUTE_NODISCARD);
328_GL_CXXALIAS_RPL (calloc, void *, (size_t nmemb, size_t size)); 414_GL_CXXALIAS_RPL (calloc, void *, (size_t nmemb, size_t size));
329# else 415# else
330# if __GNUC__ >= 11 416# if __GNUC__ >= 11 && !defined __clang__
331/* For -Wmismatched-dealloc: Associate calloc with free or rpl_free. */ 417/* For -Wmismatched-dealloc: Associate calloc with free or rpl_free. */
332# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2 418# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2
333_GL_FUNCDECL_SYS (calloc, void *, 419_GL_FUNCDECL_SYS (calloc, void *,
334 (size_t nmemb, size_t size) 420 (size_t nmemb, size_t size),
335 _GL_ATTRIBUTE_NOTHROW 421 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
336 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 422 _GL_ATTRIBUTE_NODISCARD)
423 _GL_ATTRIBUTE_NOTHROW;
337# else 424# else
338_GL_FUNCDECL_SYS (calloc, void *, 425_GL_FUNCDECL_SYS (calloc, void *,
339 (size_t nmemb, size_t size) 426 (size_t nmemb, size_t size),
340 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 427 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
428 _GL_ATTRIBUTE_NODISCARD);
341# endif 429# endif
342# endif 430# endif
343_GL_CXXALIAS_SYS (calloc, void *, (size_t nmemb, size_t size)); 431_GL_CXXALIAS_SYS (calloc, void *, (size_t nmemb, size_t size));
@@ -346,16 +434,17 @@ _GL_CXXALIAS_SYS (calloc, void *, (size_t nmemb, size_t size));
346_GL_CXXALIASWARN (calloc); 434_GL_CXXALIASWARN (calloc);
347# endif 435# endif
348#else 436#else
349# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined calloc 437# if @GNULIB_FREE_POSIX@ \
438 && (__GNUC__ >= 11 && !defined __clang__) && !defined calloc
350/* For -Wmismatched-dealloc: Associate calloc with free or rpl_free. */ 439/* For -Wmismatched-dealloc: Associate calloc with free or rpl_free. */
351# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2 440# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2
352_GL_FUNCDECL_SYS (calloc, void *, 441_GL_FUNCDECL_SYS (calloc, void *,
353 (size_t nmemb, size_t size) 442 (size_t nmemb, size_t size),
354 _GL_ATTRIBUTE_NOTHROW 443 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE)
355 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 444 _GL_ATTRIBUTE_NOTHROW;
356# else 445# else
357_GL_FUNCDECL_SYS (calloc, void *, 446_GL_FUNCDECL_SYS (calloc, void *,
358 (size_t nmemb, size_t size) 447 (size_t nmemb, size_t size),
359 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 448 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
360# endif 449# endif
361# endif 450# endif
@@ -373,23 +462,26 @@ _GL_WARN_ON_USE (calloc, "calloc is not POSIX compliant everywhere - "
373# define canonicalize_file_name rpl_canonicalize_file_name 462# define canonicalize_file_name rpl_canonicalize_file_name
374# endif 463# endif
375_GL_FUNCDECL_RPL (canonicalize_file_name, char *, 464_GL_FUNCDECL_RPL (canonicalize_file_name, char *,
376 (const char *name) 465 (const char *name),
377 _GL_ARG_NONNULL ((1)) 466 _GL_ARG_NONNULL ((1))
378 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 467 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
468 _GL_ATTRIBUTE_NODISCARD);
379_GL_CXXALIAS_RPL (canonicalize_file_name, char *, (const char *name)); 469_GL_CXXALIAS_RPL (canonicalize_file_name, char *, (const char *name));
380# else 470# else
381# if !@HAVE_CANONICALIZE_FILE_NAME@ || __GNUC__ >= 11 471# if !@HAVE_CANONICALIZE_FILE_NAME@ || (__GNUC__ >= 11 && !defined __clang__)
382# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2 472# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
383_GL_FUNCDECL_SYS (canonicalize_file_name, char *, 473_GL_FUNCDECL_SYS (canonicalize_file_name, char *,
384 (const char *name) 474 (const char *name),
385 _GL_ATTRIBUTE_NOTHROW
386 _GL_ARG_NONNULL ((1)) 475 _GL_ARG_NONNULL ((1))
387 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 476 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
477 _GL_ATTRIBUTE_NODISCARD)
478 _GL_ATTRIBUTE_NOTHROW;
388# else 479# else
389_GL_FUNCDECL_SYS (canonicalize_file_name, char *, 480_GL_FUNCDECL_SYS (canonicalize_file_name, char *,
390 (const char *name) 481 (const char *name),
391 _GL_ARG_NONNULL ((1)) 482 _GL_ARG_NONNULL ((1))
392 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 483 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
484 _GL_ATTRIBUTE_NODISCARD);
393# endif 485# endif
394# endif 486# endif
395_GL_CXXALIAS_SYS (canonicalize_file_name, char *, (const char *name)); 487_GL_CXXALIAS_SYS (canonicalize_file_name, char *, (const char *name));
@@ -400,18 +492,19 @@ _GL_CXXALIAS_SYS (canonicalize_file_name, char *, (const char *name));
400# endif 492# endif
401_GL_CXXALIASWARN (canonicalize_file_name); 493_GL_CXXALIASWARN (canonicalize_file_name);
402#else 494#else
403# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined canonicalize_file_name 495# if @GNULIB_FREE_POSIX@ \
496 && (__GNUC__ >= 11 && !defined __clang__) && !defined canonicalize_file_name
404/* For -Wmismatched-dealloc: Associate canonicalize_file_name with free or 497/* For -Wmismatched-dealloc: Associate canonicalize_file_name with free or
405 rpl_free. */ 498 rpl_free. */
406# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2 499# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
407_GL_FUNCDECL_SYS (canonicalize_file_name, char *, 500_GL_FUNCDECL_SYS (canonicalize_file_name, char *,
408 (const char *name) 501 (const char *name),
409 _GL_ATTRIBUTE_NOTHROW
410 _GL_ARG_NONNULL ((1)) 502 _GL_ARG_NONNULL ((1))
411 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 503 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE)
504 _GL_ATTRIBUTE_NOTHROW;
412# else 505# else
413_GL_FUNCDECL_SYS (canonicalize_file_name, char *, 506_GL_FUNCDECL_SYS (canonicalize_file_name, char *,
414 (const char *name) 507 (const char *name),
415 _GL_ARG_NONNULL ((1)) 508 _GL_ARG_NONNULL ((1))
416 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 509 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
417# endif 510# endif
@@ -503,12 +596,12 @@ _GL_CXXALIASWARN (gcvt);
503# undef getloadavg 596# undef getloadavg
504# define getloadavg rpl_getloadavg 597# define getloadavg rpl_getloadavg
505# endif 598# endif
506_GL_FUNCDECL_RPL (getloadavg, int, (double loadavg[], int nelem) 599_GL_FUNCDECL_RPL (getloadavg, int, (double loadavg[], int nelem),
507 _GL_ARG_NONNULL ((1))); 600 _GL_ARG_NONNULL ((1)));
508_GL_CXXALIAS_RPL (getloadavg, int, (double loadavg[], int nelem)); 601_GL_CXXALIAS_RPL (getloadavg, int, (double loadavg[], int nelem));
509# else 602# else
510# if !@HAVE_DECL_GETLOADAVG@ 603# if !@HAVE_DECL_GETLOADAVG@
511_GL_FUNCDECL_SYS (getloadavg, int, (double loadavg[], int nelem) 604_GL_FUNCDECL_SYS (getloadavg, int, (double loadavg[], int nelem),
512 _GL_ARG_NONNULL ((1))); 605 _GL_ARG_NONNULL ((1)));
513# endif 606# endif
514_GL_CXXALIAS_SYS (getloadavg, int, (double loadavg[], int nelem)); 607_GL_CXXALIAS_SYS (getloadavg, int, (double loadavg[], int nelem));
@@ -533,17 +626,17 @@ _GL_WARN_ON_USE (getloadavg, "getloadavg is not portable - "
533# define getprogname rpl_getprogname 626# define getprogname rpl_getprogname
534# endif 627# endif
535# if @HAVE_DECL_PROGRAM_INVOCATION_NAME@ 628# if @HAVE_DECL_PROGRAM_INVOCATION_NAME@
536_GL_FUNCDECL_RPL (getprogname, const char *, (void) _GL_ATTRIBUTE_PURE); 629_GL_FUNCDECL_RPL (getprogname, const char *, (void), _GL_ATTRIBUTE_PURE);
537# else 630# else
538_GL_FUNCDECL_RPL (getprogname, const char *, (void)); 631_GL_FUNCDECL_RPL (getprogname, const char *, (void), );
539# endif 632# endif
540_GL_CXXALIAS_RPL (getprogname, const char *, (void)); 633_GL_CXXALIAS_RPL (getprogname, const char *, (void));
541# else 634# else
542# if !@HAVE_GETPROGNAME@ 635# if !@HAVE_GETPROGNAME@
543# if @HAVE_DECL_PROGRAM_INVOCATION_NAME@ 636# if @HAVE_DECL_PROGRAM_INVOCATION_NAME@
544_GL_FUNCDECL_SYS (getprogname, const char *, (void) _GL_ATTRIBUTE_PURE); 637_GL_FUNCDECL_SYS (getprogname, const char *, (void), _GL_ATTRIBUTE_PURE);
545# else 638# else
546_GL_FUNCDECL_SYS (getprogname, const char *, (void)); 639_GL_FUNCDECL_SYS (getprogname, const char *, (void), );
547# endif 640# endif
548# endif 641# endif
549_GL_CXXALIAS_SYS (getprogname, const char *, (void)); 642_GL_CXXALIAS_SYS (getprogname, const char *, (void));
@@ -577,15 +670,15 @@ _GL_WARN_ON_USE (getprogname, "getprogname is unportable - "
577# define getsubopt rpl_getsubopt 670# define getsubopt rpl_getsubopt
578# endif 671# endif
579_GL_FUNCDECL_RPL (getsubopt, int, 672_GL_FUNCDECL_RPL (getsubopt, int,
580 (char **optionp, char *const *tokens, char **valuep) 673 (char **optionp, char *const *tokens, char **valuep),
581 _GL_ARG_NONNULL ((1, 2, 3))); 674 _GL_ARG_NONNULL ((1, 2, 3)) _GL_ATTRIBUTE_NODISCARD);
582_GL_CXXALIAS_RPL (getsubopt, int, 675_GL_CXXALIAS_RPL (getsubopt, int,
583 (char **optionp, char *const *tokens, char **valuep)); 676 (char **optionp, char *const *tokens, char **valuep));
584# else 677# else
585# if !@HAVE_GETSUBOPT@ 678# if !@HAVE_GETSUBOPT@
586_GL_FUNCDECL_SYS (getsubopt, int, 679_GL_FUNCDECL_SYS (getsubopt, int,
587 (char **optionp, char *const *tokens, char **valuep) 680 (char **optionp, char *const *tokens, char **valuep),
588 _GL_ARG_NONNULL ((1, 2, 3))); 681 _GL_ARG_NONNULL ((1, 2, 3)) _GL_ATTRIBUTE_NODISCARD);
589# endif 682# endif
590_GL_CXXALIAS_SYS (getsubopt, int, 683_GL_CXXALIAS_SYS (getsubopt, int,
591 (char **optionp, char *const *tokens, char **valuep)); 684 (char **optionp, char *const *tokens, char **valuep));
@@ -605,7 +698,7 @@ _GL_WARN_ON_USE (getsubopt, "getsubopt is unportable - "
605/* Change the ownership and access permission of the slave side of the 698/* Change the ownership and access permission of the slave side of the
606 pseudo-terminal whose master side is specified by FD. */ 699 pseudo-terminal whose master side is specified by FD. */
607# if !@HAVE_GRANTPT@ 700# if !@HAVE_GRANTPT@
608_GL_FUNCDECL_SYS (grantpt, int, (int fd)); 701_GL_FUNCDECL_SYS (grantpt, int, (int fd), );
609# endif 702# endif
610_GL_CXXALIAS_SYS (grantpt, int, (int fd)); 703_GL_CXXALIAS_SYS (grantpt, int, (int fd));
611_GL_CXXALIASWARN (grantpt); 704_GL_CXXALIASWARN (grantpt);
@@ -622,7 +715,7 @@ _GL_WARN_ON_USE (grantpt, "grantpt is not portable - "
622 by never specifying a zero size), so it does not need malloc or 715 by never specifying a zero size), so it does not need malloc or
623 realloc to be redefined. */ 716 realloc to be redefined. */
624#if @GNULIB_MALLOC_POSIX@ 717#if @GNULIB_MALLOC_POSIX@
625# if (@GNULIB_MALLOC_POSIX@ && @REPLACE_MALLOC_FOR_MALLOC_POSIX@) \ 718# if @REPLACE_MALLOC_FOR_MALLOC_POSIX@ \
626 || (@GNULIB_MALLOC_GNU@ && @REPLACE_MALLOC_FOR_MALLOC_GNU@) 719 || (@GNULIB_MALLOC_GNU@ && @REPLACE_MALLOC_FOR_MALLOC_GNU@)
627# if !((defined __cplusplus && defined GNULIB_NAMESPACE) \ 720# if !((defined __cplusplus && defined GNULIB_NAMESPACE) \
628 || _GL_USE_STDLIB_ALLOC) 721 || _GL_USE_STDLIB_ALLOC)
@@ -630,21 +723,24 @@ _GL_WARN_ON_USE (grantpt, "grantpt is not portable - "
630# define malloc rpl_malloc 723# define malloc rpl_malloc
631# endif 724# endif
632_GL_FUNCDECL_RPL (malloc, void *, 725_GL_FUNCDECL_RPL (malloc, void *,
633 (size_t size) 726 (size_t size),
634 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 727 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
728 _GL_ATTRIBUTE_NODISCARD);
635_GL_CXXALIAS_RPL (malloc, void *, (size_t size)); 729_GL_CXXALIAS_RPL (malloc, void *, (size_t size));
636# else 730# else
637# if __GNUC__ >= 11 731# if __GNUC__ >= 11 && !defined __clang__
638/* For -Wmismatched-dealloc: Associate malloc with free or rpl_free. */ 732/* For -Wmismatched-dealloc: Associate malloc with free or rpl_free. */
639# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2 733# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2
640_GL_FUNCDECL_SYS (malloc, void *, 734_GL_FUNCDECL_SYS (malloc, void *,
641 (size_t size) 735 (size_t size),
642 _GL_ATTRIBUTE_NOTHROW 736 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
643 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 737 _GL_ATTRIBUTE_NODISCARD)
738 _GL_ATTRIBUTE_NOTHROW;
644# else 739# else
645_GL_FUNCDECL_SYS (malloc, void *, 740_GL_FUNCDECL_SYS (malloc, void *,
646 (size_t size) 741 (size_t size),
647 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 742 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
743 _GL_ATTRIBUTE_NODISCARD);
648# endif 744# endif
649# endif 745# endif
650_GL_CXXALIAS_SYS (malloc, void *, (size_t size)); 746_GL_CXXALIAS_SYS (malloc, void *, (size_t size));
@@ -653,16 +749,17 @@ _GL_CXXALIAS_SYS (malloc, void *, (size_t size));
653_GL_CXXALIASWARN (malloc); 749_GL_CXXALIASWARN (malloc);
654# endif 750# endif
655#else 751#else
656# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined malloc 752# if @GNULIB_FREE_POSIX@ \
753 && (__GNUC__ >= 11 && !defined __clang__) && !defined malloc
657/* For -Wmismatched-dealloc: Associate malloc with free or rpl_free. */ 754/* For -Wmismatched-dealloc: Associate malloc with free or rpl_free. */
658# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2 755# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2
659_GL_FUNCDECL_SYS (malloc, void *, 756_GL_FUNCDECL_SYS (malloc, void *,
660 (size_t size) 757 (size_t size),
661 _GL_ATTRIBUTE_NOTHROW 758 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE)
662 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 759 _GL_ATTRIBUTE_NOTHROW;
663# else 760# else
664_GL_FUNCDECL_SYS (malloc, void *, 761_GL_FUNCDECL_SYS (malloc, void *,
665 (size_t size) 762 (size_t size),
666 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 763 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
667# endif 764# endif
668# endif 765# endif
@@ -674,14 +771,20 @@ _GL_WARN_ON_USE (malloc, "malloc is not POSIX compliant everywhere - "
674# endif 771# endif
675#endif 772#endif
676 773
677/* Return maximum number of bytes of a multibyte character. */ 774/* Return maximum number of bytes in a multibyte character in the
775 current locale. */
678#if @REPLACE_MB_CUR_MAX@ 776#if @REPLACE_MB_CUR_MAX@
679# if !GNULIB_defined_MB_CUR_MAX 777# if !GNULIB_defined_MB_CUR_MAX
680static inline 778_GL_STDLIB_INLINE size_t
681int gl_MB_CUR_MAX (void) 779gl_MB_CUR_MAX (void)
682{ 780{
781# if 0 < @REPLACE_MB_CUR_MAX@
782 return @REPLACE_MB_CUR_MAX@;
783# else
683 /* Turn the value 3 to the value 4, as needed for the UTF-8 encoding. */ 784 /* Turn the value 3 to the value 4, as needed for the UTF-8 encoding. */
684 return MB_CUR_MAX + (MB_CUR_MAX == 3); 785 int gl_mb_cur_max = MB_CUR_MAX;
786 return gl_mb_cur_max == 3 ? 4 : gl_mb_cur_max;
787# endif
685} 788}
686# undef MB_CUR_MAX 789# undef MB_CUR_MAX
687# define MB_CUR_MAX gl_MB_CUR_MAX () 790# define MB_CUR_MAX gl_MB_CUR_MAX ()
@@ -698,7 +801,7 @@ int gl_MB_CUR_MAX (void)
698# endif 801# endif
699_GL_FUNCDECL_RPL (mbstowcs, size_t, 802_GL_FUNCDECL_RPL (mbstowcs, size_t,
700 (wchar_t *restrict dest, const char *restrict src, 803 (wchar_t *restrict dest, const char *restrict src,
701 size_t len) 804 size_t len),
702 _GL_ARG_NONNULL ((2))); 805 _GL_ARG_NONNULL ((2)));
703_GL_CXXALIAS_RPL (mbstowcs, size_t, 806_GL_CXXALIAS_RPL (mbstowcs, size_t,
704 (wchar_t *restrict dest, const char *restrict src, 807 (wchar_t *restrict dest, const char *restrict src,
@@ -727,13 +830,13 @@ _GL_WARN_ON_USE (mbstowcs, "mbstowcs is unportable - "
727# define mbtowc rpl_mbtowc 830# define mbtowc rpl_mbtowc
728# endif 831# endif
729_GL_FUNCDECL_RPL (mbtowc, int, 832_GL_FUNCDECL_RPL (mbtowc, int,
730 (wchar_t *restrict pwc, const char *restrict s, size_t n)); 833 (wchar_t *restrict pwc, const char *restrict s, size_t n), );
731_GL_CXXALIAS_RPL (mbtowc, int, 834_GL_CXXALIAS_RPL (mbtowc, int,
732 (wchar_t *restrict pwc, const char *restrict s, size_t n)); 835 (wchar_t *restrict pwc, const char *restrict s, size_t n));
733# else 836# else
734# if !@HAVE_MBTOWC@ 837# if !@HAVE_MBTOWC@
735_GL_FUNCDECL_SYS (mbtowc, int, 838_GL_FUNCDECL_SYS (mbtowc, int,
736 (wchar_t *restrict pwc, const char *restrict s, size_t n)); 839 (wchar_t *restrict pwc, const char *restrict s, size_t n), );
737# endif 840# endif
738_GL_CXXALIAS_SYS (mbtowc, int, 841_GL_CXXALIAS_SYS (mbtowc, int,
739 (wchar_t *restrict pwc, const char *restrict s, size_t n)); 842 (wchar_t *restrict pwc, const char *restrict s, size_t n));
@@ -756,7 +859,9 @@ _GL_WARN_ON_USE (mbtowc, "mbtowc is not portable - "
756 Returns TEMPLATE, or a null pointer if it cannot get a unique name. 859 Returns TEMPLATE, or a null pointer if it cannot get a unique name.
757 The directory is created mode 700. */ 860 The directory is created mode 700. */
758# if !@HAVE_MKDTEMP@ 861# if !@HAVE_MKDTEMP@
759_GL_FUNCDECL_SYS (mkdtemp, char *, (char * /*template*/) _GL_ARG_NONNULL ((1))); 862_GL_FUNCDECL_SYS (mkdtemp, char *,
863 (char * /*template*/),
864 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
760# endif 865# endif
761_GL_CXXALIAS_SYS (mkdtemp, char *, (char * /*template*/)); 866_GL_CXXALIAS_SYS (mkdtemp, char *, (char * /*template*/));
762_GL_CXXALIASWARN (mkdtemp); 867_GL_CXXALIASWARN (mkdtemp);
@@ -786,13 +891,13 @@ _GL_WARN_ON_USE (mkdtemp, "mkdtemp is unportable - "
786# undef mkostemp 891# undef mkostemp
787# define mkostemp rpl_mkostemp 892# define mkostemp rpl_mkostemp
788# endif 893# endif
789_GL_FUNCDECL_RPL (mkostemp, int, (char * /*template*/, int /*flags*/) 894_GL_FUNCDECL_RPL (mkostemp, int, (char * /*template*/, int /*flags*/),
790 _GL_ARG_NONNULL ((1))); 895 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
791_GL_CXXALIAS_RPL (mkostemp, int, (char * /*template*/, int /*flags*/)); 896_GL_CXXALIAS_RPL (mkostemp, int, (char * /*template*/, int /*flags*/));
792# else 897# else
793# if !@HAVE_MKOSTEMP@ 898# if !@HAVE_MKOSTEMP@
794_GL_FUNCDECL_SYS (mkostemp, int, (char * /*template*/, int /*flags*/) 899_GL_FUNCDECL_SYS (mkostemp, int, (char * /*template*/, int /*flags*/),
795 _GL_ARG_NONNULL ((1))); 900 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
796# endif 901# endif
797_GL_CXXALIAS_SYS (mkostemp, int, (char * /*template*/, int /*flags*/)); 902_GL_CXXALIAS_SYS (mkostemp, int, (char * /*template*/, int /*flags*/));
798# endif 903# endif
@@ -827,15 +932,15 @@ _GL_WARN_ON_USE (mkostemp, "mkostemp is unportable - "
827# define mkostemps rpl_mkostemps 932# define mkostemps rpl_mkostemps
828# endif 933# endif
829_GL_FUNCDECL_RPL (mkostemps, int, 934_GL_FUNCDECL_RPL (mkostemps, int,
830 (char * /*template*/, int /*suffixlen*/, int /*flags*/) 935 (char * /*template*/, int /*suffixlen*/, int /*flags*/),
831 _GL_ARG_NONNULL ((1))); 936 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
832_GL_CXXALIAS_RPL (mkostemps, int, 937_GL_CXXALIAS_RPL (mkostemps, int,
833 (char * /*template*/, int /*suffixlen*/, int /*flags*/)); 938 (char * /*template*/, int /*suffixlen*/, int /*flags*/));
834# else 939# else
835# if !@HAVE_MKOSTEMPS@ 940# if !@HAVE_MKOSTEMPS@
836_GL_FUNCDECL_SYS (mkostemps, int, 941_GL_FUNCDECL_SYS (mkostemps, int,
837 (char * /*template*/, int /*suffixlen*/, int /*flags*/) 942 (char * /*template*/, int /*suffixlen*/, int /*flags*/),
838 _GL_ARG_NONNULL ((1))); 943 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
839# endif 944# endif
840_GL_CXXALIAS_SYS (mkostemps, int, 945_GL_CXXALIAS_SYS (mkostemps, int,
841 (char * /*template*/, int /*suffixlen*/, int /*flags*/)); 946 (char * /*template*/, int /*suffixlen*/, int /*flags*/));
@@ -865,11 +970,13 @@ _GL_WARN_ON_USE (mkostemps, "mkostemps is unportable - "
865# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 970# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
866# define mkstemp rpl_mkstemp 971# define mkstemp rpl_mkstemp
867# endif 972# endif
868_GL_FUNCDECL_RPL (mkstemp, int, (char * /*template*/) _GL_ARG_NONNULL ((1))); 973_GL_FUNCDECL_RPL (mkstemp, int, (char * /*template*/),
974 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
869_GL_CXXALIAS_RPL (mkstemp, int, (char * /*template*/)); 975_GL_CXXALIAS_RPL (mkstemp, int, (char * /*template*/));
870# else 976# else
871# if ! @HAVE_MKSTEMP@ 977# if ! @HAVE_MKSTEMP@
872_GL_FUNCDECL_SYS (mkstemp, int, (char * /*template*/) _GL_ARG_NONNULL ((1))); 978_GL_FUNCDECL_SYS (mkstemp, int, (char * /*template*/),
979 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
873# endif 980# endif
874_GL_CXXALIAS_SYS (mkstemp, int, (char * /*template*/)); 981_GL_CXXALIAS_SYS (mkstemp, int, (char * /*template*/));
875# endif 982# endif
@@ -894,8 +1001,8 @@ _GL_WARN_ON_USE (mkstemp, "mkstemp is unportable - "
894 Returns the open file descriptor if successful, otherwise -1 and errno 1001 Returns the open file descriptor if successful, otherwise -1 and errno
895 set. */ 1002 set. */
896# if !@HAVE_MKSTEMPS@ 1003# if !@HAVE_MKSTEMPS@
897_GL_FUNCDECL_SYS (mkstemps, int, (char * /*template*/, int /*suffixlen*/) 1004_GL_FUNCDECL_SYS (mkstemps, int, (char * /*template*/, int /*suffixlen*/),
898 _GL_ARG_NONNULL ((1))); 1005 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
899# endif 1006# endif
900_GL_CXXALIAS_SYS (mkstemps, int, (char * /*template*/, int /*suffixlen*/)); 1007_GL_CXXALIAS_SYS (mkstemps, int, (char * /*template*/, int /*suffixlen*/));
901_GL_CXXALIASWARN (mkstemps); 1008_GL_CXXALIASWARN (mkstemps);
@@ -931,8 +1038,8 @@ _GL_CXXALIASWARN (mktemp);
931# define posix_memalign rpl_posix_memalign 1038# define posix_memalign rpl_posix_memalign
932# endif 1039# endif
933_GL_FUNCDECL_RPL (posix_memalign, int, 1040_GL_FUNCDECL_RPL (posix_memalign, int,
934 (void **memptr, size_t alignment, size_t size) 1041 (void **memptr, size_t alignment, size_t size),
935 _GL_ARG_NONNULL ((1))); 1042 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
936_GL_CXXALIAS_RPL (posix_memalign, int, 1043_GL_CXXALIAS_RPL (posix_memalign, int,
937 (void **memptr, size_t alignment, size_t size)); 1044 (void **memptr, size_t alignment, size_t size));
938# else 1045# else
@@ -960,11 +1067,11 @@ _GL_WARN_ON_USE (posix_memalign, "posix_memalign is not portable - "
960# undef posix_openpt 1067# undef posix_openpt
961# define posix_openpt rpl_posix_openpt 1068# define posix_openpt rpl_posix_openpt
962# endif 1069# endif
963_GL_FUNCDECL_RPL (posix_openpt, int, (int flags)); 1070_GL_FUNCDECL_RPL (posix_openpt, int, (int flags), _GL_ATTRIBUTE_NODISCARD);
964_GL_CXXALIAS_RPL (posix_openpt, int, (int flags)); 1071_GL_CXXALIAS_RPL (posix_openpt, int, (int flags));
965# else 1072# else
966# if !@HAVE_POSIX_OPENPT@ 1073# if !@HAVE_POSIX_OPENPT@
967_GL_FUNCDECL_SYS (posix_openpt, int, (int flags)); 1074_GL_FUNCDECL_SYS (posix_openpt, int, (int flags), _GL_ATTRIBUTE_NODISCARD);
968# endif 1075# endif
969_GL_CXXALIAS_SYS (posix_openpt, int, (int flags)); 1076_GL_CXXALIAS_SYS (posix_openpt, int, (int flags));
970# endif 1077# endif
@@ -987,11 +1094,11 @@ _GL_WARN_ON_USE (posix_openpt, "posix_openpt is not portable - "
987# undef ptsname 1094# undef ptsname
988# define ptsname rpl_ptsname 1095# define ptsname rpl_ptsname
989# endif 1096# endif
990_GL_FUNCDECL_RPL (ptsname, char *, (int fd)); 1097_GL_FUNCDECL_RPL (ptsname, char *, (int fd), _GL_ATTRIBUTE_NODISCARD);
991_GL_CXXALIAS_RPL (ptsname, char *, (int fd)); 1098_GL_CXXALIAS_RPL (ptsname, char *, (int fd));
992# else 1099# else
993# if !@HAVE_PTSNAME@ 1100# if !@HAVE_PTSNAME@
994_GL_FUNCDECL_SYS (ptsname, char *, (int fd)); 1101_GL_FUNCDECL_SYS (ptsname, char *, (int fd), _GL_ATTRIBUTE_NODISCARD);
995# endif 1102# endif
996_GL_CXXALIAS_SYS (ptsname, char *, (int fd)); 1103_GL_CXXALIAS_SYS (ptsname, char *, (int fd));
997# endif 1104# endif
@@ -1013,11 +1120,11 @@ _GL_WARN_ON_USE (ptsname, "ptsname is not portable - "
1013# undef ptsname_r 1120# undef ptsname_r
1014# define ptsname_r rpl_ptsname_r 1121# define ptsname_r rpl_ptsname_r
1015# endif 1122# endif
1016_GL_FUNCDECL_RPL (ptsname_r, int, (int fd, char *buf, size_t len)); 1123_GL_FUNCDECL_RPL (ptsname_r, int, (int fd, char *buf, size_t len), );
1017_GL_CXXALIAS_RPL (ptsname_r, int, (int fd, char *buf, size_t len)); 1124_GL_CXXALIAS_RPL (ptsname_r, int, (int fd, char *buf, size_t len));
1018# else 1125# else
1019# if !@HAVE_PTSNAME_R@ 1126# if !@HAVE_PTSNAME_R@
1020_GL_FUNCDECL_SYS (ptsname_r, int, (int fd, char *buf, size_t len)); 1127_GL_FUNCDECL_SYS (ptsname_r, int, (int fd, char *buf, size_t len), );
1021# endif 1128# endif
1022_GL_CXXALIAS_SYS (ptsname_r, int, (int fd, char *buf, size_t len)); 1129_GL_CXXALIAS_SYS (ptsname_r, int, (int fd, char *buf, size_t len));
1023# endif 1130# endif
@@ -1039,7 +1146,7 @@ _GL_WARN_ON_USE (ptsname_r, "ptsname_r is not portable - "
1039# undef putenv 1146# undef putenv
1040# define putenv rpl_putenv 1147# define putenv rpl_putenv
1041# endif 1148# endif
1042_GL_FUNCDECL_RPL (putenv, int, (char *string) _GL_ARG_NONNULL ((1))); 1149_GL_FUNCDECL_RPL (putenv, int, (char *string), _GL_ARG_NONNULL ((1)));
1043_GL_CXXALIAS_RPL (putenv, int, (char *string)); 1150_GL_CXXALIAS_RPL (putenv, int, (char *string));
1044# elif defined _WIN32 && !defined __CYGWIN__ 1151# elif defined _WIN32 && !defined __CYGWIN__
1045# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1152# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -1098,7 +1205,9 @@ typedef int (*_gl_qsort_r_compar_fn) (void const *, void const *, void *);
1098# endif 1205# endif
1099_GL_FUNCDECL_RPL (qsort_r, void, (void *base, size_t nmemb, size_t size, 1206_GL_FUNCDECL_RPL (qsort_r, void, (void *base, size_t nmemb, size_t size,
1100 _gl_qsort_r_compar_fn compare, 1207 _gl_qsort_r_compar_fn compare,
1101 void *arg) _GL_ARG_NONNULL ((1, 4))); 1208 void *arg),
1209 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 2)
1210 _GL_ARG_NONNULL ((4)));
1102_GL_CXXALIAS_RPL (qsort_r, void, (void *base, size_t nmemb, size_t size, 1211_GL_CXXALIAS_RPL (qsort_r, void, (void *base, size_t nmemb, size_t size,
1103 _gl_qsort_r_compar_fn compare, 1212 _gl_qsort_r_compar_fn compare,
1104 void *arg)); 1213 void *arg));
@@ -1106,7 +1215,9 @@ _GL_CXXALIAS_RPL (qsort_r, void, (void *base, size_t nmemb, size_t size,
1106# if !@HAVE_QSORT_R@ 1215# if !@HAVE_QSORT_R@
1107_GL_FUNCDECL_SYS (qsort_r, void, (void *base, size_t nmemb, size_t size, 1216_GL_FUNCDECL_SYS (qsort_r, void, (void *base, size_t nmemb, size_t size,
1108 _gl_qsort_r_compar_fn compare, 1217 _gl_qsort_r_compar_fn compare,
1109 void *arg) _GL_ARG_NONNULL ((1, 4))); 1218 void *arg),
1219 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 2)
1220 _GL_ARG_NONNULL ((4)));
1110# endif 1221# endif
1111_GL_CXXALIAS_SYS (qsort_r, void, (void *base, size_t nmemb, size_t size, 1222_GL_CXXALIAS_SYS (qsort_r, void, (void *base, size_t nmemb, size_t size,
1112 _gl_qsort_r_compar_fn compare, 1223 _gl_qsort_r_compar_fn compare,
@@ -1137,7 +1248,7 @@ _GL_WARN_ON_USE (qsort_r, "qsort_r is not portable - "
1137# undef rand 1248# undef rand
1138# define rand rpl_rand 1249# define rand rpl_rand
1139# endif 1250# endif
1140_GL_FUNCDECL_RPL (rand, int, (void)); 1251_GL_FUNCDECL_RPL (rand, int, (void), );
1141_GL_CXXALIAS_RPL (rand, int, (void)); 1252_GL_CXXALIAS_RPL (rand, int, (void));
1142# else 1253# else
1143_GL_CXXALIAS_SYS (rand, int, (void)); 1254_GL_CXXALIAS_SYS (rand, int, (void));
@@ -1154,11 +1265,11 @@ _GL_CXXALIASWARN (rand);
1154# undef random 1265# undef random
1155# define random rpl_random 1266# define random rpl_random
1156# endif 1267# endif
1157_GL_FUNCDECL_RPL (random, long, (void)); 1268_GL_FUNCDECL_RPL (random, long, (void), );
1158_GL_CXXALIAS_RPL (random, long, (void)); 1269_GL_CXXALIAS_RPL (random, long, (void));
1159# else 1270# else
1160# if !@HAVE_RANDOM@ 1271# if !@HAVE_RANDOM@
1161_GL_FUNCDECL_SYS (random, long, (void)); 1272_GL_FUNCDECL_SYS (random, long, (void), );
1162# endif 1273# endif
1163/* Need to cast, because on Haiku, the return type is 1274/* Need to cast, because on Haiku, the return type is
1164 int. */ 1275 int. */
@@ -1181,11 +1292,11 @@ _GL_WARN_ON_USE (random, "random is unportable - "
1181# undef srandom 1292# undef srandom
1182# define srandom rpl_srandom 1293# define srandom rpl_srandom
1183# endif 1294# endif
1184_GL_FUNCDECL_RPL (srandom, void, (unsigned int seed)); 1295_GL_FUNCDECL_RPL (srandom, void, (unsigned int seed), );
1185_GL_CXXALIAS_RPL (srandom, void, (unsigned int seed)); 1296_GL_CXXALIAS_RPL (srandom, void, (unsigned int seed));
1186# else 1297# else
1187# if !@HAVE_RANDOM@ 1298# if !@HAVE_RANDOM@
1188_GL_FUNCDECL_SYS (srandom, void, (unsigned int seed)); 1299_GL_FUNCDECL_SYS (srandom, void, (unsigned int seed), );
1189# endif 1300# endif
1190/* Need to cast, because on FreeBSD, the first parameter is 1301/* Need to cast, because on FreeBSD, the first parameter is
1191 unsigned long seed. */ 1302 unsigned long seed. */
@@ -1209,14 +1320,14 @@ _GL_WARN_ON_USE (srandom, "srandom is unportable - "
1209# define initstate rpl_initstate 1320# define initstate rpl_initstate
1210# endif 1321# endif
1211_GL_FUNCDECL_RPL (initstate, char *, 1322_GL_FUNCDECL_RPL (initstate, char *,
1212 (unsigned int seed, char *buf, size_t buf_size) 1323 (unsigned int seed, char *buf, size_t buf_size),
1213 _GL_ARG_NONNULL ((2))); 1324 _GL_ARG_NONNULL ((2)));
1214_GL_CXXALIAS_RPL (initstate, char *, 1325_GL_CXXALIAS_RPL (initstate, char *,
1215 (unsigned int seed, char *buf, size_t buf_size)); 1326 (unsigned int seed, char *buf, size_t buf_size));
1216# else 1327# else
1217# if !@HAVE_INITSTATE@ || !@HAVE_DECL_INITSTATE@ 1328# if !@HAVE_INITSTATE@ || !@HAVE_DECL_INITSTATE@
1218_GL_FUNCDECL_SYS (initstate, char *, 1329_GL_FUNCDECL_SYS (initstate, char *,
1219 (unsigned int seed, char *buf, size_t buf_size) 1330 (unsigned int seed, char *buf, size_t buf_size),
1220 _GL_ARG_NONNULL ((2))); 1331 _GL_ARG_NONNULL ((2)));
1221# endif 1332# endif
1222/* Need to cast, because on FreeBSD, the first parameter is 1333/* Need to cast, because on FreeBSD, the first parameter is
@@ -1241,11 +1352,11 @@ _GL_WARN_ON_USE (initstate, "initstate is unportable - "
1241# undef setstate 1352# undef setstate
1242# define setstate rpl_setstate 1353# define setstate rpl_setstate
1243# endif 1354# endif
1244_GL_FUNCDECL_RPL (setstate, char *, (char *arg_state) _GL_ARG_NONNULL ((1))); 1355_GL_FUNCDECL_RPL (setstate, char *, (char *arg_state), _GL_ARG_NONNULL ((1)));
1245_GL_CXXALIAS_RPL (setstate, char *, (char *arg_state)); 1356_GL_CXXALIAS_RPL (setstate, char *, (char *arg_state));
1246# else 1357# else
1247# if !@HAVE_SETSTATE@ || !@HAVE_DECL_SETSTATE@ 1358# if !@HAVE_SETSTATE@ || !@HAVE_DECL_SETSTATE@
1248_GL_FUNCDECL_SYS (setstate, char *, (char *arg_state) _GL_ARG_NONNULL ((1))); 1359_GL_FUNCDECL_SYS (setstate, char *, (char *arg_state), _GL_ARG_NONNULL ((1)));
1249# endif 1360# endif
1250/* Need to cast, because on Mac OS X 10.13, HP-UX, Solaris the first parameter 1361/* Need to cast, because on Mac OS X 10.13, HP-UX, Solaris the first parameter
1251 is const char *arg_state. */ 1362 is const char *arg_state. */
@@ -1269,12 +1380,12 @@ _GL_WARN_ON_USE (setstate, "setstate is unportable - "
1269# undef random_r 1380# undef random_r
1270# define random_r rpl_random_r 1381# define random_r rpl_random_r
1271# endif 1382# endif
1272_GL_FUNCDECL_RPL (random_r, int, (struct random_data *buf, int32_t *result) 1383_GL_FUNCDECL_RPL (random_r, int, (struct random_data *buf, int32_t *result),
1273 _GL_ARG_NONNULL ((1, 2))); 1384 _GL_ARG_NONNULL ((1, 2)));
1274_GL_CXXALIAS_RPL (random_r, int, (struct random_data *buf, int32_t *result)); 1385_GL_CXXALIAS_RPL (random_r, int, (struct random_data *buf, int32_t *result));
1275# else 1386# else
1276# if !@HAVE_RANDOM_R@ 1387# if !@HAVE_RANDOM_R@
1277_GL_FUNCDECL_SYS (random_r, int, (struct random_data *buf, int32_t *result) 1388_GL_FUNCDECL_SYS (random_r, int, (struct random_data *buf, int32_t *result),
1278 _GL_ARG_NONNULL ((1, 2))); 1389 _GL_ARG_NONNULL ((1, 2)));
1279# endif 1390# endif
1280_GL_CXXALIAS_SYS (random_r, int, (struct random_data *buf, int32_t *result)); 1391_GL_CXXALIAS_SYS (random_r, int, (struct random_data *buf, int32_t *result));
@@ -1295,14 +1406,14 @@ _GL_WARN_ON_USE (random_r, "random_r is unportable - "
1295# define srandom_r rpl_srandom_r 1406# define srandom_r rpl_srandom_r
1296# endif 1407# endif
1297_GL_FUNCDECL_RPL (srandom_r, int, 1408_GL_FUNCDECL_RPL (srandom_r, int,
1298 (unsigned int seed, struct random_data *rand_state) 1409 (unsigned int seed, struct random_data *rand_state),
1299 _GL_ARG_NONNULL ((2))); 1410 _GL_ARG_NONNULL ((2)));
1300_GL_CXXALIAS_RPL (srandom_r, int, 1411_GL_CXXALIAS_RPL (srandom_r, int,
1301 (unsigned int seed, struct random_data *rand_state)); 1412 (unsigned int seed, struct random_data *rand_state));
1302# else 1413# else
1303# if !@HAVE_RANDOM_R@ 1414# if !@HAVE_RANDOM_R@
1304_GL_FUNCDECL_SYS (srandom_r, int, 1415_GL_FUNCDECL_SYS (srandom_r, int,
1305 (unsigned int seed, struct random_data *rand_state) 1416 (unsigned int seed, struct random_data *rand_state),
1306 _GL_ARG_NONNULL ((2))); 1417 _GL_ARG_NONNULL ((2)));
1307# endif 1418# endif
1308_GL_CXXALIAS_SYS (srandom_r, int, 1419_GL_CXXALIAS_SYS (srandom_r, int,
@@ -1325,7 +1436,7 @@ _GL_WARN_ON_USE (srandom_r, "srandom_r is unportable - "
1325# endif 1436# endif
1326_GL_FUNCDECL_RPL (initstate_r, int, 1437_GL_FUNCDECL_RPL (initstate_r, int,
1327 (unsigned int seed, char *buf, size_t buf_size, 1438 (unsigned int seed, char *buf, size_t buf_size,
1328 struct random_data *rand_state) 1439 struct random_data *rand_state),
1329 _GL_ARG_NONNULL ((2, 4))); 1440 _GL_ARG_NONNULL ((2, 4)));
1330_GL_CXXALIAS_RPL (initstate_r, int, 1441_GL_CXXALIAS_RPL (initstate_r, int,
1331 (unsigned int seed, char *buf, size_t buf_size, 1442 (unsigned int seed, char *buf, size_t buf_size,
@@ -1334,7 +1445,7 @@ _GL_CXXALIAS_RPL (initstate_r, int,
1334# if !@HAVE_RANDOM_R@ 1445# if !@HAVE_RANDOM_R@
1335_GL_FUNCDECL_SYS (initstate_r, int, 1446_GL_FUNCDECL_SYS (initstate_r, int,
1336 (unsigned int seed, char *buf, size_t buf_size, 1447 (unsigned int seed, char *buf, size_t buf_size,
1337 struct random_data *rand_state) 1448 struct random_data *rand_state),
1338 _GL_ARG_NONNULL ((2, 4))); 1449 _GL_ARG_NONNULL ((2, 4)));
1339# endif 1450# endif
1340/* Need to cast, because on Haiku, the third parameter is 1451/* Need to cast, because on Haiku, the third parameter is
@@ -1359,14 +1470,14 @@ _GL_WARN_ON_USE (initstate_r, "initstate_r is unportable - "
1359# define setstate_r rpl_setstate_r 1470# define setstate_r rpl_setstate_r
1360# endif 1471# endif
1361_GL_FUNCDECL_RPL (setstate_r, int, 1472_GL_FUNCDECL_RPL (setstate_r, int,
1362 (char *arg_state, struct random_data *rand_state) 1473 (char *arg_state, struct random_data *rand_state),
1363 _GL_ARG_NONNULL ((1, 2))); 1474 _GL_ARG_NONNULL ((1, 2)));
1364_GL_CXXALIAS_RPL (setstate_r, int, 1475_GL_CXXALIAS_RPL (setstate_r, int,
1365 (char *arg_state, struct random_data *rand_state)); 1476 (char *arg_state, struct random_data *rand_state));
1366# else 1477# else
1367# if !@HAVE_RANDOM_R@ 1478# if !@HAVE_RANDOM_R@
1368_GL_FUNCDECL_SYS (setstate_r, int, 1479_GL_FUNCDECL_SYS (setstate_r, int,
1369 (char *arg_state, struct random_data *rand_state) 1480 (char *arg_state, struct random_data *rand_state),
1370 _GL_ARG_NONNULL ((1, 2))); 1481 _GL_ARG_NONNULL ((1, 2)));
1371# endif 1482# endif
1372/* Need to cast, because on Haiku, the first parameter is 1483/* Need to cast, because on Haiku, the first parameter is
@@ -1385,28 +1496,44 @@ _GL_WARN_ON_USE (setstate_r, "setstate_r is unportable - "
1385 1496
1386 1497
1387#if @GNULIB_REALLOC_POSIX@ 1498#if @GNULIB_REALLOC_POSIX@
1388# if (@GNULIB_REALLOC_POSIX@ && @REPLACE_REALLOC_FOR_REALLOC_POSIX@) \ 1499# if @REPLACE_REALLOC_FOR_REALLOC_POSIX@
1389 || (@GNULIB_REALLOC_GNU@ && @REPLACE_REALLOC_FOR_REALLOC_GNU@) 1500# if @REPLACE_REALLOC_FOR_REALLOC_POSIX@ == 2
1501# define _GL_INLINE_RPL_REALLOC 1
1502# ifdef __cplusplus
1503extern "C" {
1504# endif
1505_GL_REALLOC_INLINE void *
1506rpl_realloc (void *ptr, size_t size)
1507{
1508 return realloc (ptr, size ? size : 1);
1509}
1510# ifdef __cplusplus
1511}
1512# endif
1513# endif
1390# if !((defined __cplusplus && defined GNULIB_NAMESPACE) \ 1514# if !((defined __cplusplus && defined GNULIB_NAMESPACE) \
1391 || _GL_USE_STDLIB_ALLOC) 1515 || _GL_USE_STDLIB_ALLOC)
1392# undef realloc 1516# undef realloc
1393# define realloc rpl_realloc 1517# define realloc rpl_realloc
1394# endif 1518# endif
1395_GL_FUNCDECL_RPL (realloc, void *, (void *ptr, size_t size) 1519# if !defined _GL_INLINE_RPL_REALLOC
1396 _GL_ATTRIBUTE_DEALLOC_FREE); 1520_GL_FUNCDECL_RPL (realloc, void *,
1521 (void *ptr, size_t size),
1522 _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_NODISCARD);
1523# endif
1397_GL_CXXALIAS_RPL (realloc, void *, (void *ptr, size_t size)); 1524_GL_CXXALIAS_RPL (realloc, void *, (void *ptr, size_t size));
1398# else 1525# else
1399# if __GNUC__ >= 11 1526# if __GNUC__ >= 11 && !defined __clang__
1400/* For -Wmismatched-dealloc: Associate realloc with free or rpl_free. */ 1527/* For -Wmismatched-dealloc: Associate realloc with free or rpl_free. */
1401# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2 1528# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2
1402_GL_FUNCDECL_SYS (realloc, void *, 1529_GL_FUNCDECL_SYS (realloc, void *,
1403 (void *ptr, size_t size) 1530 (void *ptr, size_t size),
1404 _GL_ATTRIBUTE_NOTHROW 1531 _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_NODISCARD)
1405 _GL_ATTRIBUTE_DEALLOC_FREE); 1532 _GL_ATTRIBUTE_NOTHROW;
1406# else 1533# else
1407_GL_FUNCDECL_SYS (realloc, void *, 1534_GL_FUNCDECL_SYS (realloc, void *,
1408 (void *ptr, size_t size) 1535 (void *ptr, size_t size),
1409 _GL_ATTRIBUTE_DEALLOC_FREE); 1536 _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_NODISCARD);
1410# endif 1537# endif
1411# endif 1538# endif
1412_GL_CXXALIAS_SYS (realloc, void *, (void *ptr, size_t size)); 1539_GL_CXXALIAS_SYS (realloc, void *, (void *ptr, size_t size));
@@ -1415,16 +1542,17 @@ _GL_CXXALIAS_SYS (realloc, void *, (void *ptr, size_t size));
1415_GL_CXXALIASWARN (realloc); 1542_GL_CXXALIASWARN (realloc);
1416# endif 1543# endif
1417#else 1544#else
1418# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined realloc 1545# if @GNULIB_FREE_POSIX@ \
1546 && (__GNUC__ >= 11 && !defined __clang__) && !defined realloc
1419/* For -Wmismatched-dealloc: Associate realloc with free or rpl_free. */ 1547/* For -Wmismatched-dealloc: Associate realloc with free or rpl_free. */
1420# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2 1548# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2
1421_GL_FUNCDECL_SYS (realloc, void *, 1549_GL_FUNCDECL_SYS (realloc, void *,
1422 (void *ptr, size_t size) 1550 (void *ptr, size_t size),
1423 _GL_ATTRIBUTE_NOTHROW 1551 _GL_ATTRIBUTE_DEALLOC_FREE)
1424 _GL_ATTRIBUTE_DEALLOC_FREE); 1552 _GL_ATTRIBUTE_NOTHROW;
1425# else 1553# else
1426_GL_FUNCDECL_SYS (realloc, void *, 1554_GL_FUNCDECL_SYS (realloc, void *,
1427 (void *ptr, size_t size) 1555 (void *ptr, size_t size),
1428 _GL_ATTRIBUTE_DEALLOC_FREE); 1556 _GL_ATTRIBUTE_DEALLOC_FREE);
1429# endif 1557# endif
1430# endif 1558# endif
@@ -1444,13 +1572,15 @@ _GL_WARN_ON_USE (realloc, "realloc is not POSIX compliant everywhere - "
1444# define reallocarray rpl_reallocarray 1572# define reallocarray rpl_reallocarray
1445# endif 1573# endif
1446_GL_FUNCDECL_RPL (reallocarray, void *, 1574_GL_FUNCDECL_RPL (reallocarray, void *,
1447 (void *ptr, size_t nmemb, size_t size)); 1575 (void *ptr, size_t nmemb, size_t size),
1576 _GL_ATTRIBUTE_NODISCARD);
1448_GL_CXXALIAS_RPL (reallocarray, void *, 1577_GL_CXXALIAS_RPL (reallocarray, void *,
1449 (void *ptr, size_t nmemb, size_t size)); 1578 (void *ptr, size_t nmemb, size_t size));
1450# else 1579# else
1451# if ! @HAVE_REALLOCARRAY@ 1580# if ! @HAVE_REALLOCARRAY@
1452_GL_FUNCDECL_SYS (reallocarray, void *, 1581_GL_FUNCDECL_SYS (reallocarray, void *,
1453 (void *ptr, size_t nmemb, size_t size)); 1582 (void *ptr, size_t nmemb, size_t size),
1583 _GL_ATTRIBUTE_NODISCARD);
1454# endif 1584# endif
1455_GL_CXXALIAS_SYS (reallocarray, void *, 1585_GL_CXXALIAS_SYS (reallocarray, void *,
1456 (void *ptr, size_t nmemb, size_t size)); 1586 (void *ptr, size_t nmemb, size_t size));
@@ -1472,15 +1602,15 @@ _GL_WARN_ON_USE (reallocarray, "reallocarray is not portable - "
1472# define realpath rpl_realpath 1602# define realpath rpl_realpath
1473# endif 1603# endif
1474_GL_FUNCDECL_RPL (realpath, char *, 1604_GL_FUNCDECL_RPL (realpath, char *,
1475 (const char *restrict name, char *restrict resolved) 1605 (const char *restrict name, char *restrict resolved),
1476 _GL_ARG_NONNULL ((1))); 1606 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
1477_GL_CXXALIAS_RPL (realpath, char *, 1607_GL_CXXALIAS_RPL (realpath, char *,
1478 (const char *restrict name, char *restrict resolved)); 1608 (const char *restrict name, char *restrict resolved));
1479# else 1609# else
1480# if !@HAVE_REALPATH@ 1610# if !@HAVE_REALPATH@
1481_GL_FUNCDECL_SYS (realpath, char *, 1611_GL_FUNCDECL_SYS (realpath, char *,
1482 (const char *restrict name, char *restrict resolved) 1612 (const char *restrict name, char *restrict resolved),
1483 _GL_ARG_NONNULL ((1))); 1613 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
1484# endif 1614# endif
1485_GL_CXXALIAS_SYS (realpath, char *, 1615_GL_CXXALIAS_SYS (realpath, char *,
1486 (const char *restrict name, char *restrict resolved)); 1616 (const char *restrict name, char *restrict resolved));
@@ -1498,7 +1628,8 @@ _GL_WARN_ON_USE (realpath, "realpath is unportable - use gnulib module "
1498/* Test a user response to a question. 1628/* Test a user response to a question.
1499 Return 1 if it is affirmative, 0 if it is negative, or -1 if not clear. */ 1629 Return 1 if it is affirmative, 0 if it is negative, or -1 if not clear. */
1500# if !@HAVE_RPMATCH@ 1630# if !@HAVE_RPMATCH@
1501_GL_FUNCDECL_SYS (rpmatch, int, (const char *response) _GL_ARG_NONNULL ((1))); 1631_GL_FUNCDECL_SYS (rpmatch, int, (const char *response),
1632 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
1502# endif 1633# endif
1503_GL_CXXALIAS_SYS (rpmatch, int, (const char *response)); 1634_GL_CXXALIAS_SYS (rpmatch, int, (const char *response));
1504_GL_CXXALIASWARN (rpmatch); 1635_GL_CXXALIASWARN (rpmatch);
@@ -1514,7 +1645,8 @@ _GL_WARN_ON_USE (rpmatch, "rpmatch is unportable - "
1514/* Look up NAME in the environment, returning 0 in insecure situations. */ 1645/* Look up NAME in the environment, returning 0 in insecure situations. */
1515# if !@HAVE_SECURE_GETENV@ 1646# if !@HAVE_SECURE_GETENV@
1516_GL_FUNCDECL_SYS (secure_getenv, char *, 1647_GL_FUNCDECL_SYS (secure_getenv, char *,
1517 (char const *name) _GL_ARG_NONNULL ((1))); 1648 (char const *name),
1649 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
1518# endif 1650# endif
1519_GL_CXXALIAS_SYS (secure_getenv, char *, (char const *name)); 1651_GL_CXXALIAS_SYS (secure_getenv, char *, (char const *name));
1520_GL_CXXALIASWARN (secure_getenv); 1652_GL_CXXALIASWARN (secure_getenv);
@@ -1535,14 +1667,14 @@ _GL_WARN_ON_USE (secure_getenv, "secure_getenv is unportable - "
1535# define setenv rpl_setenv 1667# define setenv rpl_setenv
1536# endif 1668# endif
1537_GL_FUNCDECL_RPL (setenv, int, 1669_GL_FUNCDECL_RPL (setenv, int,
1538 (const char *name, const char *value, int replace) 1670 (const char *name, const char *value, int replace),
1539 _GL_ARG_NONNULL ((1))); 1671 _GL_ARG_NONNULL ((1)));
1540_GL_CXXALIAS_RPL (setenv, int, 1672_GL_CXXALIAS_RPL (setenv, int,
1541 (const char *name, const char *value, int replace)); 1673 (const char *name, const char *value, int replace));
1542# else 1674# else
1543# if !@HAVE_DECL_SETENV@ 1675# if !@HAVE_DECL_SETENV@
1544_GL_FUNCDECL_SYS (setenv, int, 1676_GL_FUNCDECL_SYS (setenv, int,
1545 (const char *name, const char *value, int replace) 1677 (const char *name, const char *value, int replace),
1546 _GL_ARG_NONNULL ((1))); 1678 _GL_ARG_NONNULL ((1)));
1547# endif 1679# endif
1548_GL_CXXALIAS_SYS (setenv, int, 1680_GL_CXXALIAS_SYS (setenv, int,
@@ -1559,6 +1691,19 @@ _GL_WARN_ON_USE (setenv, "setenv is unportable - "
1559# endif 1691# endif
1560#endif 1692#endif
1561 1693
1694#if @GNULIB_STACK_TRACE@
1695/* Prints a stack trace of the current thread to standard error,
1696 if possible. */
1697# if @CAN_PRINT_STACK_TRACE@
1698_GL_EXTERN_C void print_stack_trace (void);
1699# else
1700# if !GNULIB_defined_print_stack_trace
1701# define print_stack_trace() /* nothing */
1702# define GNULIB_defined_print_stack_trace 1
1703# endif
1704# endif
1705#endif
1706
1562#if @GNULIB_STRTOD@ 1707#if @GNULIB_STRTOD@
1563 /* Parse a double from STRING, updating ENDP if appropriate. */ 1708 /* Parse a double from STRING, updating ENDP if appropriate. */
1564# if @REPLACE_STRTOD@ 1709# if @REPLACE_STRTOD@
@@ -1567,14 +1712,14 @@ _GL_WARN_ON_USE (setenv, "setenv is unportable - "
1567# endif 1712# endif
1568# define GNULIB_defined_strtod_function 1 1713# define GNULIB_defined_strtod_function 1
1569_GL_FUNCDECL_RPL (strtod, double, 1714_GL_FUNCDECL_RPL (strtod, double,
1570 (const char *restrict str, char **restrict endp) 1715 (const char *restrict str, char **restrict endp),
1571 _GL_ARG_NONNULL ((1))); 1716 _GL_ARG_NONNULL ((1)));
1572_GL_CXXALIAS_RPL (strtod, double, 1717_GL_CXXALIAS_RPL (strtod, double,
1573 (const char *restrict str, char **restrict endp)); 1718 (const char *restrict str, char **restrict endp));
1574# else 1719# else
1575# if !@HAVE_STRTOD@ 1720# if !@HAVE_STRTOD@
1576_GL_FUNCDECL_SYS (strtod, double, 1721_GL_FUNCDECL_SYS (strtod, double,
1577 (const char *restrict str, char **restrict endp) 1722 (const char *restrict str, char **restrict endp),
1578 _GL_ARG_NONNULL ((1))); 1723 _GL_ARG_NONNULL ((1)));
1579# endif 1724# endif
1580_GL_CXXALIAS_SYS (strtod, double, 1725_GL_CXXALIAS_SYS (strtod, double,
@@ -1599,14 +1744,14 @@ _GL_WARN_ON_USE (strtod, "strtod is unportable - "
1599# endif 1744# endif
1600# define GNULIB_defined_strtof_function 1 1745# define GNULIB_defined_strtof_function 1
1601_GL_FUNCDECL_RPL (strtof, float, 1746_GL_FUNCDECL_RPL (strtof, float,
1602 (const char *restrict str, char **restrict endp) 1747 (const char *restrict str, char **restrict endp),
1603 _GL_ARG_NONNULL ((1))); 1748 _GL_ARG_NONNULL ((1)));
1604_GL_CXXALIAS_RPL (strtof, float, 1749_GL_CXXALIAS_RPL (strtof, float,
1605 (const char *restrict str, char **restrict endp)); 1750 (const char *restrict str, char **restrict endp));
1606# else 1751# else
1607# if !@HAVE_STRTOF@ 1752# if !@HAVE_STRTOF@
1608_GL_FUNCDECL_SYS (strtof, float, 1753_GL_FUNCDECL_SYS (strtof, float,
1609 (const char *restrict str, char **restrict endp) 1754 (const char *restrict str, char **restrict endp),
1610 _GL_ARG_NONNULL ((1))); 1755 _GL_ARG_NONNULL ((1)));
1611# endif 1756# endif
1612_GL_CXXALIAS_SYS (strtof, float, 1757_GL_CXXALIAS_SYS (strtof, float,
@@ -1631,14 +1776,14 @@ _GL_WARN_ON_USE (strtof, "strtof is unportable - "
1631# endif 1776# endif
1632# define GNULIB_defined_strtold_function 1 1777# define GNULIB_defined_strtold_function 1
1633_GL_FUNCDECL_RPL (strtold, long double, 1778_GL_FUNCDECL_RPL (strtold, long double,
1634 (const char *restrict str, char **restrict endp) 1779 (const char *restrict str, char **restrict endp),
1635 _GL_ARG_NONNULL ((1))); 1780 _GL_ARG_NONNULL ((1)));
1636_GL_CXXALIAS_RPL (strtold, long double, 1781_GL_CXXALIAS_RPL (strtold, long double,
1637 (const char *restrict str, char **restrict endp)); 1782 (const char *restrict str, char **restrict endp));
1638# else 1783# else
1639# if !@HAVE_STRTOLD@ 1784# if !@HAVE_STRTOLD@
1640_GL_FUNCDECL_SYS (strtold, long double, 1785_GL_FUNCDECL_SYS (strtold, long double,
1641 (const char *restrict str, char **restrict endp) 1786 (const char *restrict str, char **restrict endp),
1642 _GL_ARG_NONNULL ((1))); 1787 _GL_ARG_NONNULL ((1)));
1643# endif 1788# endif
1644_GL_CXXALIAS_SYS (strtold, long double, 1789_GL_CXXALIAS_SYS (strtold, long double,
@@ -1669,7 +1814,7 @@ _GL_WARN_ON_USE (strtold, "strtold is unportable - "
1669# define GNULIB_defined_strtol_function 1 1814# define GNULIB_defined_strtol_function 1
1670_GL_FUNCDECL_RPL (strtol, long, 1815_GL_FUNCDECL_RPL (strtol, long,
1671 (const char *restrict string, char **restrict endptr, 1816 (const char *restrict string, char **restrict endptr,
1672 int base) 1817 int base),
1673 _GL_ARG_NONNULL ((1))); 1818 _GL_ARG_NONNULL ((1)));
1674_GL_CXXALIAS_RPL (strtol, long, 1819_GL_CXXALIAS_RPL (strtol, long,
1675 (const char *restrict string, char **restrict endptr, 1820 (const char *restrict string, char **restrict endptr,
@@ -1678,7 +1823,7 @@ _GL_CXXALIAS_RPL (strtol, long,
1678# if !@HAVE_STRTOL@ 1823# if !@HAVE_STRTOL@
1679_GL_FUNCDECL_SYS (strtol, long, 1824_GL_FUNCDECL_SYS (strtol, long,
1680 (const char *restrict string, char **restrict endptr, 1825 (const char *restrict string, char **restrict endptr,
1681 int base) 1826 int base),
1682 _GL_ARG_NONNULL ((1))); 1827 _GL_ARG_NONNULL ((1)));
1683# endif 1828# endif
1684_GL_CXXALIAS_SYS (strtol, long, 1829_GL_CXXALIAS_SYS (strtol, long,
@@ -1712,7 +1857,7 @@ _GL_WARN_ON_USE (strtol, "strtol is unportable - "
1712# define GNULIB_defined_strtoll_function 1 1857# define GNULIB_defined_strtoll_function 1
1713_GL_FUNCDECL_RPL (strtoll, long long, 1858_GL_FUNCDECL_RPL (strtoll, long long,
1714 (const char *restrict string, char **restrict endptr, 1859 (const char *restrict string, char **restrict endptr,
1715 int base) 1860 int base),
1716 _GL_ARG_NONNULL ((1))); 1861 _GL_ARG_NONNULL ((1)));
1717_GL_CXXALIAS_RPL (strtoll, long long, 1862_GL_CXXALIAS_RPL (strtoll, long long,
1718 (const char *restrict string, char **restrict endptr, 1863 (const char *restrict string, char **restrict endptr,
@@ -1721,7 +1866,7 @@ _GL_CXXALIAS_RPL (strtoll, long long,
1721# if !@HAVE_STRTOLL@ 1866# if !@HAVE_STRTOLL@
1722_GL_FUNCDECL_SYS (strtoll, long long, 1867_GL_FUNCDECL_SYS (strtoll, long long,
1723 (const char *restrict string, char **restrict endptr, 1868 (const char *restrict string, char **restrict endptr,
1724 int base) 1869 int base),
1725 _GL_ARG_NONNULL ((1))); 1870 _GL_ARG_NONNULL ((1)));
1726# endif 1871# endif
1727_GL_CXXALIAS_SYS (strtoll, long long, 1872_GL_CXXALIAS_SYS (strtoll, long long,
@@ -1752,7 +1897,7 @@ _GL_WARN_ON_USE (strtoll, "strtoll is unportable - "
1752# define GNULIB_defined_strtoul_function 1 1897# define GNULIB_defined_strtoul_function 1
1753_GL_FUNCDECL_RPL (strtoul, unsigned long, 1898_GL_FUNCDECL_RPL (strtoul, unsigned long,
1754 (const char *restrict string, char **restrict endptr, 1899 (const char *restrict string, char **restrict endptr,
1755 int base) 1900 int base),
1756 _GL_ARG_NONNULL ((1))); 1901 _GL_ARG_NONNULL ((1)));
1757_GL_CXXALIAS_RPL (strtoul, unsigned long, 1902_GL_CXXALIAS_RPL (strtoul, unsigned long,
1758 (const char *restrict string, char **restrict endptr, 1903 (const char *restrict string, char **restrict endptr,
@@ -1761,7 +1906,7 @@ _GL_CXXALIAS_RPL (strtoul, unsigned long,
1761# if !@HAVE_STRTOUL@ 1906# if !@HAVE_STRTOUL@
1762_GL_FUNCDECL_SYS (strtoul, unsigned long, 1907_GL_FUNCDECL_SYS (strtoul, unsigned long,
1763 (const char *restrict string, char **restrict endptr, 1908 (const char *restrict string, char **restrict endptr,
1764 int base) 1909 int base),
1765 _GL_ARG_NONNULL ((1))); 1910 _GL_ARG_NONNULL ((1)));
1766# endif 1911# endif
1767_GL_CXXALIAS_SYS (strtoul, unsigned long, 1912_GL_CXXALIAS_SYS (strtoul, unsigned long,
@@ -1795,7 +1940,7 @@ _GL_WARN_ON_USE (strtoul, "strtoul is unportable - "
1795# define GNULIB_defined_strtoull_function 1 1940# define GNULIB_defined_strtoull_function 1
1796_GL_FUNCDECL_RPL (strtoull, unsigned long long, 1941_GL_FUNCDECL_RPL (strtoull, unsigned long long,
1797 (const char *restrict string, char **restrict endptr, 1942 (const char *restrict string, char **restrict endptr,
1798 int base) 1943 int base),
1799 _GL_ARG_NONNULL ((1))); 1944 _GL_ARG_NONNULL ((1)));
1800_GL_CXXALIAS_RPL (strtoull, unsigned long long, 1945_GL_CXXALIAS_RPL (strtoull, unsigned long long,
1801 (const char *restrict string, char **restrict endptr, 1946 (const char *restrict string, char **restrict endptr,
@@ -1804,7 +1949,7 @@ _GL_CXXALIAS_RPL (strtoull, unsigned long long,
1804# if !@HAVE_STRTOULL@ 1949# if !@HAVE_STRTOULL@
1805_GL_FUNCDECL_SYS (strtoull, unsigned long long, 1950_GL_FUNCDECL_SYS (strtoull, unsigned long long,
1806 (const char *restrict string, char **restrict endptr, 1951 (const char *restrict string, char **restrict endptr,
1807 int base) 1952 int base),
1808 _GL_ARG_NONNULL ((1))); 1953 _GL_ARG_NONNULL ((1)));
1809# endif 1954# endif
1810_GL_CXXALIAS_SYS (strtoull, unsigned long long, 1955_GL_CXXALIAS_SYS (strtoull, unsigned long long,
@@ -1824,7 +1969,7 @@ _GL_WARN_ON_USE (strtoull, "strtoull is unportable - "
1824/* Unlock the slave side of the pseudo-terminal whose master side is specified 1969/* Unlock the slave side of the pseudo-terminal whose master side is specified
1825 by FD, so that it can be opened. */ 1970 by FD, so that it can be opened. */
1826# if !@HAVE_UNLOCKPT@ 1971# if !@HAVE_UNLOCKPT@
1827_GL_FUNCDECL_SYS (unlockpt, int, (int fd)); 1972_GL_FUNCDECL_SYS (unlockpt, int, (int fd), );
1828# endif 1973# endif
1829_GL_CXXALIAS_SYS (unlockpt, int, (int fd)); 1974_GL_CXXALIAS_SYS (unlockpt, int, (int fd));
1830_GL_CXXALIASWARN (unlockpt); 1975_GL_CXXALIASWARN (unlockpt);
@@ -1843,11 +1988,11 @@ _GL_WARN_ON_USE (unlockpt, "unlockpt is not portable - "
1843# undef unsetenv 1988# undef unsetenv
1844# define unsetenv rpl_unsetenv 1989# define unsetenv rpl_unsetenv
1845# endif 1990# endif
1846_GL_FUNCDECL_RPL (unsetenv, int, (const char *name) _GL_ARG_NONNULL ((1))); 1991_GL_FUNCDECL_RPL (unsetenv, int, (const char *name), _GL_ARG_NONNULL ((1)));
1847_GL_CXXALIAS_RPL (unsetenv, int, (const char *name)); 1992_GL_CXXALIAS_RPL (unsetenv, int, (const char *name));
1848# else 1993# else
1849# if !@HAVE_DECL_UNSETENV@ 1994# if !@HAVE_DECL_UNSETENV@
1850_GL_FUNCDECL_SYS (unsetenv, int, (const char *name) _GL_ARG_NONNULL ((1))); 1995_GL_FUNCDECL_SYS (unsetenv, int, (const char *name), _GL_ARG_NONNULL ((1)));
1851# endif 1996# endif
1852_GL_CXXALIAS_SYS (unsetenv, int, (const char *name)); 1997_GL_CXXALIAS_SYS (unsetenv, int, (const char *name));
1853# endif 1998# endif
@@ -1869,7 +2014,7 @@ _GL_WARN_ON_USE (unsetenv, "unsetenv is unportable - "
1869# undef wctomb 2014# undef wctomb
1870# define wctomb rpl_wctomb 2015# define wctomb rpl_wctomb
1871# endif 2016# endif
1872_GL_FUNCDECL_RPL (wctomb, int, (char *s, wchar_t wc)); 2017_GL_FUNCDECL_RPL (wctomb, int, (char *s, wchar_t wc), );
1873_GL_CXXALIAS_RPL (wctomb, int, (char *s, wchar_t wc)); 2018_GL_CXXALIAS_RPL (wctomb, int, (char *s, wchar_t wc));
1874# else 2019# else
1875_GL_CXXALIAS_SYS (wctomb, int, (char *s, wchar_t wc)); 2020_GL_CXXALIAS_SYS (wctomb, int, (char *s, wchar_t wc));
@@ -1880,6 +2025,8 @@ _GL_CXXALIASWARN (wctomb);
1880#endif 2025#endif
1881 2026
1882 2027
2028_GL_INLINE_HEADER_END
2029
1883#endif /* _@GUARD_PREFIX@_STDLIB_H */ 2030#endif /* _@GUARD_PREFIX@_STDLIB_H */
1884#endif /* _@GUARD_PREFIX@_STDLIB_H */ 2031#endif /* _@GUARD_PREFIX@_STDLIB_H */
1885#endif 2032#endif
diff --git a/gl/str-two-way.h b/gl/str-two-way.h
index cf85e268..d13fb298 100644
--- a/gl/str-two-way.h
+++ b/gl/str-two-way.h
@@ -1,5 +1,5 @@
1/* Byte-wise substring search, using the Two-Way algorithm. 1/* Byte-wise substring search, using the Two-Way algorithm.
2 Copyright (C) 2008-2024 Free Software Foundation, Inc. 2 Copyright (C) 2008-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 Written by Eric Blake <ebb9@byu.net>, 2008. 4 Written by Eric Blake <ebb9@byu.net>, 2008.
5 5
diff --git a/gl/strcasecmp.c b/gl/strcasecmp.c
index 7939b404..16626d4d 100644
--- a/gl/strcasecmp.c
+++ b/gl/strcasecmp.c
@@ -1,5 +1,5 @@
1/* Case-insensitive string comparison function. 1/* Case-insensitive string comparison function for unibyte locales.
2 Copyright (C) 1998-1999, 2005-2007, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 1998-1999, 2005-2007, 2009-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -17,7 +17,7 @@
17#include <config.h> 17#include <config.h>
18 18
19/* Specification. */ 19/* Specification. */
20#include <string.h> 20#include <strings.h>
21 21
22#include <ctype.h> 22#include <ctype.h>
23#include <limits.h> 23#include <limits.h>
diff --git a/gl/strcasestr.c b/gl/strcasestr.c
index b8c0479d..fd0e2c3e 100644
--- a/gl/strcasestr.c
+++ b/gl/strcasestr.c
@@ -1,5 +1,5 @@
1/* Case-insensitive searching in a string. 1/* Case-insensitive searching in a string.
2 Copyright (C) 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2005. 3 Written by Bruno Haible <bruno@clisp.org>, 2005.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/streq.h b/gl/streq.h
index 8593de6d..1f1ff38f 100644
--- a/gl/streq.h
+++ b/gl/streq.h
@@ -1,5 +1,5 @@
1/* Optimized string comparison. 1/* Optimized string comparison.
2 Copyright (C) 2001-2002, 2007, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 2001-2002, 2007, 2009-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -26,7 +26,7 @@ extern "C" {
26#endif 26#endif
27 27
28 28
29/* STREQ_OPT allows to optimize string comparison with a small literal string. 29/* STREQ_OPT optimizes string comparison with a small literal string.
30 STREQ_OPT (s, "EUC-KR", 'E', 'U', 'C', '-', 'K', 'R', 0, 0, 0) 30 STREQ_OPT (s, "EUC-KR", 'E', 'U', 'C', '-', 'K', 'R', 0, 0, 0)
31 is semantically equivalent to 31 is semantically equivalent to
32 strcmp (s, "EUC-KR") == 0 32 strcmp (s, "EUC-KR") == 0
diff --git a/gl/strerror-override.c b/gl/strerror-override.c
index b9c1c7ab..3cc25905 100644
--- a/gl/strerror-override.c
+++ b/gl/strerror-override.c
@@ -1,6 +1,6 @@
1/* strerror-override.c --- POSIX compatible system error routine 1/* strerror-override.c --- POSIX compatible system error routine
2 2
3 Copyright (C) 2010-2024 Free Software Foundation, Inc. 3 Copyright (C) 2010-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -298,6 +298,11 @@ strerror_override (int errnum)
298 return "Invalid or incomplete multibyte or wide character"; 298 return "Invalid or incomplete multibyte or wide character";
299# endif 299# endif
300 300
301# if GNULIB_defined_ESOCKTNOSUPPORT
302 case ESOCKTNOSUPPORT:
303 return "Socket type not supported";
304# endif
305
301 default: 306 default:
302 return NULL; 307 return NULL;
303 } 308 }
diff --git a/gl/strerror-override.h b/gl/strerror-override.h
index a1734a24..653ea0ad 100644
--- a/gl/strerror-override.h
+++ b/gl/strerror-override.h
@@ -1,6 +1,6 @@
1/* strerror-override.h --- POSIX compatible system error routine 1/* strerror-override.h --- POSIX compatible system error routine
2 2
3 Copyright (C) 2010-2024 Free Software Foundation, Inc. 3 Copyright (C) 2010-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -57,7 +57,8 @@ extern "C" {
57 || GNULIB_defined_ECANCELED \ 57 || GNULIB_defined_ECANCELED \
58 || GNULIB_defined_EOWNERDEAD \ 58 || GNULIB_defined_EOWNERDEAD \
59 || GNULIB_defined_ENOTRECOVERABLE \ 59 || GNULIB_defined_ENOTRECOVERABLE \
60 || GNULIB_defined_EILSEQ 60 || GNULIB_defined_EILSEQ \
61 || GNULIB_defined_ESOCKTNOSUPPORT
61extern const char *strerror_override (int errnum) _GL_ATTRIBUTE_CONST; 62extern const char *strerror_override (int errnum) _GL_ATTRIBUTE_CONST;
62#else 63#else
63# define strerror_override(ignored) NULL 64# define strerror_override(ignored) NULL
diff --git a/gl/strerror.c b/gl/strerror.c
index 6b760ff4..72572ae4 100644
--- a/gl/strerror.c
+++ b/gl/strerror.c
@@ -1,6 +1,6 @@
1/* strerror.c --- POSIX compatible system error routine 1/* strerror.c --- POSIX compatible system error routine
2 2
3 Copyright (C) 2007-2024 Free Software Foundation, Inc. 3 Copyright (C) 2007-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -31,6 +31,12 @@
31/* Use the system functions, not the gnulib overrides in this file. */ 31/* Use the system functions, not the gnulib overrides in this file. */
32#undef sprintf 32#undef sprintf
33 33
34/* macOS 12's "warning: 'sprintf' is deprecated" is pointless,
35 as sprintf is used safely here. */
36#if defined __APPLE__ && defined __MACH__ && _GL_GNUC_PREREQ (4, 2)
37# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
38#endif
39
34char * 40char *
35strerror (int n) 41strerror (int n)
36#undef strerror 42#undef strerror
diff --git a/gl/string.in.h b/gl/string.in.h
index 44ec2e7e..25e6a087 100644
--- a/gl/string.in.h
+++ b/gl/string.in.h
@@ -1,6 +1,6 @@
1/* A GNU-like <string.h>. 1/* A GNU-like <string.h>.
2 2
3 Copyright (C) 1995-1996, 2001-2024 Free Software Foundation, Inc. 3 Copyright (C) 1995-1996, 2001-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -20,7 +20,7 @@
20#endif 20#endif
21@PRAGMA_COLUMNS@ 21@PRAGMA_COLUMNS@
22 22
23#if defined _GL_ALREADY_INCLUDING_STRING_H 23#if defined _@GUARD_PREFIX@_ALREADY_INCLUDING_STRING_H
24/* Special invocation convention: 24/* Special invocation convention:
25 - On OS X/NetBSD we have a sequence of nested includes 25 - On OS X/NetBSD we have a sequence of nested includes
26 <string.h> -> <strings.h> -> "string.h" 26 <string.h> -> <strings.h> -> "string.h"
@@ -34,12 +34,12 @@
34 34
35#ifndef _@GUARD_PREFIX@_STRING_H 35#ifndef _@GUARD_PREFIX@_STRING_H
36 36
37#define _GL_ALREADY_INCLUDING_STRING_H 37#define _@GUARD_PREFIX@_ALREADY_INCLUDING_STRING_H
38 38
39/* The include_next requires a split double-inclusion guard. */ 39/* The include_next requires a split double-inclusion guard. */
40#@INCLUDE_NEXT@ @NEXT_STRING_H@ 40#@INCLUDE_NEXT@ @NEXT_STRING_H@
41 41
42#undef _GL_ALREADY_INCLUDING_STRING_H 42#undef _@GUARD_PREFIX@_ALREADY_INCLUDING_STRING_H
43 43
44#ifndef _@GUARD_PREFIX@_STRING_H 44#ifndef _@GUARD_PREFIX@_STRING_H
45#define _@GUARD_PREFIX@_STRING_H 45#define _@GUARD_PREFIX@_STRING_H
@@ -54,6 +54,11 @@
54/* NetBSD 5.0 mis-defines NULL. */ 54/* NetBSD 5.0 mis-defines NULL. */
55#include <stddef.h> 55#include <stddef.h>
56 56
57#if @GNULIB_STRERROR_L@
58/* Get locale_t. */
59# include <locale.h>
60#endif
61
57/* MirBSD defines mbslen as a macro. */ 62/* MirBSD defines mbslen as a macro. */
58#if @GNULIB_MBSLEN@ && defined __MirBSD__ 63#if @GNULIB_MBSLEN@ && defined __MirBSD__
59# include <wchar.h> 64# include <wchar.h>
@@ -79,7 +84,7 @@
79 that can be freed by passing them as the Ith argument to the 84 that can be freed by passing them as the Ith argument to the
80 function F. */ 85 function F. */
81#ifndef _GL_ATTRIBUTE_DEALLOC 86#ifndef _GL_ATTRIBUTE_DEALLOC
82# if __GNUC__ >= 11 87# if __GNUC__ >= 11 && !defined __clang__
83# define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i))) 88# define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i)))
84# else 89# else
85# define _GL_ATTRIBUTE_DEALLOC(f, i) 90# define _GL_ATTRIBUTE_DEALLOC(f, i)
@@ -111,11 +116,23 @@
111# endif 116# endif
112#endif 117#endif
113 118
119/* _GL_ATTRIBUTE_NONNULL_IF_NONZERO (NP, NI) declares that the argument NP
120 (a pointer) must not be NULL if the argument NI (an integer) is != 0. */
121/* Applies to: functions. */
122#ifndef _GL_ATTRIBUTE_NONNULL_IF_NONZERO
123# if __GNUC__ >= 15 && !defined __clang__
124# define _GL_ATTRIBUTE_NONNULL_IF_NONZERO(np, ni) \
125 __attribute__ ((__nonnull_if_nonzero__ (np, ni)))
126# else
127# define _GL_ATTRIBUTE_NONNULL_IF_NONZERO(np, ni)
128# endif
129#endif
130
114/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions. 131/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions.
115 */ 132 */
116#ifndef _GL_ATTRIBUTE_NOTHROW 133#ifndef _GL_ATTRIBUTE_NOTHROW
117# if defined __cplusplus 134# if defined __cplusplus
118# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major >= 4 135# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major__ >= 4
119# if __cplusplus >= 201103L 136# if __cplusplus >= 201103L
120# define _GL_ATTRIBUTE_NOTHROW noexcept (true) 137# define _GL_ATTRIBUTE_NOTHROW noexcept (true)
121# else 138# else
@@ -149,6 +166,7 @@
149 166
150/* The definition of _GL_WARN_ON_USE is copied here. */ 167/* The definition of _GL_WARN_ON_USE is copied here. */
151 168
169
152/* Make _GL_ATTRIBUTE_DEALLOC_FREE work, even though <stdlib.h> may not have 170/* Make _GL_ATTRIBUTE_DEALLOC_FREE work, even though <stdlib.h> may not have
153 been included yet. */ 171 been included yet. */
154#if @GNULIB_FREE_POSIX@ 172#if @GNULIB_FREE_POSIX@
@@ -193,12 +211,97 @@ _GL_EXTERN_C void free (void *);
193# endif 211# endif
194#endif 212#endif
195 213
214
215/* Declarations for ISO C N3322. */
216#if defined __GNUC__ && __GNUC__ >= 15 && !defined __clang__
217# ifndef memcpy
218_GL_EXTERN_C void *memcpy (void *__dest, const void *__src, size_t __n)
219# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
220 _GL_ATTRIBUTE_NOTHROW
221# endif
222 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
223 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
224# endif
225# ifndef memccpy
226_GL_EXTERN_C void *memccpy (void *__dest, const void *__src, int __c, size_t __n)
227# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
228 _GL_ATTRIBUTE_NOTHROW
229# endif
230 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 4)
231 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 4);
232# endif
233# ifndef memmove
234_GL_EXTERN_C void *memmove (void *__dest, const void *__src, size_t __n)
235# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
236 _GL_ATTRIBUTE_NOTHROW
237# endif
238 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
239 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
240# endif
241# ifndef strncpy
242_GL_EXTERN_C char *strncpy (char *__dest, const char *__src, size_t __n)
243# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
244 _GL_ATTRIBUTE_NOTHROW
245# endif
246 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
247 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
248# endif
249# ifndef strndup
250_GL_EXTERN_C char *strndup (const char *__s, size_t __n)
251# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
252 _GL_ATTRIBUTE_NOTHROW
253# endif
254 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 2);
255# endif
256# ifndef strncat
257_GL_EXTERN_C char *strncat (char *__dest, const char *__src, size_t __n)
258# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
259 _GL_ATTRIBUTE_NOTHROW
260# endif
261 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
262# endif
263# ifndef memcmp
264_GL_EXTERN_C int memcmp (const void *__s1, const void *__s2, size_t __n)
265# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
266 _GL_ATTRIBUTE_NOTHROW
267# endif
268 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
269 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
270# endif
271# ifndef strncmp
272_GL_EXTERN_C int strncmp (const char *__s1, const char *__s2, size_t __n)
273# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
274 _GL_ATTRIBUTE_NOTHROW
275# endif
276 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
277 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
278# endif
279# if !defined memchr && !defined __cplusplus
280_GL_EXTERN_C void *memchr (const void *__s, int __c, size_t __n)
281 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3);
282_GL_EXTERN_C void *memrchr (const void *__s, int __c, size_t __n)
283 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3);
284# endif
285# ifndef memset
286_GL_EXTERN_C void *memset (void *__s, int __c, size_t __n)
287# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
288 _GL_ATTRIBUTE_NOTHROW
289# endif
290 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3);
291# endif
292# ifndef memset_explicit
293_GL_EXTERN_C void *memset_explicit (void *__s, int __c, size_t __n)
294 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3);
295# endif
296#endif
297
298
196/* Clear a block of memory. The compiler will not delete a call to 299/* Clear a block of memory. The compiler will not delete a call to
197 this function, even if the block is dead after the call. */ 300 this function, even if the block is dead after the call. */
198#if @GNULIB_EXPLICIT_BZERO@ 301#if @GNULIB_EXPLICIT_BZERO@
199# if ! @HAVE_EXPLICIT_BZERO@ 302# if ! @HAVE_EXPLICIT_BZERO@
200_GL_FUNCDECL_SYS (explicit_bzero, void, 303_GL_FUNCDECL_SYS (explicit_bzero, void,
201 (void *__dest, size_t __n) _GL_ARG_NONNULL ((1))); 304 (void *__dest, size_t __n), _GL_ARG_NONNULL ((1)));
202# endif 305# endif
203_GL_CXXALIAS_SYS (explicit_bzero, void, (void *__dest, size_t __n)); 306_GL_CXXALIAS_SYS (explicit_bzero, void, (void *__dest, size_t __n));
204_GL_CXXALIASWARN (explicit_bzero); 307_GL_CXXALIASWARN (explicit_bzero);
@@ -210,10 +313,11 @@ _GL_WARN_ON_USE (explicit_bzero, "explicit_bzero is unportable - "
210# endif 313# endif
211#endif 314#endif
212 315
316
213/* Find the index of the least-significant set bit. */ 317/* Find the index of the least-significant set bit. */
214#if @GNULIB_FFSL@ 318#if @GNULIB_FFSL@
215# if !@HAVE_FFSL@ 319# if !@HAVE_FFSL@
216_GL_FUNCDECL_SYS (ffsl, int, (long int i)); 320_GL_FUNCDECL_SYS (ffsl, int, (long int i), );
217# endif 321# endif
218_GL_CXXALIAS_SYS (ffsl, int, (long int i)); 322_GL_CXXALIAS_SYS (ffsl, int, (long int i));
219_GL_CXXALIASWARN (ffsl); 323_GL_CXXALIASWARN (ffsl);
@@ -231,11 +335,11 @@ _GL_WARN_ON_USE (ffsl, "ffsl is not portable - use the ffsl module");
231# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 335# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
232# define ffsll rpl_ffsll 336# define ffsll rpl_ffsll
233# endif 337# endif
234_GL_FUNCDECL_RPL (ffsll, int, (long long int i)); 338_GL_FUNCDECL_RPL (ffsll, int, (long long int i), );
235_GL_CXXALIAS_RPL (ffsll, int, (long long int i)); 339_GL_CXXALIAS_RPL (ffsll, int, (long long int i));
236# else 340# else
237# if !@HAVE_FFSLL@ 341# if !@HAVE_FFSLL@
238_GL_FUNCDECL_SYS (ffsll, int, (long long int i)); 342_GL_FUNCDECL_SYS (ffsll, int, (long long int i), );
239# endif 343# endif
240_GL_CXXALIAS_SYS (ffsll, int, (long long int i)); 344_GL_CXXALIAS_SYS (ffsll, int, (long long int i));
241# endif 345# endif
@@ -274,9 +378,9 @@ _GL_CXXALIASWARN (memccpy);
274# undef memchr 378# undef memchr
275# define memchr rpl_memchr 379# define memchr rpl_memchr
276# endif 380# endif
277_GL_FUNCDECL_RPL (memchr, void *, (void const *__s, int __c, size_t __n) 381_GL_FUNCDECL_RPL (memchr, void *, (void const *__s, int __c, size_t __n),
278 _GL_ATTRIBUTE_PURE 382 _GL_ATTRIBUTE_PURE
279 _GL_ARG_NONNULL ((1))); 383 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3));
280_GL_CXXALIAS_RPL (memchr, void *, (void const *__s, int __c, size_t __n)); 384_GL_CXXALIAS_RPL (memchr, void *, (void const *__s, int __c, size_t __n));
281# else 385# else
282 /* On some systems, this function is defined as an overloaded function: 386 /* On some systems, this function is defined as an overloaded function:
@@ -301,8 +405,10 @@ _GL_CXXALIASWARN (memchr);
301#elif defined GNULIB_POSIXCHECK 405#elif defined GNULIB_POSIXCHECK
302# undef memchr 406# undef memchr
303/* Assume memchr is always declared. */ 407/* Assume memchr is always declared. */
304_GL_WARN_ON_USE (memchr, "memchr has platform-specific bugs - " 408_GL_WARN_ON_USE_CXX (memchr,
305 "use gnulib module memchr for portability" ); 409 const void *, void *, (void const *, int, size_t),
410 "memchr has platform-specific bugs - "
411 "use gnulib module memchr for portability" );
306#endif 412#endif
307 413
308/* Return the first occurrence of NEEDLE in HAYSTACK. */ 414/* Return the first occurrence of NEEDLE in HAYSTACK. */
@@ -313,7 +419,7 @@ _GL_WARN_ON_USE (memchr, "memchr has platform-specific bugs - "
313# endif 419# endif
314_GL_FUNCDECL_RPL (memmem, void *, 420_GL_FUNCDECL_RPL (memmem, void *,
315 (void const *__haystack, size_t __haystack_len, 421 (void const *__haystack, size_t __haystack_len,
316 void const *__needle, size_t __needle_len) 422 void const *__needle, size_t __needle_len),
317 _GL_ATTRIBUTE_PURE 423 _GL_ATTRIBUTE_PURE
318 _GL_ARG_NONNULL ((1, 3))); 424 _GL_ARG_NONNULL ((1, 3)));
319_GL_CXXALIAS_RPL (memmem, void *, 425_GL_CXXALIAS_RPL (memmem, void *,
@@ -323,7 +429,7 @@ _GL_CXXALIAS_RPL (memmem, void *,
323# if ! @HAVE_DECL_MEMMEM@ 429# if ! @HAVE_DECL_MEMMEM@
324_GL_FUNCDECL_SYS (memmem, void *, 430_GL_FUNCDECL_SYS (memmem, void *,
325 (void const *__haystack, size_t __haystack_len, 431 (void const *__haystack, size_t __haystack_len,
326 void const *__needle, size_t __needle_len) 432 void const *__needle, size_t __needle_len),
327 _GL_ATTRIBUTE_PURE 433 _GL_ATTRIBUTE_PURE
328 _GL_ARG_NONNULL ((1, 3))); 434 _GL_ARG_NONNULL ((1, 3)));
329# endif 435# endif
@@ -351,7 +457,7 @@ _GL_WARN_ON_USE (memmem, "memmem is unportable and often quadratic - "
351# endif 457# endif
352_GL_FUNCDECL_RPL (mempcpy, void *, 458_GL_FUNCDECL_RPL (mempcpy, void *,
353 (void *restrict __dest, void const *restrict __src, 459 (void *restrict __dest, void const *restrict __src,
354 size_t __n) 460 size_t __n),
355 _GL_ARG_NONNULL ((1, 2))); 461 _GL_ARG_NONNULL ((1, 2)));
356_GL_CXXALIAS_RPL (mempcpy, void *, 462_GL_CXXALIAS_RPL (mempcpy, void *,
357 (void *restrict __dest, void const *restrict __src, 463 (void *restrict __dest, void const *restrict __src,
@@ -360,7 +466,7 @@ _GL_CXXALIAS_RPL (mempcpy, void *,
360# if !@HAVE_MEMPCPY@ 466# if !@HAVE_MEMPCPY@
361_GL_FUNCDECL_SYS (mempcpy, void *, 467_GL_FUNCDECL_SYS (mempcpy, void *,
362 (void *restrict __dest, void const *restrict __src, 468 (void *restrict __dest, void const *restrict __src,
363 size_t __n) 469 size_t __n),
364 _GL_ARG_NONNULL ((1, 2))); 470 _GL_ARG_NONNULL ((1, 2)));
365# endif 471# endif
366_GL_CXXALIAS_SYS (mempcpy, void *, 472_GL_CXXALIAS_SYS (mempcpy, void *,
@@ -381,9 +487,9 @@ _GL_WARN_ON_USE (mempcpy, "mempcpy is unportable - "
381/* Search backwards through a block for a byte (specified as an int). */ 487/* Search backwards through a block for a byte (specified as an int). */
382#if @GNULIB_MEMRCHR@ 488#if @GNULIB_MEMRCHR@
383# if ! @HAVE_DECL_MEMRCHR@ 489# if ! @HAVE_DECL_MEMRCHR@
384_GL_FUNCDECL_SYS (memrchr, void *, (void const *, int, size_t) 490_GL_FUNCDECL_SYS (memrchr, void *, (void const *, int, size_t),
385 _GL_ATTRIBUTE_PURE 491 _GL_ATTRIBUTE_PURE
386 _GL_ARG_NONNULL ((1))); 492 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3));
387# endif 493# endif
388 /* On some systems, this function is defined as an overloaded function: 494 /* On some systems, this function is defined as an overloaded function:
389 extern "C++" { const void * std::memrchr (const void *, int, size_t); } 495 extern "C++" { const void * std::memrchr (const void *, int, size_t); }
@@ -420,16 +526,20 @@ _GL_WARN_ON_USE (memrchr, "memrchr is unportable - "
420# define memset_explicit rpl_memset_explicit 526# define memset_explicit rpl_memset_explicit
421# endif 527# endif
422_GL_FUNCDECL_RPL (memset_explicit, void *, 528_GL_FUNCDECL_RPL (memset_explicit, void *,
423 (void *__dest, int __c, size_t __n) _GL_ARG_NONNULL ((1))); 529 (void *__dest, int __c, size_t __n),
530 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3));
424_GL_CXXALIAS_RPL (memset_explicit, void *, (void *__dest, int __c, size_t __n)); 531_GL_CXXALIAS_RPL (memset_explicit, void *, (void *__dest, int __c, size_t __n));
425# else 532# else
426# if !@HAVE_MEMSET_EXPLICIT@ 533# if !@HAVE_MEMSET_EXPLICIT@
427_GL_FUNCDECL_SYS (memset_explicit, void *, 534_GL_FUNCDECL_SYS (memset_explicit, void *,
428 (void *__dest, int __c, size_t __n) _GL_ARG_NONNULL ((1))); 535 (void *__dest, int __c, size_t __n),
536 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3));
429# endif 537# endif
430_GL_CXXALIAS_SYS (memset_explicit, void *, (void *__dest, int __c, size_t __n)); 538_GL_CXXALIAS_SYS (memset_explicit, void *, (void *__dest, int __c, size_t __n));
431# endif 539# endif
540# if __GLIBC__ >= 2
432_GL_CXXALIASWARN (memset_explicit); 541_GL_CXXALIASWARN (memset_explicit);
542# endif
433#elif defined GNULIB_POSIXCHECK 543#elif defined GNULIB_POSIXCHECK
434# undef memset_explicit 544# undef memset_explicit
435# if HAVE_RAW_DECL_MEMSET_EXPLICIT 545# if HAVE_RAW_DECL_MEMSET_EXPLICIT
@@ -443,7 +553,7 @@ _GL_WARN_ON_USE (memset_explicit, "memset_explicit is unportable - "
443 occur within N bytes. */ 553 occur within N bytes. */
444#if @GNULIB_RAWMEMCHR@ 554#if @GNULIB_RAWMEMCHR@
445# if ! @HAVE_RAWMEMCHR@ 555# if ! @HAVE_RAWMEMCHR@
446_GL_FUNCDECL_SYS (rawmemchr, void *, (void const *__s, int __c_in) 556_GL_FUNCDECL_SYS (rawmemchr, void *, (void const *__s, int __c_in),
447 _GL_ATTRIBUTE_PURE 557 _GL_ATTRIBUTE_PURE
448 _GL_ARG_NONNULL ((1))); 558 _GL_ARG_NONNULL ((1)));
449# endif 559# endif
@@ -481,14 +591,14 @@ _GL_WARN_ON_USE (rawmemchr, "rawmemchr is unportable - "
481# define stpcpy rpl_stpcpy 591# define stpcpy rpl_stpcpy
482# endif 592# endif
483_GL_FUNCDECL_RPL (stpcpy, char *, 593_GL_FUNCDECL_RPL (stpcpy, char *,
484 (char *restrict __dst, char const *restrict __src) 594 (char *restrict __dst, char const *restrict __src),
485 _GL_ARG_NONNULL ((1, 2))); 595 _GL_ARG_NONNULL ((1, 2)));
486_GL_CXXALIAS_RPL (stpcpy, char *, 596_GL_CXXALIAS_RPL (stpcpy, char *,
487 (char *restrict __dst, char const *restrict __src)); 597 (char *restrict __dst, char const *restrict __src));
488# else 598# else
489# if !@HAVE_STPCPY@ 599# if !@HAVE_STPCPY@
490_GL_FUNCDECL_SYS (stpcpy, char *, 600_GL_FUNCDECL_SYS (stpcpy, char *,
491 (char *restrict __dst, char const *restrict __src) 601 (char *restrict __dst, char const *restrict __src),
492 _GL_ARG_NONNULL ((1, 2))); 602 _GL_ARG_NONNULL ((1, 2)));
493# endif 603# endif
494_GL_CXXALIAS_SYS (stpcpy, char *, 604_GL_CXXALIAS_SYS (stpcpy, char *,
@@ -515,7 +625,7 @@ _GL_WARN_ON_USE (stpcpy, "stpcpy is unportable - "
515# endif 625# endif
516_GL_FUNCDECL_RPL (stpncpy, char *, 626_GL_FUNCDECL_RPL (stpncpy, char *,
517 (char *restrict __dst, char const *restrict __src, 627 (char *restrict __dst, char const *restrict __src,
518 size_t __n) 628 size_t __n),
519 _GL_ARG_NONNULL ((1, 2))); 629 _GL_ARG_NONNULL ((1, 2)));
520_GL_CXXALIAS_RPL (stpncpy, char *, 630_GL_CXXALIAS_RPL (stpncpy, char *,
521 (char *restrict __dst, char const *restrict __src, 631 (char *restrict __dst, char const *restrict __src,
@@ -524,7 +634,7 @@ _GL_CXXALIAS_RPL (stpncpy, char *,
524# if ! @HAVE_STPNCPY@ 634# if ! @HAVE_STPNCPY@
525_GL_FUNCDECL_SYS (stpncpy, char *, 635_GL_FUNCDECL_SYS (stpncpy, char *,
526 (char *restrict __dst, char const *restrict __src, 636 (char *restrict __dst, char const *restrict __src,
527 size_t __n) 637 size_t __n),
528 _GL_ARG_NONNULL ((1, 2))); 638 _GL_ARG_NONNULL ((1, 2)));
529# endif 639# endif
530_GL_CXXALIAS_SYS (stpncpy, char *, 640_GL_CXXALIAS_SYS (stpncpy, char *,
@@ -560,14 +670,14 @@ _GL_WARN_ON_USE_CXX (strchr,
560# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 670# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
561# define strchrnul rpl_strchrnul 671# define strchrnul rpl_strchrnul
562# endif 672# endif
563_GL_FUNCDECL_RPL (strchrnul, char *, (const char *__s, int __c_in) 673_GL_FUNCDECL_RPL (strchrnul, char *, (const char *__s, int __c_in),
564 _GL_ATTRIBUTE_PURE 674 _GL_ATTRIBUTE_PURE
565 _GL_ARG_NONNULL ((1))); 675 _GL_ARG_NONNULL ((1)));
566_GL_CXXALIAS_RPL (strchrnul, char *, 676_GL_CXXALIAS_RPL (strchrnul, char *,
567 (const char *str, int ch)); 677 (const char *str, int ch));
568# else 678# else
569# if ! @HAVE_STRCHRNUL@ 679# if ! @HAVE_STRCHRNUL@
570_GL_FUNCDECL_SYS (strchrnul, char *, (char const *__s, int __c_in) 680_GL_FUNCDECL_SYS (strchrnul, char *, (char const *__s, int __c_in),
571 _GL_ATTRIBUTE_PURE 681 _GL_ATTRIBUTE_PURE
572 _GL_ARG_NONNULL ((1))); 682 _GL_ARG_NONNULL ((1)));
573# endif 683# endif
@@ -606,7 +716,7 @@ _GL_WARN_ON_USE (strchrnul, "strchrnul is unportable - "
606# define strdup rpl_strdup 716# define strdup rpl_strdup
607# endif 717# endif
608_GL_FUNCDECL_RPL (strdup, char *, 718_GL_FUNCDECL_RPL (strdup, char *,
609 (char const *__s) 719 (char const *__s),
610 _GL_ARG_NONNULL ((1)) 720 _GL_ARG_NONNULL ((1))
611 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 721 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
612_GL_CXXALIAS_RPL (strdup, char *, (char const *__s)); 722_GL_CXXALIAS_RPL (strdup, char *, (char const *__s));
@@ -621,16 +731,17 @@ _GL_CXXALIAS_MDA (strdup, char *, (char const *__s));
621 /* strdup exists as a function and as a macro. Get rid of the macro. */ 731 /* strdup exists as a function and as a macro. Get rid of the macro. */
622# undef strdup 732# undef strdup
623# endif 733# endif
624# if (!@HAVE_DECL_STRDUP@ || __GNUC__ >= 11) && !defined strdup 734# if (!@HAVE_DECL_STRDUP@ || (__GNUC__ >= 11 && !defined __clang__)) \
735 && !defined strdup
625# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2 736# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
626_GL_FUNCDECL_SYS (strdup, char *, 737_GL_FUNCDECL_SYS (strdup, char *,
627 (char const *__s) 738 (char const *__s),
628 _GL_ATTRIBUTE_NOTHROW
629 _GL_ARG_NONNULL ((1)) 739 _GL_ARG_NONNULL ((1))
630 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 740 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE)
741 _GL_ATTRIBUTE_NOTHROW;
631# else 742# else
632_GL_FUNCDECL_SYS (strdup, char *, 743_GL_FUNCDECL_SYS (strdup, char *,
633 (char const *__s) 744 (char const *__s),
634 _GL_ARG_NONNULL ((1)) 745 _GL_ARG_NONNULL ((1))
635 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 746 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
636# endif 747# endif
@@ -639,17 +750,17 @@ _GL_CXXALIAS_SYS (strdup, char *, (char const *__s));
639# endif 750# endif
640_GL_CXXALIASWARN (strdup); 751_GL_CXXALIASWARN (strdup);
641#else 752#else
642# if __GNUC__ >= 11 && !defined strdup 753# if (__GNUC__ >= 11 && !defined __clang__) && !defined strdup
643/* For -Wmismatched-dealloc: Associate strdup with free or rpl_free. */ 754/* For -Wmismatched-dealloc: Associate strdup with free or rpl_free. */
644# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2 755# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
645_GL_FUNCDECL_SYS (strdup, char *, 756_GL_FUNCDECL_SYS (strdup, char *,
646 (char const *__s) 757 (char const *__s),
647 _GL_ATTRIBUTE_NOTHROW
648 _GL_ARG_NONNULL ((1)) 758 _GL_ARG_NONNULL ((1))
649 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 759 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE)
760 _GL_ATTRIBUTE_NOTHROW;
650# else 761# else
651_GL_FUNCDECL_SYS (strdup, char *, 762_GL_FUNCDECL_SYS (strdup, char *,
652 (char const *__s) 763 (char const *__s),
653 _GL_ARG_NONNULL ((1)) 764 _GL_ARG_NONNULL ((1))
654 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 765 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
655# endif 766# endif
@@ -688,8 +799,9 @@ _GL_CXXALIASWARN (strdup);
688# define strncat rpl_strncat 799# define strncat rpl_strncat
689# endif 800# endif
690_GL_FUNCDECL_RPL (strncat, char *, 801_GL_FUNCDECL_RPL (strncat, char *,
691 (char *restrict dest, const char *restrict src, size_t n) 802 (char *restrict dest, const char *restrict src, size_t n),
692 _GL_ARG_NONNULL ((1, 2))); 803 _GL_ARG_NONNULL ((1))
804 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3));
693_GL_CXXALIAS_RPL (strncat, char *, 805_GL_CXXALIAS_RPL (strncat, char *,
694 (char *restrict dest, const char *restrict src, size_t n)); 806 (char *restrict dest, const char *restrict src, size_t n));
695# else 807# else
@@ -707,6 +819,35 @@ _GL_WARN_ON_USE (strncat, "strncat is unportable - "
707# endif 819# endif
708#endif 820#endif
709 821
822/* Copy no more than N bytes of SRC to DST, returning DST. */
823#if @GNULIB_STRNCPY@
824# if @REPLACE_STRNCPY@
825# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
826# undef strncpy
827# define strncpy rpl_strncpy
828# endif
829_GL_FUNCDECL_RPL (strncpy, char *,
830 (char *restrict __dst, char const *restrict __src,
831 size_t __n),
832 _GL_ARG_NONNULL ((1, 2)));
833_GL_CXXALIAS_RPL (strncpy, char *,
834 (char *restrict __dst, char const *restrict __src,
835 size_t __n));
836# else
837_GL_CXXALIAS_SYS (strncpy, char *,
838 (char *restrict __dst, char const *restrict __src,
839 size_t __n));
840# endif
841# if __GLIBC__ >= 2
842_GL_CXXALIASWARN (strncpy);
843# endif
844#elif defined GNULIB_POSIXCHECK
845# if HAVE_RAW_DECL_STRNCPY
846_GL_WARN_ON_USE (strncpy, "strncpy is unportable - "
847 "use gnulib module strncpy for portability");
848# endif
849#endif
850
710/* Return a newly allocated copy of at most N bytes of STRING. */ 851/* Return a newly allocated copy of at most N bytes of STRING. */
711#if @GNULIB_STRNDUP@ 852#if @GNULIB_STRNDUP@
712# if @REPLACE_STRNDUP@ 853# if @REPLACE_STRNDUP@
@@ -715,22 +856,23 @@ _GL_WARN_ON_USE (strncat, "strncat is unportable - "
715# define strndup rpl_strndup 856# define strndup rpl_strndup
716# endif 857# endif
717_GL_FUNCDECL_RPL (strndup, char *, 858_GL_FUNCDECL_RPL (strndup, char *,
718 (char const *__s, size_t __n) 859 (char const *__s, size_t __n),
719 _GL_ARG_NONNULL ((1)) 860 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 2)
720 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 861 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
721_GL_CXXALIAS_RPL (strndup, char *, (char const *__s, size_t __n)); 862_GL_CXXALIAS_RPL (strndup, char *, (char const *__s, size_t __n));
722# else 863# else
723# if !@HAVE_DECL_STRNDUP@ || (__GNUC__ >= 11 && !defined strndup) 864# if !@HAVE_DECL_STRNDUP@ \
865 || ((__GNUC__ >= 11 && !defined __clang__) && !defined strndup)
724# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2 866# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
725_GL_FUNCDECL_SYS (strndup, char *, 867_GL_FUNCDECL_SYS (strndup, char *,
726 (char const *__s, size_t __n) 868 (char const *__s, size_t __n),
727 _GL_ATTRIBUTE_NOTHROW 869 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 2)
728 _GL_ARG_NONNULL ((1)) 870 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE)
729 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 871 _GL_ATTRIBUTE_NOTHROW;
730# else 872# else
731_GL_FUNCDECL_SYS (strndup, char *, 873_GL_FUNCDECL_SYS (strndup, char *,
732 (char const *__s, size_t __n) 874 (char const *__s, size_t __n),
733 _GL_ARG_NONNULL ((1)) 875 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 2)
734 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 876 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
735# endif 877# endif
736# endif 878# endif
@@ -738,18 +880,18 @@ _GL_CXXALIAS_SYS (strndup, char *, (char const *__s, size_t __n));
738# endif 880# endif
739_GL_CXXALIASWARN (strndup); 881_GL_CXXALIASWARN (strndup);
740#else 882#else
741# if __GNUC__ >= 11 && !defined strndup 883# if (__GNUC__ >= 11 && !defined __clang__) && !defined strndup
742/* For -Wmismatched-dealloc: Associate strndup with free or rpl_free. */ 884/* For -Wmismatched-dealloc: Associate strndup with free or rpl_free. */
743# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2 885# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
744_GL_FUNCDECL_SYS (strndup, char *, 886_GL_FUNCDECL_SYS (strndup, char *,
745 (char const *__s, size_t __n) 887 (char const *__s, size_t __n),
746 _GL_ATTRIBUTE_NOTHROW 888 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 2)
747 _GL_ARG_NONNULL ((1)) 889 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE)
748 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 890 _GL_ATTRIBUTE_NOTHROW;
749# else 891# else
750_GL_FUNCDECL_SYS (strndup, char *, 892_GL_FUNCDECL_SYS (strndup, char *,
751 (char const *__s, size_t __n) 893 (char const *__s, size_t __n),
752 _GL_ARG_NONNULL ((1)) 894 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 2)
753 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 895 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
754# endif 896# endif
755# endif 897# endif
@@ -771,13 +913,13 @@ _GL_WARN_ON_USE (strndup, "strndup is unportable - "
771# undef strnlen 913# undef strnlen
772# define strnlen rpl_strnlen 914# define strnlen rpl_strnlen
773# endif 915# endif
774_GL_FUNCDECL_RPL (strnlen, size_t, (char const *__s, size_t __maxlen) 916_GL_FUNCDECL_RPL (strnlen, size_t, (char const *__s, size_t __maxlen),
775 _GL_ATTRIBUTE_PURE 917 _GL_ATTRIBUTE_PURE
776 _GL_ARG_NONNULL ((1))); 918 _GL_ARG_NONNULL ((1)));
777_GL_CXXALIAS_RPL (strnlen, size_t, (char const *__s, size_t __maxlen)); 919_GL_CXXALIAS_RPL (strnlen, size_t, (char const *__s, size_t __maxlen));
778# else 920# else
779# if ! @HAVE_DECL_STRNLEN@ 921# if ! @HAVE_DECL_STRNLEN@
780_GL_FUNCDECL_SYS (strnlen, size_t, (char const *__s, size_t __maxlen) 922_GL_FUNCDECL_SYS (strnlen, size_t, (char const *__s, size_t __maxlen),
781 _GL_ATTRIBUTE_PURE 923 _GL_ATTRIBUTE_PURE
782 _GL_ARG_NONNULL ((1))); 924 _GL_ARG_NONNULL ((1)));
783# endif 925# endif
@@ -807,7 +949,7 @@ _GL_WARN_ON_USE (strcspn, "strcspn cannot work correctly on character strings "
807/* Find the first occurrence in S of any character in ACCEPT. */ 949/* Find the first occurrence in S of any character in ACCEPT. */
808#if @GNULIB_STRPBRK@ 950#if @GNULIB_STRPBRK@
809# if ! @HAVE_STRPBRK@ 951# if ! @HAVE_STRPBRK@
810_GL_FUNCDECL_SYS (strpbrk, char *, (char const *__s, char const *__accept) 952_GL_FUNCDECL_SYS (strpbrk, char *, (char const *__s, char const *__accept),
811 _GL_ATTRIBUTE_PURE 953 _GL_ATTRIBUTE_PURE
812 _GL_ARG_NONNULL ((1, 2))); 954 _GL_ARG_NONNULL ((1, 2)));
813# endif 955# endif
@@ -892,7 +1034,7 @@ _GL_WARN_ON_USE_CXX (strrchr,
892#if @GNULIB_STRSEP@ 1034#if @GNULIB_STRSEP@
893# if ! @HAVE_STRSEP@ 1035# if ! @HAVE_STRSEP@
894_GL_FUNCDECL_SYS (strsep, char *, 1036_GL_FUNCDECL_SYS (strsep, char *,
895 (char **restrict __stringp, char const *restrict __delim) 1037 (char **restrict __stringp, char const *restrict __delim),
896 _GL_ARG_NONNULL ((1, 2))); 1038 _GL_ARG_NONNULL ((1, 2)));
897# endif 1039# endif
898_GL_CXXALIAS_SYS (strsep, char *, 1040_GL_CXXALIAS_SYS (strsep, char *,
@@ -917,7 +1059,7 @@ _GL_WARN_ON_USE (strsep, "strsep is unportable - "
917# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1059# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
918# define strstr rpl_strstr 1060# define strstr rpl_strstr
919# endif 1061# endif
920_GL_FUNCDECL_RPL (strstr, char *, (const char *haystack, const char *needle) 1062_GL_FUNCDECL_RPL (strstr, char *, (const char *haystack, const char *needle),
921 _GL_ATTRIBUTE_PURE 1063 _GL_ATTRIBUTE_PURE
922 _GL_ARG_NONNULL ((1, 2))); 1064 _GL_ARG_NONNULL ((1, 2)));
923_GL_CXXALIAS_RPL (strstr, char *, (const char *haystack, const char *needle)); 1065_GL_CXXALIAS_RPL (strstr, char *, (const char *haystack, const char *needle));
@@ -948,11 +1090,13 @@ _GL_CXXALIASWARN (strstr);
948 as a sequence of bytes, not of characters. */ 1090 as a sequence of bytes, not of characters. */
949# undef strstr 1091# undef strstr
950/* Assume strstr is always declared. */ 1092/* Assume strstr is always declared. */
951_GL_WARN_ON_USE (strstr, "strstr is quadratic on many systems, and cannot " 1093_GL_WARN_ON_USE_CXX (strstr,
952 "work correctly on character strings in most " 1094 const char *, char *, (const char *, const char *),
953 "multibyte locales - " 1095 "strstr is quadratic on many systems, and cannot "
954 "use mbsstr if you care about internationalization, " 1096 "work correctly on character strings in most "
955 "or use strstr if you care about speed"); 1097 "multibyte locales - "
1098 "use mbsstr if you care about internationalization, "
1099 "or use strstr if you care about speed");
956#endif 1100#endif
957 1101
958/* Find the first occurrence of NEEDLE in HAYSTACK, using case-insensitive 1102/* Find the first occurrence of NEEDLE in HAYSTACK, using case-insensitive
@@ -963,7 +1107,7 @@ _GL_WARN_ON_USE (strstr, "strstr is quadratic on many systems, and cannot "
963# define strcasestr rpl_strcasestr 1107# define strcasestr rpl_strcasestr
964# endif 1108# endif
965_GL_FUNCDECL_RPL (strcasestr, char *, 1109_GL_FUNCDECL_RPL (strcasestr, char *,
966 (const char *haystack, const char *needle) 1110 (const char *haystack, const char *needle),
967 _GL_ATTRIBUTE_PURE 1111 _GL_ATTRIBUTE_PURE
968 _GL_ARG_NONNULL ((1, 2))); 1112 _GL_ARG_NONNULL ((1, 2)));
969_GL_CXXALIAS_RPL (strcasestr, char *, 1113_GL_CXXALIAS_RPL (strcasestr, char *,
@@ -971,7 +1115,7 @@ _GL_CXXALIAS_RPL (strcasestr, char *,
971# else 1115# else
972# if ! @HAVE_STRCASESTR@ 1116# if ! @HAVE_STRCASESTR@
973_GL_FUNCDECL_SYS (strcasestr, char *, 1117_GL_FUNCDECL_SYS (strcasestr, char *,
974 (const char *haystack, const char *needle) 1118 (const char *haystack, const char *needle),
975 _GL_ATTRIBUTE_PURE 1119 _GL_ATTRIBUTE_PURE
976 _GL_ARG_NONNULL ((1, 2))); 1120 _GL_ARG_NONNULL ((1, 2)));
977# endif 1121# endif
@@ -1038,7 +1182,7 @@ _GL_WARN_ON_USE (strcasestr, "strcasestr does work correctly on character "
1038# endif 1182# endif
1039_GL_FUNCDECL_RPL (strtok_r, char *, 1183_GL_FUNCDECL_RPL (strtok_r, char *,
1040 (char *restrict s, char const *restrict delim, 1184 (char *restrict s, char const *restrict delim,
1041 char **restrict save_ptr) 1185 char **restrict save_ptr),
1042 _GL_ARG_NONNULL ((2, 3))); 1186 _GL_ARG_NONNULL ((2, 3)));
1043_GL_CXXALIAS_RPL (strtok_r, char *, 1187_GL_CXXALIAS_RPL (strtok_r, char *,
1044 (char *restrict s, char const *restrict delim, 1188 (char *restrict s, char const *restrict delim,
@@ -1050,7 +1194,7 @@ _GL_CXXALIAS_RPL (strtok_r, char *,
1050# if ! @HAVE_DECL_STRTOK_R@ 1194# if ! @HAVE_DECL_STRTOK_R@
1051_GL_FUNCDECL_SYS (strtok_r, char *, 1195_GL_FUNCDECL_SYS (strtok_r, char *,
1052 (char *restrict s, char const *restrict delim, 1196 (char *restrict s, char const *restrict delim,
1053 char **restrict save_ptr) 1197 char **restrict save_ptr),
1054 _GL_ARG_NONNULL ((2, 3))); 1198 _GL_ARG_NONNULL ((2, 3)));
1055# endif 1199# endif
1056_GL_CXXALIAS_SYS (strtok_r, char *, 1200_GL_CXXALIAS_SYS (strtok_r, char *,
@@ -1075,6 +1219,22 @@ _GL_WARN_ON_USE (strtok_r, "strtok_r is unportable - "
1075/* The following functions are not specified by POSIX. They are gnulib 1219/* The following functions are not specified by POSIX. They are gnulib
1076 extensions. */ 1220 extensions. */
1077 1221
1222#if @GNULIB_STR_STARTSWITH@
1223/* Returns true if STRING starts with PREFIX.
1224 Returns false otherwise. */
1225_GL_EXTERN_C bool str_startswith (const char *string, const char *prefix)
1226 _GL_ATTRIBUTE_PURE
1227 _GL_ARG_NONNULL ((1, 2));
1228#endif
1229
1230#if @GNULIB_STR_ENDSWITH@
1231/* Returns true if STRING ends with SUFFIX.
1232 Returns false otherwise. */
1233_GL_EXTERN_C bool str_endswith (const char *string, const char *prefix)
1234 _GL_ATTRIBUTE_PURE
1235 _GL_ARG_NONNULL ((1, 2));
1236#endif
1237
1078#if @GNULIB_MBSLEN@ 1238#if @GNULIB_MBSLEN@
1079/* Return the number of multibyte characters in the character string STRING. 1239/* Return the number of multibyte characters in the character string STRING.
1080 This considers multibyte characters, unlike strlen, which counts bytes. */ 1240 This considers multibyte characters, unlike strlen, which counts bytes. */
@@ -1085,12 +1245,12 @@ _GL_WARN_ON_USE (strtok_r, "strtok_r is unportable - "
1085# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1245# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1086# define mbslen rpl_mbslen 1246# define mbslen rpl_mbslen
1087# endif 1247# endif
1088_GL_FUNCDECL_RPL (mbslen, size_t, (const char *string) 1248_GL_FUNCDECL_RPL (mbslen, size_t, (const char *string),
1089 _GL_ATTRIBUTE_PURE 1249 _GL_ATTRIBUTE_PURE
1090 _GL_ARG_NONNULL ((1))); 1250 _GL_ARG_NONNULL ((1)));
1091_GL_CXXALIAS_RPL (mbslen, size_t, (const char *string)); 1251_GL_CXXALIAS_RPL (mbslen, size_t, (const char *string));
1092# else 1252# else
1093_GL_FUNCDECL_SYS (mbslen, size_t, (const char *string) 1253_GL_FUNCDECL_SYS (mbslen, size_t, (const char *string),
1094 _GL_ATTRIBUTE_PURE 1254 _GL_ATTRIBUTE_PURE
1095 _GL_ARG_NONNULL ((1))); 1255 _GL_ARG_NONNULL ((1)));
1096_GL_CXXALIAS_SYS (mbslen, size_t, (const char *string)); 1256_GL_CXXALIAS_SYS (mbslen, size_t, (const char *string));
@@ -1117,12 +1277,12 @@ _GL_EXTERN_C size_t mbsnlen (const char *string, size_t len)
1117# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1277# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1118# define mbschr rpl_mbschr /* avoid collision with HP-UX function */ 1278# define mbschr rpl_mbschr /* avoid collision with HP-UX function */
1119# endif 1279# endif
1120_GL_FUNCDECL_RPL (mbschr, char *, (const char *string, int c) 1280_GL_FUNCDECL_RPL (mbschr, char *, (const char *string, int c),
1121 _GL_ATTRIBUTE_PURE 1281 _GL_ATTRIBUTE_PURE
1122 _GL_ARG_NONNULL ((1))); 1282 _GL_ARG_NONNULL ((1)));
1123_GL_CXXALIAS_RPL (mbschr, char *, (const char *string, int c)); 1283_GL_CXXALIAS_RPL (mbschr, char *, (const char *string, int c));
1124# else 1284# else
1125_GL_FUNCDECL_SYS (mbschr, char *, (const char *string, int c) 1285_GL_FUNCDECL_SYS (mbschr, char *, (const char *string, int c),
1126 _GL_ATTRIBUTE_PURE 1286 _GL_ATTRIBUTE_PURE
1127 _GL_ARG_NONNULL ((1))); 1287 _GL_ARG_NONNULL ((1)));
1128_GL_CXXALIAS_SYS (mbschr, char *, (const char *string, int c)); 1288_GL_CXXALIAS_SYS (mbschr, char *, (const char *string, int c));
@@ -1139,12 +1299,12 @@ _GL_CXXALIASWARN (mbschr);
1139# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1299# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1140# define mbsrchr rpl_mbsrchr /* avoid collision with system function */ 1300# define mbsrchr rpl_mbsrchr /* avoid collision with system function */
1141# endif 1301# endif
1142_GL_FUNCDECL_RPL (mbsrchr, char *, (const char *string, int c) 1302_GL_FUNCDECL_RPL (mbsrchr, char *, (const char *string, int c),
1143 _GL_ATTRIBUTE_PURE 1303 _GL_ATTRIBUTE_PURE
1144 _GL_ARG_NONNULL ((1))); 1304 _GL_ARG_NONNULL ((1)));
1145_GL_CXXALIAS_RPL (mbsrchr, char *, (const char *string, int c)); 1305_GL_CXXALIAS_RPL (mbsrchr, char *, (const char *string, int c));
1146# else 1306# else
1147_GL_FUNCDECL_SYS (mbsrchr, char *, (const char *string, int c) 1307_GL_FUNCDECL_SYS (mbsrchr, char *, (const char *string, int c),
1148 _GL_ATTRIBUTE_PURE 1308 _GL_ATTRIBUTE_PURE
1149 _GL_ARG_NONNULL ((1))); 1309 _GL_ARG_NONNULL ((1)));
1150_GL_CXXALIAS_SYS (mbsrchr, char *, (const char *string, int c)); 1310_GL_CXXALIAS_SYS (mbsrchr, char *, (const char *string, int c));
@@ -1160,6 +1320,33 @@ _GL_CXXALIASWARN (mbsrchr);
1160_GL_EXTERN_C char * mbsstr (const char *haystack, const char *needle) 1320_GL_EXTERN_C char * mbsstr (const char *haystack, const char *needle)
1161 _GL_ATTRIBUTE_PURE 1321 _GL_ATTRIBUTE_PURE
1162 _GL_ARG_NONNULL ((1, 2)); 1322 _GL_ARG_NONNULL ((1, 2));
1323# ifndef _GL_NO_CONST_GENERICS
1324/* Don't silently convert a 'const char *' to a 'char *'. Programmers want
1325 compiler warnings for 'const' related mistakes. */
1326# ifdef __cplusplus
1327extern "C++" { /* needed for AIX */
1328template <typename T>
1329 T * mbsstr_template (T* haystack, const char *needle);
1330template <>
1331 inline char * mbsstr_template (char *haystack, const char *needle)
1332 { return mbsstr (haystack, needle); }
1333template <>
1334 inline const char * mbsstr_template (const char *haystack, const char *needle)
1335 { return mbsstr (haystack, needle); }
1336}
1337# undef mbsstr
1338# define mbsstr mbsstr_template
1339# elif !defined mbsstr
1340# if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
1341 || defined __ICC || defined __TINYC__ \
1342 || (__STDC_VERSION__ >= 201112L && !(defined __GNUC__ || defined __clang__)))
1343# define mbsstr(h,n) \
1344 _Generic ((h), \
1345 char const *: (char const *) mbsstr ((h), (n)), \
1346 default : mbsstr ((h), (n)))
1347# endif
1348# endif
1349# endif
1163#endif 1350#endif
1164 1351
1165#if @GNULIB_MBSCASECMP@ 1352#if @GNULIB_MBSCASECMP@
@@ -1201,6 +1388,33 @@ _GL_EXTERN_C int mbsncasecmp (const char *s1, const char *s2, size_t n)
1201_GL_EXTERN_C char * mbspcasecmp (const char *string, const char *prefix) 1388_GL_EXTERN_C char * mbspcasecmp (const char *string, const char *prefix)
1202 _GL_ATTRIBUTE_PURE 1389 _GL_ATTRIBUTE_PURE
1203 _GL_ARG_NONNULL ((1, 2)); 1390 _GL_ARG_NONNULL ((1, 2));
1391# ifndef _GL_NO_CONST_GENERICS
1392/* Don't silently convert a 'const char *' to a 'char *'. Programmers want
1393 compiler warnings for 'const' related mistakes. */
1394# ifdef __cplusplus
1395extern "C++" { /* needed for AIX */
1396template <typename T>
1397 T * mbspcasecmp_template (T* string, const char *prefix);
1398template <>
1399 inline char * mbspcasecmp_template (char *string, const char *prefix)
1400 { return mbspcasecmp (string, prefix); }
1401template <>
1402 inline const char * mbspcasecmp_template (const char *string, const char *prefix)
1403 { return mbspcasecmp (string, prefix); }
1404}
1405# undef mbspcasecmp
1406# define mbspcasecmp mbspcasecmp_template
1407# elif !defined mbspcasecmp
1408# if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
1409 || defined __ICC || defined __TINYC__ \
1410 || (__STDC_VERSION__ >= 201112L && !(defined __GNUC__ || defined __clang__)))
1411# define mbspcasecmp(s,p) \
1412 _Generic ((s), \
1413 char const *: (char const *) mbspcasecmp ((s), (p)), \
1414 default : mbspcasecmp ((s), (p)))
1415# endif
1416# endif
1417# endif
1204#endif 1418#endif
1205 1419
1206#if @GNULIB_MBSCASESTR@ 1420#if @GNULIB_MBSCASESTR@
@@ -1212,6 +1426,33 @@ _GL_EXTERN_C char * mbspcasecmp (const char *string, const char *prefix)
1212_GL_EXTERN_C char * mbscasestr (const char *haystack, const char *needle) 1426_GL_EXTERN_C char * mbscasestr (const char *haystack, const char *needle)
1213 _GL_ATTRIBUTE_PURE 1427 _GL_ATTRIBUTE_PURE
1214 _GL_ARG_NONNULL ((1, 2)); 1428 _GL_ARG_NONNULL ((1, 2));
1429# ifndef _GL_NO_CONST_GENERICS
1430/* Don't silently convert a 'const char *' to a 'char *'. Programmers want
1431 compiler warnings for 'const' related mistakes. */
1432# ifdef __cplusplus
1433extern "C++" { /* needed for AIX */
1434template <typename T>
1435 T * mbscasestr_template (T* haystack, const char *needle);
1436template <>
1437 inline char * mbscasestr_template (char *haystack, const char *needle)
1438 { return mbscasestr (haystack, needle); }
1439template <>
1440 inline const char * mbscasestr_template (const char *haystack, const char *needle)
1441 { return mbscasestr (haystack, needle); }
1442}
1443# undef mbscasestr
1444# define mbscasestr mbscasestr_template
1445# elif !defined mbscasestr
1446# if ((__GNUC__ + (__GNUC_MINOR__ >= 9) > 4) || (__clang_major__ >= 3) \
1447 || defined __ICC || defined __TINYC__ \
1448 || (__STDC_VERSION__ >= 201112L && !(defined __GNUC__ || defined __clang__)))
1449# define mbscasestr(h,n) \
1450 _Generic ((h), \
1451 char const *: (char const *) mbscasestr ((h), (n)), \
1452 default : mbscasestr ((h), (n)))
1453# endif
1454# endif
1455# endif
1215#endif 1456#endif
1216 1457
1217#if @GNULIB_MBSCSPN@ 1458#if @GNULIB_MBSCSPN@
@@ -1234,12 +1475,12 @@ _GL_EXTERN_C size_t mbscspn (const char *string, const char *accept)
1234# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1475# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1235# define mbspbrk rpl_mbspbrk /* avoid collision with HP-UX function */ 1476# define mbspbrk rpl_mbspbrk /* avoid collision with HP-UX function */
1236# endif 1477# endif
1237_GL_FUNCDECL_RPL (mbspbrk, char *, (const char *string, const char *accept) 1478_GL_FUNCDECL_RPL (mbspbrk, char *, (const char *string, const char *accept),
1238 _GL_ATTRIBUTE_PURE 1479 _GL_ATTRIBUTE_PURE
1239 _GL_ARG_NONNULL ((1, 2))); 1480 _GL_ARG_NONNULL ((1, 2)));
1240_GL_CXXALIAS_RPL (mbspbrk, char *, (const char *string, const char *accept)); 1481_GL_CXXALIAS_RPL (mbspbrk, char *, (const char *string, const char *accept));
1241# else 1482# else
1242_GL_FUNCDECL_SYS (mbspbrk, char *, (const char *string, const char *accept) 1483_GL_FUNCDECL_SYS (mbspbrk, char *, (const char *string, const char *accept),
1243 _GL_ATTRIBUTE_PURE 1484 _GL_ATTRIBUTE_PURE
1244 _GL_ARG_NONNULL ((1, 2))); 1485 _GL_ARG_NONNULL ((1, 2)));
1245_GL_CXXALIAS_SYS (mbspbrk, char *, (const char *string, const char *accept)); 1486_GL_CXXALIAS_SYS (mbspbrk, char *, (const char *string, const char *accept));
@@ -1299,6 +1540,26 @@ _GL_EXTERN_C char * mbstok_r (char *restrict string, const char *delim,
1299 _GL_ARG_NONNULL ((2, 3)); 1540 _GL_ARG_NONNULL ((2, 3));
1300#endif 1541#endif
1301 1542
1543#if @GNULIB_MBS_STARTSWITH@
1544/* Returns true if STRING starts with PREFIX.
1545 Returns false otherwise. */
1546_GL_EXTERN_C bool mbs_startswith (const char *string, const char *prefix)
1547 _GL_ATTRIBUTE_PURE
1548 _GL_ARG_NONNULL ((1, 2));
1549/* No extra code is needed for multibyte locales for this function. */
1550# define mbs_startswith str_startswith
1551#endif
1552
1553#if @GNULIB_MBS_ENDSWITH@
1554/* Returns true if STRING ends with SUFFIX.
1555 Returns false otherwise.
1556 Unlike str_endswith(), this function works correctly in multibyte locales.
1557 */
1558_GL_EXTERN_C bool mbs_endswith (const char *string, const char *suffix)
1559 _GL_ATTRIBUTE_PURE
1560 _GL_ARG_NONNULL ((1, 2));
1561#endif
1562
1302/* Map any int, typically from errno, into an error message. */ 1563/* Map any int, typically from errno, into an error message. */
1303#if @GNULIB_STRERROR@ 1564#if @GNULIB_STRERROR@
1304# if @REPLACE_STRERROR@ 1565# if @REPLACE_STRERROR@
@@ -1306,7 +1567,7 @@ _GL_EXTERN_C char * mbstok_r (char *restrict string, const char *delim,
1306# undef strerror 1567# undef strerror
1307# define strerror rpl_strerror 1568# define strerror rpl_strerror
1308# endif 1569# endif
1309_GL_FUNCDECL_RPL (strerror, char *, (int)); 1570_GL_FUNCDECL_RPL (strerror, char *, (int), );
1310_GL_CXXALIAS_RPL (strerror, char *, (int)); 1571_GL_CXXALIAS_RPL (strerror, char *, (int));
1311# else 1572# else
1312_GL_CXXALIAS_SYS (strerror, char *, (int)); 1573_GL_CXXALIAS_SYS (strerror, char *, (int));
@@ -1329,12 +1590,12 @@ _GL_WARN_ON_USE (strerror, "strerror is unportable - "
1329# undef strerror_r 1590# undef strerror_r
1330# define strerror_r rpl_strerror_r 1591# define strerror_r rpl_strerror_r
1331# endif 1592# endif
1332_GL_FUNCDECL_RPL (strerror_r, int, (int errnum, char *buf, size_t buflen) 1593_GL_FUNCDECL_RPL (strerror_r, int, (int errnum, char *buf, size_t buflen),
1333 _GL_ARG_NONNULL ((2))); 1594 _GL_ARG_NONNULL ((2)));
1334_GL_CXXALIAS_RPL (strerror_r, int, (int errnum, char *buf, size_t buflen)); 1595_GL_CXXALIAS_RPL (strerror_r, int, (int errnum, char *buf, size_t buflen));
1335# else 1596# else
1336# if !@HAVE_DECL_STRERROR_R@ 1597# if !@HAVE_DECL_STRERROR_R@
1337_GL_FUNCDECL_SYS (strerror_r, int, (int errnum, char *buf, size_t buflen) 1598_GL_FUNCDECL_SYS (strerror_r, int, (int errnum, char *buf, size_t buflen),
1338 _GL_ARG_NONNULL ((2))); 1599 _GL_ARG_NONNULL ((2)));
1339# endif 1600# endif
1340_GL_CXXALIAS_SYS (strerror_r, int, (int errnum, char *buf, size_t buflen)); 1601_GL_CXXALIAS_SYS (strerror_r, int, (int errnum, char *buf, size_t buflen));
@@ -1350,6 +1611,44 @@ _GL_WARN_ON_USE (strerror_r, "strerror_r is unportable - "
1350# endif 1611# endif
1351#endif 1612#endif
1352 1613
1614/* Map any int, typically from errno, into an error message.
1615 With locale_t argument. */
1616#if @GNULIB_STRERROR_L@
1617# if @REPLACE_STRERROR_L@
1618# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1619# undef strerror_l
1620# define strerror_l rpl_strerror_l
1621# endif
1622_GL_FUNCDECL_RPL (strerror_l, char *, (int errnum, locale_t locale),
1623 _GL_ARG_NONNULL ((2)));
1624_GL_CXXALIAS_RPL (strerror_l, char *, (int errnum, locale_t locale));
1625# else
1626# if !@HAVE_STRERROR_L@
1627_GL_FUNCDECL_SYS (strerror_l, char *, (int errnum, locale_t locale),
1628 _GL_ARG_NONNULL ((2)));
1629# endif
1630_GL_CXXALIAS_SYS (strerror_l, char *, (int errnum, locale_t locale));
1631# endif
1632# if __GLIBC__ >= 2
1633_GL_CXXALIASWARN (strerror_l);
1634# endif
1635#elif defined GNULIB_POSIXCHECK
1636# undef strerror_l
1637# if HAVE_RAW_DECL_STRERROR_L
1638_GL_WARN_ON_USE (strerror_l, "strerror_l is unportable - "
1639 "use gnulib module strerror_l for portability");
1640# endif
1641#endif
1642
1643/* Map any int, typically from errno, into an error message. Multithread-safe,
1644 with locale_t argument.
1645 Not portable! Only provided by gnulib. */
1646#if @GNULIB_STRERROR_L@
1647_GL_FUNCDECL_SYS (strerror_l_r, int,
1648 (int errnum, char *buf, size_t buflen, locale_t locale),
1649 _GL_ARG_NONNULL ((2, 4)));
1650#endif
1651
1353/* Return the name of the system error code ERRNUM. */ 1652/* Return the name of the system error code ERRNUM. */
1354#if @GNULIB_STRERRORNAME_NP@ 1653#if @GNULIB_STRERRORNAME_NP@
1355# if @REPLACE_STRERRORNAME_NP@ 1654# if @REPLACE_STRERRORNAME_NP@
@@ -1357,15 +1656,17 @@ _GL_WARN_ON_USE (strerror_r, "strerror_r is unportable - "
1357# undef strerrorname_np 1656# undef strerrorname_np
1358# define strerrorname_np rpl_strerrorname_np 1657# define strerrorname_np rpl_strerrorname_np
1359# endif 1658# endif
1360_GL_FUNCDECL_RPL (strerrorname_np, const char *, (int errnum)); 1659_GL_FUNCDECL_RPL (strerrorname_np, const char *, (int errnum), );
1361_GL_CXXALIAS_RPL (strerrorname_np, const char *, (int errnum)); 1660_GL_CXXALIAS_RPL (strerrorname_np, const char *, (int errnum));
1362# else 1661# else
1363# if !@HAVE_STRERRORNAME_NP@ 1662# if !@HAVE_STRERRORNAME_NP@
1364_GL_FUNCDECL_SYS (strerrorname_np, const char *, (int errnum)); 1663_GL_FUNCDECL_SYS (strerrorname_np, const char *, (int errnum), );
1365# endif 1664# endif
1366_GL_CXXALIAS_SYS (strerrorname_np, const char *, (int errnum)); 1665_GL_CXXALIAS_SYS (strerrorname_np, const char *, (int errnum));
1367# endif 1666# endif
1667# if __GLIBC__ >= 2
1368_GL_CXXALIASWARN (strerrorname_np); 1668_GL_CXXALIASWARN (strerrorname_np);
1669# endif
1369#elif defined GNULIB_POSIXCHECK 1670#elif defined GNULIB_POSIXCHECK
1370# undef strerrorname_np 1671# undef strerrorname_np
1371# if HAVE_RAW_DECL_STRERRORNAME_NP 1672# if HAVE_RAW_DECL_STRERRORNAME_NP
@@ -1377,7 +1678,7 @@ _GL_WARN_ON_USE (strerrorname_np, "strerrorname_np is unportable - "
1377/* Return an abbreviation string for the signal number SIG. */ 1678/* Return an abbreviation string for the signal number SIG. */
1378#if @GNULIB_SIGABBREV_NP@ 1679#if @GNULIB_SIGABBREV_NP@
1379# if ! @HAVE_SIGABBREV_NP@ 1680# if ! @HAVE_SIGABBREV_NP@
1380_GL_FUNCDECL_SYS (sigabbrev_np, const char *, (int sig)); 1681_GL_FUNCDECL_SYS (sigabbrev_np, const char *, (int sig), );
1381# endif 1682# endif
1382_GL_CXXALIAS_SYS (sigabbrev_np, const char *, (int sig)); 1683_GL_CXXALIAS_SYS (sigabbrev_np, const char *, (int sig));
1383_GL_CXXALIASWARN (sigabbrev_np); 1684_GL_CXXALIASWARN (sigabbrev_np);
@@ -1392,7 +1693,7 @@ _GL_WARN_ON_USE (sigabbrev_np, "sigabbrev_np is unportable - "
1392/* Return an English description string for the signal number SIG. */ 1693/* Return an English description string for the signal number SIG. */
1393#if @GNULIB_SIGDESCR_NP@ 1694#if @GNULIB_SIGDESCR_NP@
1394# if ! @HAVE_SIGDESCR_NP@ 1695# if ! @HAVE_SIGDESCR_NP@
1395_GL_FUNCDECL_SYS (sigdescr_np, const char *, (int sig)); 1696_GL_FUNCDECL_SYS (sigdescr_np, const char *, (int sig), );
1396# endif 1697# endif
1397_GL_CXXALIAS_SYS (sigdescr_np, const char *, (int sig)); 1698_GL_CXXALIAS_SYS (sigdescr_np, const char *, (int sig));
1398_GL_CXXALIASWARN (sigdescr_np); 1699_GL_CXXALIASWARN (sigdescr_np);
@@ -1409,11 +1710,11 @@ _GL_WARN_ON_USE (sigdescr_np, "sigdescr_np is unportable - "
1409# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1710# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1410# define strsignal rpl_strsignal 1711# define strsignal rpl_strsignal
1411# endif 1712# endif
1412_GL_FUNCDECL_RPL (strsignal, char *, (int __sig)); 1713_GL_FUNCDECL_RPL (strsignal, char *, (int __sig), );
1413_GL_CXXALIAS_RPL (strsignal, char *, (int __sig)); 1714_GL_CXXALIAS_RPL (strsignal, char *, (int __sig));
1414# else 1715# else
1415# if ! @HAVE_DECL_STRSIGNAL@ 1716# if ! @HAVE_DECL_STRSIGNAL@
1416_GL_FUNCDECL_SYS (strsignal, char *, (int __sig)); 1717_GL_FUNCDECL_SYS (strsignal, char *, (int __sig), );
1417# endif 1718# endif
1418/* Need to cast, because on Cygwin 1.5.x systems, the return type is 1719/* Need to cast, because on Cygwin 1.5.x systems, the return type is
1419 'const char *'. */ 1720 'const char *'. */
@@ -1433,13 +1734,13 @@ _GL_WARN_ON_USE (strsignal, "strsignal is unportable - "
1433# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1734# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1434# define strverscmp rpl_strverscmp 1735# define strverscmp rpl_strverscmp
1435# endif 1736# endif
1436_GL_FUNCDECL_RPL (strverscmp, int, (const char *, const char *) 1737_GL_FUNCDECL_RPL (strverscmp, int, (const char *, const char *),
1437 _GL_ATTRIBUTE_PURE 1738 _GL_ATTRIBUTE_PURE
1438 _GL_ARG_NONNULL ((1, 2))); 1739 _GL_ARG_NONNULL ((1, 2)));
1439_GL_CXXALIAS_RPL (strverscmp, int, (const char *, const char *)); 1740_GL_CXXALIAS_RPL (strverscmp, int, (const char *, const char *));
1440# else 1741# else
1441# if !@HAVE_STRVERSCMP@ 1742# if !@HAVE_STRVERSCMP@
1442_GL_FUNCDECL_SYS (strverscmp, int, (const char *, const char *) 1743_GL_FUNCDECL_SYS (strverscmp, int, (const char *, const char *),
1443 _GL_ATTRIBUTE_PURE 1744 _GL_ATTRIBUTE_PURE
1444 _GL_ARG_NONNULL ((1, 2))); 1745 _GL_ARG_NONNULL ((1, 2)));
1445# endif 1746# endif
diff --git a/gl/strings.in.h b/gl/strings.in.h
index 2b3e062a..40c891d7 100644
--- a/gl/strings.in.h
+++ b/gl/strings.in.h
@@ -1,6 +1,6 @@
1/* A substitute <strings.h>. 1/* A substitute <strings.h>.
2 2
3 Copyright (C) 2007-2024 Free Software Foundation, Inc. 3 Copyright (C) 2007-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -36,7 +36,7 @@
36#ifndef _@GUARD_PREFIX@_STRINGS_H 36#ifndef _@GUARD_PREFIX@_STRINGS_H
37#define _@GUARD_PREFIX@_STRINGS_H 37#define _@GUARD_PREFIX@_STRINGS_H
38 38
39/* This file uses GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */ 39/* This file uses _GL_ARG_NONNULL, GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
40#if !_GL_CONFIG_H_INCLUDED 40#if !_GL_CONFIG_H_INCLUDED
41 #error "Please include config.h first." 41 #error "Please include config.h first."
42#endif 42#endif
@@ -46,6 +46,16 @@
46# include <stddef.h> 46# include <stddef.h>
47#endif 47#endif
48 48
49#if @GNULIB_STRCASECMP_L@ || @GNULIB_STRNCASECMP_L@
50/* Get locale_t. */
51# include <locale.h>
52# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ < 10) \
53 || (defined __APPLE__ && defined __MACH__))
54/* Get the declaration of strcasecmp_l. */
55# include <string.h>
56# endif
57#endif
58
49 59
50/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ 60/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
51 61
@@ -58,10 +68,10 @@ extern "C" {
58#endif 68#endif
59 69
60 70
61 /* Find the index of the least-significant set bit. */
62#if @GNULIB_FFS@ 71#if @GNULIB_FFS@
72/* Find the index of the least-significant set bit. */
63# if !@HAVE_FFS@ 73# if !@HAVE_FFS@
64_GL_FUNCDECL_SYS (ffs, int, (int i)); 74_GL_FUNCDECL_SYS (ffs, int, (int i), );
65# endif 75# endif
66_GL_CXXALIAS_SYS (ffs, int, (int i)); 76_GL_CXXALIAS_SYS (ffs, int, (int i));
67_GL_CXXALIASWARN (ffs); 77_GL_CXXALIASWARN (ffs);
@@ -72,52 +82,152 @@ _GL_WARN_ON_USE (ffs, "ffs is not portable - use the ffs module");
72# endif 82# endif
73#endif 83#endif
74 84
85#if @GNULIB_STRCASECMP@
75/* Compare strings S1 and S2, ignoring case, returning less than, equal to or 86/* Compare strings S1 and S2, ignoring case, returning less than, equal to or
76 greater than zero if S1 is lexicographically less than, equal to or greater 87 greater than zero if S1 is lexicographically less than, equal to or greater
77 than S2. 88 than S2.
78 Note: This function does not work in multibyte locales. */ 89 Note: This function does not work in multibyte locales. */
79#if ! @HAVE_STRCASECMP@ 90# if @REPLACE_STRCASECMP@
80extern int strcasecmp (char const *s1, char const *s2) 91# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
81 _GL_ARG_NONNULL ((1, 2)); 92# undef strcasecmp
82#endif 93# define strcasecmp rpl_strcasecmp
83#if defined GNULIB_POSIXCHECK 94# endif
95_GL_FUNCDECL_RPL (strcasecmp, int, (const char *, const char *),
96 _GL_ARG_NONNULL ((1, 2)));
97_GL_CXXALIAS_RPL (strcasecmp, int, (const char *, const char *));
98# else
99# if !@HAVE_STRCASECMP@
100_GL_FUNCDECL_SYS (strcasecmp, int, (const char *, const char *),
101 _GL_ARG_NONNULL ((1, 2)));
102# endif
103_GL_CXXALIAS_SYS (strcasecmp, int, (const char *, const char *));
104# endif
105# if __GLIBC__ >= 2
106_GL_CXXALIASWARN (strcasecmp);
107# endif
108#elif defined GNULIB_POSIXCHECK
84/* strcasecmp() does not work with multibyte strings: 109/* strcasecmp() does not work with multibyte strings:
85 POSIX says that it operates on "strings", and "string" in POSIX is defined 110 POSIX says that it operates on "strings", and "string" in POSIX is defined
86 as a sequence of bytes, not of characters. */ 111 as a sequence of bytes, not of characters. */
87# undef strcasecmp 112# undef strcasecmp
88# if HAVE_RAW_DECL_STRCASECMP 113# if HAVE_RAW_DECL_STRCASECMP
89_GL_WARN_ON_USE (strcasecmp, "strcasecmp cannot work correctly on character " 114_GL_WARN_ON_USE (strcasecmp, "strcasecmp cannot work correctly on character "
90 "strings in multibyte locales - " 115 "strings in multibyte locales and is unportable - "
91 "use mbscasecmp if you care about " 116 "use mbscasecmp if you care about "
92 "internationalization, or use c_strcasecmp , " 117 "internationalization, or use c_strcasecmp "
93 "gnulib module c-strcase) if you want a locale " 118 "(gnulib module c-strcasecmp) if you want a locale "
94 "independent function"); 119 "independent function");
95# endif 120# endif
96#endif 121#endif
97 122
123#if @GNULIB_STRCASECMP_L@
124# if @REPLACE_STRCASECMP_L@
125# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
126# undef strcasecmp_l
127# define strcasecmp_l rpl_strcasecmp_l
128# endif
129_GL_FUNCDECL_RPL (strcasecmp_l, int,
130 (const char *s1, const char *s2, locale_t locale),
131 _GL_ARG_NONNULL ((1, 2, 3)));
132_GL_CXXALIAS_RPL (strcasecmp_l, int,
133 (const char *s1, const char *s2, locale_t locale));
134# else
135# if !@HAVE_STRCASECMP_L@
136_GL_FUNCDECL_SYS (strcasecmp_l, int,
137 (const char *s1, const char *s2, locale_t locale),
138 _GL_ARG_NONNULL ((1, 2, 3)));
139# endif
140_GL_CXXALIAS_SYS (strcasecmp_l, int,
141 (const char *s1, const char *s2, locale_t locale));
142# endif
143# if __GLIBC__ >= 2
144_GL_CXXALIASWARN (strcasecmp_l);
145# endif
146#elif defined GNULIB_POSIXCHECK
147/* strcasecmp_l() does not work with multibyte strings:
148 POSIX says that it operates on "strings", and "string" in POSIX is defined
149 as a sequence of bytes, not of characters. */
150# undef strcasecmp_l
151# if HAVE_RAW_DECL_STRCASECMP_L
152_GL_WARN_ON_USE (strcasecmp_l, "strcasecmp_l cannot work correctly on "
153 "character strings in multibyte locales and is unportable - "
154 "use gnulib module strcasecmp_l for portability");
155# endif
156#endif
157
158#if @GNULIB_STRNCASECMP@
98/* Compare no more than N bytes of strings S1 and S2, ignoring case, 159/* Compare no more than N bytes of strings S1 and S2, ignoring case,
99 returning less than, equal to or greater than zero if S1 is 160 returning less than, equal to or greater than zero if S1 is
100 lexicographically less than, equal to or greater than S2. 161 lexicographically less than, equal to or greater than S2.
101 Note: This function cannot work correctly in multibyte locales. */ 162 Note: This function cannot work correctly in multibyte locales. */
102#if ! @HAVE_DECL_STRNCASECMP@ 163# if @REPLACE_STRNCASECMP@
103extern int strncasecmp (char const *s1, char const *s2, size_t n) 164# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
104 _GL_ARG_NONNULL ((1, 2)); 165# undef strncasecmp
105#endif 166# define strncasecmp rpl_strncasecmp
106#if defined GNULIB_POSIXCHECK 167# endif
168_GL_FUNCDECL_RPL (strncasecmp, int, (const char *, const char *, size_t),
169 _GL_ARG_NONNULL ((1, 2)));
170_GL_CXXALIAS_RPL (strncasecmp, int, (const char *, const char *, size_t));
171# else
172# if !@HAVE_DECL_STRNCASECMP@
173_GL_FUNCDECL_SYS (strncasecmp, int, (const char *, const char *, size_t),
174 _GL_ARG_NONNULL ((1, 2)));
175# endif
176_GL_CXXALIAS_SYS (strncasecmp, int, (const char *, const char *, size_t));
177# endif
178# if __GLIBC__ >= 2
179_GL_CXXALIASWARN (strncasecmp);
180# endif
181#elif defined GNULIB_POSIXCHECK
107/* strncasecmp() does not work with multibyte strings: 182/* strncasecmp() does not work with multibyte strings:
108 POSIX says that it operates on "strings", and "string" in POSIX is defined 183 POSIX says that it operates on "strings", and "string" in POSIX is defined
109 as a sequence of bytes, not of characters. */ 184 as a sequence of bytes, not of characters. */
110# undef strncasecmp 185# undef strncasecmp
111# if HAVE_RAW_DECL_STRNCASECMP 186# if HAVE_RAW_DECL_STRNCASECMP
112_GL_WARN_ON_USE (strncasecmp, "strncasecmp cannot work correctly on character " 187_GL_WARN_ON_USE (strncasecmp, "strncasecmp cannot work correctly on character "
113 "strings in multibyte locales - " 188 "strings in multibyte locales and is unportable - "
114 "use mbsncasecmp or mbspcasecmp if you care about " 189 "use mbsncasecmp or mbspcasecmp if you care about "
115 "internationalization, or use c_strncasecmp , " 190 "internationalization, or use c_strncasecmp "
116 "gnulib module c-strcase) if you want a locale " 191 "(gnulib module c-strncasecmp) if you want a locale "
117 "independent function"); 192 "independent function");
118# endif 193# endif
119#endif 194#endif
120 195
196#if @GNULIB_STRNCASECMP_L@
197# if @REPLACE_STRNCASECMP_L@
198# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
199# undef strncasecmp_l
200# define strncasecmp_l rpl_strncasecmp_l
201# endif
202_GL_FUNCDECL_RPL (strncasecmp_l, int,
203 (const char *s1, const char *s2, size_t n, locale_t locale),
204 _GL_ARG_NONNULL ((1, 2, 4)));
205_GL_CXXALIAS_RPL (strncasecmp_l, int,
206 (const char *s1, const char *s2, size_t n, locale_t locale));
207# else
208# if !@HAVE_STRNCASECMP_L@
209_GL_FUNCDECL_SYS (strncasecmp_l, int,
210 (const char *s1, const char *s2, size_t n, locale_t locale),
211 _GL_ARG_NONNULL ((1, 2, 4)));
212# endif
213_GL_CXXALIAS_SYS (strncasecmp_l, int,
214 (const char *s1, const char *s2, size_t n, locale_t locale));
215# endif
216# if __GLIBC__ >= 2
217_GL_CXXALIASWARN (strncasecmp_l);
218# endif
219#elif defined GNULIB_POSIXCHECK
220/* strncasecmp_l() does not work with multibyte strings:
221 POSIX says that it operates on "strings", and "string" in POSIX is defined
222 as a sequence of bytes, not of characters. */
223# undef strncasecmp_l
224# if HAVE_RAW_DECL_STRNCASECMP_L
225_GL_WARN_ON_USE (strncasecmp_l, "strncasecmp_l cannot work correctly on "
226 "character strings in multibyte locales and is unportable - "
227 "use gnulib module strncasecmp_l for portability");
228# endif
229#endif
230
121 231
122#ifdef __cplusplus 232#ifdef __cplusplus
123} 233}
diff --git a/gl/stripslash.c b/gl/stripslash.c
index c127ce7e..d5b07bca 100644
--- a/gl/stripslash.c
+++ b/gl/stripslash.c
@@ -1,6 +1,6 @@
1/* stripslash.c -- remove redundant trailing slashes from a file name 1/* stripslash.c -- remove redundant trailing slashes from a file name
2 2
3 Copyright (C) 1990, 2001, 2003-2006, 2009-2024 Free Software Foundation, 3 Copyright (C) 1990, 2001, 2003-2006, 2009-2025 Free Software Foundation,
4 Inc. 4 Inc.
5 5
6 This file is free software: you can redistribute it and/or modify 6 This file is free software: you can redistribute it and/or modify
diff --git a/gl/strncasecmp.c b/gl/strncasecmp.c
index c79161f3..7d7c5b7f 100644
--- a/gl/strncasecmp.c
+++ b/gl/strncasecmp.c
@@ -1,5 +1,5 @@
1/* strncasecmp.c -- case insensitive string comparator 1/* Case-insensitive string comparison function for unibyte locales.
2 Copyright (C) 1998-1999, 2005-2007, 2009-2024 Free Software Foundation, Inc. 2 Copyright (C) 1998-1999, 2005-2007, 2009-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -17,7 +17,7 @@
17#include <config.h> 17#include <config.h>
18 18
19/* Specification. */ 19/* Specification. */
20#include <string.h> 20#include <strings.h>
21 21
22#include <ctype.h> 22#include <ctype.h>
23#include <limits.h> 23#include <limits.h>
diff --git a/gl/strncpy.c b/gl/strncpy.c
new file mode 100644
index 00000000..1b680046
--- /dev/null
+++ b/gl/strncpy.c
@@ -0,0 +1,38 @@
1/* Copy a size-bounded string.
2 Copyright (C) 1999, 2011-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation, either version 3 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17/* Written by Bruno Haible <bruno@clisp.org>, 1999. */
18
19#include <config.h>
20
21/* Specification. */
22#include <string.h>
23
24char *
25strncpy (char *dest, const char *src, size_t n)
26{
27 char *destptr = dest;
28
29 for (; n > 0 && (*destptr = *src) != '\0'; src++, destptr++, n--)
30 ;
31
32 /* This behavior is rarely useful, but it is specified by the ISO C
33 standard. */
34 for (; n > 0; n--)
35 *destptr++ = '\0';
36
37 return dest;
38}
diff --git a/gl/strsep.c b/gl/strsep.c
index eefd85e2..5a489d11 100644
--- a/gl/strsep.c
+++ b/gl/strsep.c
@@ -1,4 +1,4 @@
1/* Copyright (C) 2004, 2007, 2009-2024 Free Software Foundation, Inc. 1/* Copyright (C) 2004, 2007, 2009-2025 Free Software Foundation, Inc.
2 2
3 Written by Yoann Vandoorselaere <yoann@prelude-ids.org>. 3 Written by Yoann Vandoorselaere <yoann@prelude-ids.org>.
4 4
diff --git a/gl/strstr.c b/gl/strstr.c
index 7ea28603..d6953f90 100644
--- a/gl/strstr.c
+++ b/gl/strstr.c
@@ -1,4 +1,4 @@
1/* Copyright (C) 1991-1994, 1996-1998, 2000, 2004, 2007-2024 Free Software 1/* Copyright (C) 1991-1994, 1996-1998, 2000, 2004, 2007-2025 Free Software
2 Foundation, Inc. 2 Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 4
diff --git a/gl/sys-limits.h b/gl/sys-limits.h
index d2f29d80..a556dfeb 100644
--- a/gl/sys-limits.h
+++ b/gl/sys-limits.h
@@ -1,6 +1,6 @@
1/* System call limits 1/* System call limits
2 2
3 Copyright 2018-2024 Free Software Foundation, Inc. 3 Copyright 2018-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/sys_socket.c b/gl/sys_socket.c
index 672d3aac..efd36610 100644
--- a/gl/sys_socket.c
+++ b/gl/sys_socket.c
@@ -1,6 +1,6 @@
1/* Inline functions for <sys/socket.h>. 1/* Inline functions for <sys/socket.h>.
2 2
3 Copyright (C) 2012-2024 Free Software Foundation, Inc. 3 Copyright (C) 2012-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -15,8 +15,8 @@
15 You should have received a copy of the GNU Lesser General Public License 15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 17
18#define _GL_SYS_SOCKET_INLINE _GL_EXTERN_INLINE
18#include <config.h> 19#include <config.h>
19 20
20#define _GL_SYS_SOCKET_INLINE _GL_EXTERN_INLINE
21#include <sys/socket.h> 21#include <sys/socket.h>
22typedef int dummy; 22typedef int dummy;
diff --git a/gl/sys_socket.in.h b/gl/sys_socket.in.h
index 13833c0f..8632c66d 100644
--- a/gl/sys_socket.in.h
+++ b/gl/sys_socket.in.h
@@ -1,6 +1,6 @@
1/* Provide a sys/socket header file for systems lacking it (read: MinGW) 1/* Provide a sys/socket header file for systems lacking it (read: MinGW)
2 and for systems where it is incomplete. 2 and for systems where it is incomplete.
3 Copyright (C) 2005-2024 Free Software Foundation, Inc. 3 Copyright (C) 2005-2025 Free Software Foundation, Inc.
4 Written by Simon Josefsson. 4 Written by Simon Josefsson.
5 5
6 This file is free software: you can redistribute it and/or modify 6 This file is free software: you can redistribute it and/or modify
@@ -27,7 +27,7 @@
27#endif 27#endif
28@PRAGMA_COLUMNS@ 28@PRAGMA_COLUMNS@
29 29
30#if defined _GL_ALREADY_INCLUDING_SYS_SOCKET_H 30#if defined _@GUARD_PREFIX@_ALREADY_INCLUDING_SYS_SOCKET_H
31/* Special invocation convention: 31/* Special invocation convention:
32 - On Cygwin 1.5.x we have a sequence of nested includes 32 - On Cygwin 1.5.x we have a sequence of nested includes
33 <sys/socket.h> -> <cygwin/socket.h> -> <asm/socket.h> -> <cygwin/if.h>, 33 <sys/socket.h> -> <cygwin/socket.h> -> <asm/socket.h> -> <cygwin/if.h>,
@@ -43,7 +43,7 @@
43 43
44#if @HAVE_SYS_SOCKET_H@ 44#if @HAVE_SYS_SOCKET_H@
45 45
46# define _GL_ALREADY_INCLUDING_SYS_SOCKET_H 46# define _@GUARD_PREFIX@_ALREADY_INCLUDING_SYS_SOCKET_H
47 47
48/* On many platforms, <sys/socket.h> assumes prior inclusion of 48/* On many platforms, <sys/socket.h> assumes prior inclusion of
49 <sys/types.h>. */ 49 <sys/types.h>. */
@@ -56,7 +56,7 @@
56/* The include_next requires a split double-inclusion guard. */ 56/* The include_next requires a split double-inclusion guard. */
57# @INCLUDE_NEXT@ @NEXT_SYS_SOCKET_H@ 57# @INCLUDE_NEXT@ @NEXT_SYS_SOCKET_H@
58 58
59# undef _GL_ALREADY_INCLUDING_SYS_SOCKET_H 59# undef _@GUARD_PREFIX@_ALREADY_INCLUDING_SYS_SOCKET_H
60 60
61#endif 61#endif
62 62
@@ -202,6 +202,7 @@ struct sockaddr_storage
202 202
203/* Rudimentary 'struct msghdr'; this works as long as you don't try to 203/* Rudimentary 'struct msghdr'; this works as long as you don't try to
204 access msg_control or msg_controllen. */ 204 access msg_control or msg_controllen. */
205# if !defined GNULIB_defined_struct_msghdr
205struct msghdr { 206struct msghdr {
206 void *msg_name; 207 void *msg_name;
207 socklen_t msg_namelen; 208 socklen_t msg_namelen;
@@ -209,6 +210,8 @@ struct msghdr {
209 int msg_iovlen; 210 int msg_iovlen;
210 int msg_flags; 211 int msg_flags;
211}; 212};
213# define GNULIB_defined_struct_msghdr 1
214# endif
212 215
213#endif 216#endif
214 217
@@ -289,15 +292,17 @@ rpl_fd_isset (SOCKET fd, fd_set * set)
289# undef socket 292# undef socket
290# define socket rpl_socket 293# define socket rpl_socket
291# endif 294# endif
292_GL_FUNCDECL_RPL (socket, int, (int domain, int type, int protocol)); 295_GL_FUNCDECL_RPL (socket, int, (int domain, int type, int protocol), );
293_GL_CXXALIAS_RPL (socket, int, (int domain, int type, int protocol)); 296_GL_CXXALIAS_RPL (socket, int, (int domain, int type, int protocol));
294# else 297# else
295_GL_CXXALIAS_SYS (socket, int, (int domain, int type, int protocol)); 298_GL_CXXALIAS_SYS (socket, int, (int domain, int type, int protocol));
296# endif 299# endif
297_GL_CXXALIASWARN (socket); 300_GL_CXXALIASWARN (socket);
298#elif @HAVE_WINSOCK2_H@ 301#elif @HAVE_WINSOCK2_H@
299# undef socket 302# if !GNULIB_SOCKET
300# define socket socket_used_without_requesting_gnulib_module_socket 303# undef socket
304# define socket socket_used_without_requesting_gnulib_module_socket
305# endif
301#elif defined GNULIB_POSIXCHECK 306#elif defined GNULIB_POSIXCHECK
302# undef socket 307# undef socket
303# if HAVE_RAW_DECL_SOCKET 308# if HAVE_RAW_DECL_SOCKET
@@ -313,7 +318,7 @@ _GL_WARN_ON_USE (socket, "socket is not always POSIX compliant - "
313# define connect rpl_connect 318# define connect rpl_connect
314# endif 319# endif
315_GL_FUNCDECL_RPL (connect, int, 320_GL_FUNCDECL_RPL (connect, int,
316 (int fd, const struct sockaddr *addr, socklen_t addrlen) 321 (int fd, const struct sockaddr *addr, socklen_t addrlen),
317 _GL_ARG_NONNULL ((2))); 322 _GL_ARG_NONNULL ((2)));
318_GL_CXXALIAS_RPL (connect, int, 323_GL_CXXALIAS_RPL (connect, int,
319 (int fd, const struct sockaddr *addr, socklen_t addrlen)); 324 (int fd, const struct sockaddr *addr, socklen_t addrlen));
@@ -326,8 +331,10 @@ _GL_CXXALIAS_SYS_CAST (connect, int,
326# endif 331# endif
327_GL_CXXALIASWARN (connect); 332_GL_CXXALIASWARN (connect);
328#elif @HAVE_WINSOCK2_H@ 333#elif @HAVE_WINSOCK2_H@
329# undef connect 334# if !GNULIB_CONNECT
330# define connect socket_used_without_requesting_gnulib_module_connect 335# undef connect
336# define connect connect_used_without_requesting_gnulib_module_connect
337# endif
331#elif defined GNULIB_POSIXCHECK 338#elif defined GNULIB_POSIXCHECK
332# undef connect 339# undef connect
333# if HAVE_RAW_DECL_CONNECT 340# if HAVE_RAW_DECL_CONNECT
@@ -345,7 +352,7 @@ _GL_WARN_ON_USE (connect, "connect is not always POSIX compliant - "
345_GL_FUNCDECL_RPL (accept, int, 352_GL_FUNCDECL_RPL (accept, int,
346 (int fd, 353 (int fd,
347 struct sockaddr *restrict addr, 354 struct sockaddr *restrict addr,
348 socklen_t *restrict addrlen)); 355 socklen_t *restrict addrlen), );
349_GL_CXXALIAS_RPL (accept, int, 356_GL_CXXALIAS_RPL (accept, int,
350 (int fd, 357 (int fd,
351 struct sockaddr *restrict addr, 358 struct sockaddr *restrict addr,
@@ -362,8 +369,10 @@ _GL_CXXALIAS_SYS_CAST (accept, int,
362_GL_CXXALIASWARN (accept); 369_GL_CXXALIASWARN (accept);
363# endif 370# endif
364#elif @HAVE_WINSOCK2_H@ 371#elif @HAVE_WINSOCK2_H@
365# undef accept 372# if !GNULIB_ACCEPT
366# define accept accept_used_without_requesting_gnulib_module_accept 373# undef accept
374# define accept accept_used_without_requesting_gnulib_module_accept
375# endif
367#elif defined GNULIB_POSIXCHECK 376#elif defined GNULIB_POSIXCHECK
368# undef accept 377# undef accept
369# if HAVE_RAW_DECL_ACCEPT 378# if HAVE_RAW_DECL_ACCEPT
@@ -379,7 +388,7 @@ _GL_WARN_ON_USE (accept, "accept is not always POSIX compliant - "
379# define bind rpl_bind 388# define bind rpl_bind
380# endif 389# endif
381_GL_FUNCDECL_RPL (bind, int, 390_GL_FUNCDECL_RPL (bind, int,
382 (int fd, const struct sockaddr *addr, socklen_t addrlen) 391 (int fd, const struct sockaddr *addr, socklen_t addrlen),
383 _GL_ARG_NONNULL ((2))); 392 _GL_ARG_NONNULL ((2)));
384_GL_CXXALIAS_RPL (bind, int, 393_GL_CXXALIAS_RPL (bind, int,
385 (int fd, const struct sockaddr *addr, socklen_t addrlen)); 394 (int fd, const struct sockaddr *addr, socklen_t addrlen));
@@ -392,8 +401,10 @@ _GL_CXXALIAS_SYS_CAST (bind, int,
392# endif 401# endif
393_GL_CXXALIASWARN (bind); 402_GL_CXXALIASWARN (bind);
394#elif @HAVE_WINSOCK2_H@ 403#elif @HAVE_WINSOCK2_H@
395# undef bind 404# if !GNULIB_BIND
396# define bind bind_used_without_requesting_gnulib_module_bind 405# undef bind
406# define bind bind_used_without_requesting_gnulib_module_bind
407# endif
397#elif defined GNULIB_POSIXCHECK 408#elif defined GNULIB_POSIXCHECK
398# undef bind 409# undef bind
399# if HAVE_RAW_DECL_BIND 410# if HAVE_RAW_DECL_BIND
@@ -410,7 +421,7 @@ _GL_WARN_ON_USE (bind, "bind is not always POSIX compliant - "
410# endif 421# endif
411_GL_FUNCDECL_RPL (getpeername, int, 422_GL_FUNCDECL_RPL (getpeername, int,
412 (int fd, struct sockaddr *restrict addr, 423 (int fd, struct sockaddr *restrict addr,
413 socklen_t *restrict addrlen) 424 socklen_t *restrict addrlen),
414 _GL_ARG_NONNULL ((2, 3))); 425 _GL_ARG_NONNULL ((2, 3)));
415_GL_CXXALIAS_RPL (getpeername, int, 426_GL_CXXALIAS_RPL (getpeername, int,
416 (int fd, struct sockaddr *restrict addr, 427 (int fd, struct sockaddr *restrict addr,
@@ -426,8 +437,10 @@ _GL_CXXALIAS_SYS_CAST (getpeername, int,
426_GL_CXXALIASWARN (getpeername); 437_GL_CXXALIASWARN (getpeername);
427# endif 438# endif
428#elif @HAVE_WINSOCK2_H@ 439#elif @HAVE_WINSOCK2_H@
429# undef getpeername 440# if !GNULIB_GETPEERNAME
430# define getpeername getpeername_used_without_requesting_gnulib_module_getpeername 441# undef getpeername
442# define getpeername getpeername_used_without_requesting_gnulib_module_getpeername
443# endif
431#elif defined GNULIB_POSIXCHECK 444#elif defined GNULIB_POSIXCHECK
432# undef getpeername 445# undef getpeername
433# if HAVE_RAW_DECL_GETPEERNAME 446# if HAVE_RAW_DECL_GETPEERNAME
@@ -444,7 +457,7 @@ _GL_WARN_ON_USE (getpeername, "getpeername is not always POSIX compliant - "
444# endif 457# endif
445_GL_FUNCDECL_RPL (getsockname, int, 458_GL_FUNCDECL_RPL (getsockname, int,
446 (int fd, struct sockaddr *restrict addr, 459 (int fd, struct sockaddr *restrict addr,
447 socklen_t *restrict addrlen) 460 socklen_t *restrict addrlen),
448 _GL_ARG_NONNULL ((2, 3))); 461 _GL_ARG_NONNULL ((2, 3)));
449_GL_CXXALIAS_RPL (getsockname, int, 462_GL_CXXALIAS_RPL (getsockname, int,
450 (int fd, struct sockaddr *restrict addr, 463 (int fd, struct sockaddr *restrict addr,
@@ -460,8 +473,10 @@ _GL_CXXALIAS_SYS_CAST (getsockname, int,
460_GL_CXXALIASWARN (getsockname); 473_GL_CXXALIASWARN (getsockname);
461# endif 474# endif
462#elif @HAVE_WINSOCK2_H@ 475#elif @HAVE_WINSOCK2_H@
463# undef getsockname 476# if !GNULIB_GETSOCKNAME
464# define getsockname getsockname_used_without_requesting_gnulib_module_getsockname 477# undef getsockname
478# define getsockname getsockname_used_without_requesting_gnulib_module_getsockname
479# endif
465#elif defined GNULIB_POSIXCHECK 480#elif defined GNULIB_POSIXCHECK
466# undef getsockname 481# undef getsockname
467# if HAVE_RAW_DECL_GETSOCKNAME 482# if HAVE_RAW_DECL_GETSOCKNAME
@@ -478,7 +493,7 @@ _GL_WARN_ON_USE (getsockname, "getsockname is not always POSIX compliant - "
478# endif 493# endif
479_GL_FUNCDECL_RPL (getsockopt, int, 494_GL_FUNCDECL_RPL (getsockopt, int,
480 (int fd, int level, int optname, 495 (int fd, int level, int optname,
481 void *restrict optval, socklen_t *restrict optlen) 496 void *restrict optval, socklen_t *restrict optlen),
482 _GL_ARG_NONNULL ((4, 5))); 497 _GL_ARG_NONNULL ((4, 5)));
483_GL_CXXALIAS_RPL (getsockopt, int, 498_GL_CXXALIAS_RPL (getsockopt, int,
484 (int fd, int level, int optname, 499 (int fd, int level, int optname,
@@ -492,8 +507,10 @@ _GL_CXXALIAS_SYS_CAST (getsockopt, int,
492# endif 507# endif
493_GL_CXXALIASWARN (getsockopt); 508_GL_CXXALIASWARN (getsockopt);
494#elif @HAVE_WINSOCK2_H@ 509#elif @HAVE_WINSOCK2_H@
495# undef getsockopt 510# if !GNULIB_GETSOCKOPT
496# define getsockopt getsockopt_used_without_requesting_gnulib_module_getsockopt 511# undef getsockopt
512# define getsockopt getsockopt_used_without_requesting_gnulib_module_getsockopt
513# endif
497#elif defined GNULIB_POSIXCHECK 514#elif defined GNULIB_POSIXCHECK
498# undef getsockopt 515# undef getsockopt
499# if HAVE_RAW_DECL_GETSOCKOPT 516# if HAVE_RAW_DECL_GETSOCKOPT
@@ -508,15 +525,17 @@ _GL_WARN_ON_USE (getsockopt, "getsockopt is not always POSIX compliant - "
508# undef listen 525# undef listen
509# define listen rpl_listen 526# define listen rpl_listen
510# endif 527# endif
511_GL_FUNCDECL_RPL (listen, int, (int fd, int backlog)); 528_GL_FUNCDECL_RPL (listen, int, (int fd, int backlog), );
512_GL_CXXALIAS_RPL (listen, int, (int fd, int backlog)); 529_GL_CXXALIAS_RPL (listen, int, (int fd, int backlog));
513# else 530# else
514_GL_CXXALIAS_SYS (listen, int, (int fd, int backlog)); 531_GL_CXXALIAS_SYS (listen, int, (int fd, int backlog));
515# endif 532# endif
516_GL_CXXALIASWARN (listen); 533_GL_CXXALIASWARN (listen);
517#elif @HAVE_WINSOCK2_H@ 534#elif @HAVE_WINSOCK2_H@
518# undef listen 535# if !GNULIB_LISTEN
519# define listen listen_used_without_requesting_gnulib_module_listen 536# undef listen
537# define listen listen_used_without_requesting_gnulib_module_listen
538# endif
520#elif defined GNULIB_POSIXCHECK 539#elif defined GNULIB_POSIXCHECK
521# undef listen 540# undef listen
522# if HAVE_RAW_DECL_LISTEN 541# if HAVE_RAW_DECL_LISTEN
@@ -531,7 +550,7 @@ _GL_WARN_ON_USE (listen, "listen is not always POSIX compliant - "
531# undef recv 550# undef recv
532# define recv rpl_recv 551# define recv rpl_recv
533# endif 552# endif
534_GL_FUNCDECL_RPL (recv, ssize_t, (int fd, void *buf, size_t len, int flags) 553_GL_FUNCDECL_RPL (recv, ssize_t, (int fd, void *buf, size_t len, int flags),
535 _GL_ARG_NONNULL ((2))); 554 _GL_ARG_NONNULL ((2)));
536_GL_CXXALIAS_RPL (recv, ssize_t, (int fd, void *buf, size_t len, int flags)); 555_GL_CXXALIAS_RPL (recv, ssize_t, (int fd, void *buf, size_t len, int flags));
537# else 556# else
@@ -542,8 +561,10 @@ _GL_CXXALIAS_SYS_CAST (recv, ssize_t, (int fd, void *buf, size_t len, int flags)
542# endif 561# endif
543_GL_CXXALIASWARN (recv); 562_GL_CXXALIASWARN (recv);
544#elif @HAVE_WINSOCK2_H@ 563#elif @HAVE_WINSOCK2_H@
545# undef recv 564# if !GNULIB_RECV
546# define recv recv_used_without_requesting_gnulib_module_recv 565# undef recv
566# define recv recv_used_without_requesting_gnulib_module_recv
567# endif
547#elif defined GNULIB_POSIXCHECK 568#elif defined GNULIB_POSIXCHECK
548# undef recv 569# undef recv
549# if HAVE_RAW_DECL_RECV 570# if HAVE_RAW_DECL_RECV
@@ -559,7 +580,7 @@ _GL_WARN_ON_USE (recv, "recv is not always POSIX compliant - "
559# define send rpl_send 580# define send rpl_send
560# endif 581# endif
561_GL_FUNCDECL_RPL (send, ssize_t, 582_GL_FUNCDECL_RPL (send, ssize_t,
562 (int fd, const void *buf, size_t len, int flags) 583 (int fd, const void *buf, size_t len, int flags),
563 _GL_ARG_NONNULL ((2))); 584 _GL_ARG_NONNULL ((2)));
564_GL_CXXALIAS_RPL (send, ssize_t, 585_GL_CXXALIAS_RPL (send, ssize_t,
565 (int fd, const void *buf, size_t len, int flags)); 586 (int fd, const void *buf, size_t len, int flags));
@@ -572,8 +593,10 @@ _GL_CXXALIAS_SYS_CAST (send, ssize_t,
572# endif 593# endif
573_GL_CXXALIASWARN (send); 594_GL_CXXALIASWARN (send);
574#elif @HAVE_WINSOCK2_H@ 595#elif @HAVE_WINSOCK2_H@
575# undef send 596# if !GNULIB_SEND
576# define send send_used_without_requesting_gnulib_module_send 597# undef send
598# define send send_used_without_requesting_gnulib_module_send
599# endif
577#elif defined GNULIB_POSIXCHECK 600#elif defined GNULIB_POSIXCHECK
578# undef send 601# undef send
579# if HAVE_RAW_DECL_SEND 602# if HAVE_RAW_DECL_SEND
@@ -591,7 +614,7 @@ _GL_WARN_ON_USE (send, "send is not always POSIX compliant - "
591_GL_FUNCDECL_RPL (recvfrom, ssize_t, 614_GL_FUNCDECL_RPL (recvfrom, ssize_t,
592 (int fd, void *restrict buf, size_t len, int flags, 615 (int fd, void *restrict buf, size_t len, int flags,
593 struct sockaddr *restrict from, 616 struct sockaddr *restrict from,
594 socklen_t *restrict fromlen) 617 socklen_t *restrict fromlen),
595 _GL_ARG_NONNULL ((2))); 618 _GL_ARG_NONNULL ((2)));
596_GL_CXXALIAS_RPL (recvfrom, ssize_t, 619_GL_CXXALIAS_RPL (recvfrom, ssize_t,
597 (int fd, void *restrict buf, size_t len, int flags, 620 (int fd, void *restrict buf, size_t len, int flags,
@@ -609,8 +632,10 @@ _GL_CXXALIAS_SYS_CAST (recvfrom, ssize_t,
609_GL_CXXALIASWARN (recvfrom); 632_GL_CXXALIASWARN (recvfrom);
610# endif 633# endif
611#elif @HAVE_WINSOCK2_H@ 634#elif @HAVE_WINSOCK2_H@
612# undef recvfrom 635# if !GNULIB_RECVFROM
613# define recvfrom recvfrom_used_without_requesting_gnulib_module_recvfrom 636# undef recvfrom
637# define recvfrom recvfrom_used_without_requesting_gnulib_module_recvfrom
638# endif
614#elif defined GNULIB_POSIXCHECK 639#elif defined GNULIB_POSIXCHECK
615# undef recvfrom 640# undef recvfrom
616# if HAVE_RAW_DECL_RECVFROM 641# if HAVE_RAW_DECL_RECVFROM
@@ -627,7 +652,7 @@ _GL_WARN_ON_USE (recvfrom, "recvfrom is not always POSIX compliant - "
627# endif 652# endif
628_GL_FUNCDECL_RPL (sendto, ssize_t, 653_GL_FUNCDECL_RPL (sendto, ssize_t,
629 (int fd, const void *buf, size_t len, int flags, 654 (int fd, const void *buf, size_t len, int flags,
630 const struct sockaddr *to, socklen_t tolen) 655 const struct sockaddr *to, socklen_t tolen),
631 _GL_ARG_NONNULL ((2))); 656 _GL_ARG_NONNULL ((2)));
632_GL_CXXALIAS_RPL (sendto, ssize_t, 657_GL_CXXALIAS_RPL (sendto, ssize_t,
633 (int fd, const void *buf, size_t len, int flags, 658 (int fd, const void *buf, size_t len, int flags,
@@ -641,8 +666,10 @@ _GL_CXXALIAS_SYS_CAST (sendto, ssize_t,
641# endif 666# endif
642_GL_CXXALIASWARN (sendto); 667_GL_CXXALIASWARN (sendto);
643#elif @HAVE_WINSOCK2_H@ 668#elif @HAVE_WINSOCK2_H@
644# undef sendto 669# if !GNULIB_SENDTO
645# define sendto sendto_used_without_requesting_gnulib_module_sendto 670# undef sendto
671# define sendto sendto_used_without_requesting_gnulib_module_sendto
672# endif
646#elif defined GNULIB_POSIXCHECK 673#elif defined GNULIB_POSIXCHECK
647# undef sendto 674# undef sendto
648# if HAVE_RAW_DECL_SENDTO 675# if HAVE_RAW_DECL_SENDTO
@@ -658,7 +685,7 @@ _GL_WARN_ON_USE (sendto, "sendto is not always POSIX compliant - "
658# define setsockopt rpl_setsockopt 685# define setsockopt rpl_setsockopt
659# endif 686# endif
660_GL_FUNCDECL_RPL (setsockopt, int, (int fd, int level, int optname, 687_GL_FUNCDECL_RPL (setsockopt, int, (int fd, int level, int optname,
661 const void * optval, socklen_t optlen) 688 const void * optval, socklen_t optlen),
662 _GL_ARG_NONNULL ((4))); 689 _GL_ARG_NONNULL ((4)));
663_GL_CXXALIAS_RPL (setsockopt, int, (int fd, int level, int optname, 690_GL_CXXALIAS_RPL (setsockopt, int, (int fd, int level, int optname,
664 const void * optval, socklen_t optlen)); 691 const void * optval, socklen_t optlen));
@@ -671,8 +698,10 @@ _GL_CXXALIAS_SYS_CAST (setsockopt, int,
671# endif 698# endif
672_GL_CXXALIASWARN (setsockopt); 699_GL_CXXALIASWARN (setsockopt);
673#elif @HAVE_WINSOCK2_H@ 700#elif @HAVE_WINSOCK2_H@
674# undef setsockopt 701# if !GNULIB_SETSOCKOPT
675# define setsockopt setsockopt_used_without_requesting_gnulib_module_setsockopt 702# undef setsockopt
703# define setsockopt setsockopt_used_without_requesting_gnulib_module_setsockopt
704# endif
676#elif defined GNULIB_POSIXCHECK 705#elif defined GNULIB_POSIXCHECK
677# undef setsockopt 706# undef setsockopt
678# if HAVE_RAW_DECL_SETSOCKOPT 707# if HAVE_RAW_DECL_SETSOCKOPT
@@ -687,15 +716,17 @@ _GL_WARN_ON_USE (setsockopt, "setsockopt is not always POSIX compliant - "
687# undef shutdown 716# undef shutdown
688# define shutdown rpl_shutdown 717# define shutdown rpl_shutdown
689# endif 718# endif
690_GL_FUNCDECL_RPL (shutdown, int, (int fd, int how)); 719_GL_FUNCDECL_RPL (shutdown, int, (int fd, int how), );
691_GL_CXXALIAS_RPL (shutdown, int, (int fd, int how)); 720_GL_CXXALIAS_RPL (shutdown, int, (int fd, int how));
692# else 721# else
693_GL_CXXALIAS_SYS (shutdown, int, (int fd, int how)); 722_GL_CXXALIAS_SYS (shutdown, int, (int fd, int how));
694# endif 723# endif
695_GL_CXXALIASWARN (shutdown); 724_GL_CXXALIASWARN (shutdown);
696#elif @HAVE_WINSOCK2_H@ 725#elif @HAVE_WINSOCK2_H@
697# undef shutdown 726# if !GNULIB_SHUTDOWN
698# define shutdown shutdown_used_without_requesting_gnulib_module_shutdown 727# undef shutdown
728# define shutdown shutdown_used_without_requesting_gnulib_module_shutdown
729# endif
699#elif defined GNULIB_POSIXCHECK 730#elif defined GNULIB_POSIXCHECK
700# undef shutdown 731# undef shutdown
701# if HAVE_RAW_DECL_SHUTDOWN 732# if HAVE_RAW_DECL_SHUTDOWN
@@ -716,14 +747,14 @@ _GL_WARN_ON_USE (shutdown, "shutdown is not always POSIX compliant - "
716# endif 747# endif
717_GL_FUNCDECL_RPL (accept4, int, 748_GL_FUNCDECL_RPL (accept4, int,
718 (int sockfd, struct sockaddr *addr, socklen_t *addrlen, 749 (int sockfd, struct sockaddr *addr, socklen_t *addrlen,
719 int flags)); 750 int flags), );
720_GL_CXXALIAS_RPL (accept4, int, 751_GL_CXXALIAS_RPL (accept4, int,
721 (int sockfd, struct sockaddr *addr, socklen_t *addrlen, 752 (int sockfd, struct sockaddr *addr, socklen_t *addrlen,
722 int flags)); 753 int flags));
723# else 754# else
724_GL_FUNCDECL_SYS (accept4, int, 755_GL_FUNCDECL_SYS (accept4, int,
725 (int sockfd, struct sockaddr *addr, socklen_t *addrlen, 756 (int sockfd, struct sockaddr *addr, socklen_t *addrlen,
726 int flags)); 757 int flags), );
727_GL_CXXALIAS_SYS (accept4, int, 758_GL_CXXALIAS_SYS (accept4, int,
728 (int sockfd, struct sockaddr *addr, socklen_t *addrlen, 759 (int sockfd, struct sockaddr *addr, socklen_t *addrlen,
729 int flags)); 760 int flags));
diff --git a/gl/sys_stat.in.h b/gl/sys_stat.in.h
index bf08f335..c3c38fd6 100644
--- a/gl/sys_stat.in.h
+++ b/gl/sys_stat.in.h
@@ -1,5 +1,5 @@
1/* Provide a more complete sys/stat.h header file. 1/* Provide a more complete sys/stat.h header file.
2 Copyright (C) 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -55,7 +55,8 @@
55#ifndef _@GUARD_PREFIX@_SYS_STAT_H 55#ifndef _@GUARD_PREFIX@_SYS_STAT_H
56#define _@GUARD_PREFIX@_SYS_STAT_H 56#define _@GUARD_PREFIX@_SYS_STAT_H
57 57
58/* This file uses _GL_ATTRIBUTE_NOTHROW, GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */ 58/* This file uses _GL_ATTRIBUTE_NODISCARD, _GL_ATTRIBUTE_NOTHROW,
59 GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
59#if !_GL_CONFIG_H_INCLUDED 60#if !_GL_CONFIG_H_INCLUDED
60 #error "Please include config.h first." 61 #error "Please include config.h first."
61#endif 62#endif
@@ -65,7 +66,7 @@
65 */ 66 */
66#ifndef _GL_ATTRIBUTE_NOTHROW 67#ifndef _GL_ATTRIBUTE_NOTHROW
67# if defined __cplusplus 68# if defined __cplusplus
68# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major >= 4 69# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major__ >= 4
69# if __cplusplus >= 201103L 70# if __cplusplus >= 201103L
70# define _GL_ATTRIBUTE_NOTHROW noexcept (true) 71# define _GL_ATTRIBUTE_NOTHROW noexcept (true)
71# else 72# else
@@ -122,9 +123,11 @@
122# if @GNULIB_STAT@ 123# if @GNULIB_STAT@
123# define stat rpl_stat 124# define stat rpl_stat
124# else 125# else
125 /* Provoke a clear link error if stat() is used as a function and 126# if !GNULIB_STAT
126 module 'stat' is not in use. */ 127 /* Provoke a clear link error if stat() is used as a function and
127# define stat stat_used_without_requesting_gnulib_module_stat 128 module 'stat' is not in use. */
129# define stat stat_used_without_requesting_gnulib_module_stat
130# endif
128# endif 131# endif
129 132
130# if !GNULIB_defined_struct_stat 133# if !GNULIB_defined_struct_stat
@@ -433,7 +436,7 @@ struct stat
433# undef chmod 436# undef chmod
434# define chmod rpl_chmod 437# define chmod rpl_chmod
435# endif 438# endif
436_GL_FUNCDECL_RPL (chmod, int, (const char *filename, mode_t mode) 439_GL_FUNCDECL_RPL (chmod, int, (const char *filename, mode_t mode),
437 _GL_ARG_NONNULL ((1))); 440 _GL_ARG_NONNULL ((1)));
438_GL_CXXALIAS_RPL (chmod, int, (const char *filename, mode_t mode)); 441_GL_CXXALIAS_RPL (chmod, int, (const char *filename, mode_t mode));
439# elif defined _WIN32 && !defined __CYGWIN__ 442# elif defined _WIN32 && !defined __CYGWIN__
@@ -478,15 +481,15 @@ _GL_CXXALIASWARN (chmod);
478# define fchmodat rpl_fchmodat 481# define fchmodat rpl_fchmodat
479# endif 482# endif
480_GL_FUNCDECL_RPL (fchmodat, int, 483_GL_FUNCDECL_RPL (fchmodat, int,
481 (int fd, char const *file, mode_t mode, int flag) 484 (int fd, char const *file, mode_t mode, int flag),
482 _GL_ARG_NONNULL ((2))); 485 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD);
483_GL_CXXALIAS_RPL (fchmodat, int, 486_GL_CXXALIAS_RPL (fchmodat, int,
484 (int fd, char const *file, mode_t mode, int flag)); 487 (int fd, char const *file, mode_t mode, int flag));
485# else 488# else
486# if !@HAVE_FCHMODAT@ 489# if !@HAVE_FCHMODAT@
487_GL_FUNCDECL_SYS (fchmodat, int, 490_GL_FUNCDECL_SYS (fchmodat, int,
488 (int fd, char const *file, mode_t mode, int flag) 491 (int fd, char const *file, mode_t mode, int flag),
489 _GL_ARG_NONNULL ((2))); 492 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD);
490# endif 493# endif
491_GL_CXXALIAS_SYS (fchmodat, int, 494_GL_CXXALIAS_SYS (fchmodat, int,
492 (int fd, char const *file, mode_t mode, int flag)); 495 (int fd, char const *file, mode_t mode, int flag));
@@ -507,7 +510,8 @@ _GL_WARN_ON_USE (fchmodat, "fchmodat is not portable - "
507# undef fstat 510# undef fstat
508# define fstat rpl_fstat 511# define fstat rpl_fstat
509# endif 512# endif
510_GL_FUNCDECL_RPL (fstat, int, (int fd, struct stat *buf) _GL_ARG_NONNULL ((2))); 513_GL_FUNCDECL_RPL (fstat, int, (int fd, struct stat *buf),
514 _GL_ARG_NONNULL ((2)));
511_GL_CXXALIAS_RPL (fstat, int, (int fd, struct stat *buf)); 515_GL_CXXALIAS_RPL (fstat, int, (int fd, struct stat *buf));
512# else 516# else
513_GL_CXXALIAS_SYS (fstat, int, (int fd, struct stat *buf)); 517_GL_CXXALIAS_SYS (fstat, int, (int fd, struct stat *buf));
@@ -516,8 +520,10 @@ _GL_CXXALIAS_SYS (fstat, int, (int fd, struct stat *buf));
516_GL_CXXALIASWARN (fstat); 520_GL_CXXALIASWARN (fstat);
517# endif 521# endif
518#elif @GNULIB_OVERRIDES_STRUCT_STAT@ 522#elif @GNULIB_OVERRIDES_STRUCT_STAT@
519# undef fstat 523# if !GNULIB_FSTAT
520# define fstat fstat_used_without_requesting_gnulib_module_fstat 524# undef fstat
525# define fstat fstat_used_without_requesting_gnulib_module_fstat
526# endif
521#elif @WINDOWS_64_BIT_ST_SIZE@ 527#elif @WINDOWS_64_BIT_ST_SIZE@
522/* Above, we define stat to _stati64. */ 528/* Above, we define stat to _stati64. */
523# define fstat _fstati64 529# define fstat _fstati64
@@ -538,7 +544,7 @@ _GL_WARN_ON_USE (fstat, "fstat has portability problems - "
538# endif 544# endif
539_GL_FUNCDECL_RPL (fstatat, int, 545_GL_FUNCDECL_RPL (fstatat, int,
540 (int fd, char const *restrict name, struct stat *restrict st, 546 (int fd, char const *restrict name, struct stat *restrict st,
541 int flags) 547 int flags),
542 _GL_ARG_NONNULL ((2, 3))); 548 _GL_ARG_NONNULL ((2, 3)));
543_GL_CXXALIAS_RPL (fstatat, int, 549_GL_CXXALIAS_RPL (fstatat, int,
544 (int fd, char const *restrict name, struct stat *restrict st, 550 (int fd, char const *restrict name, struct stat *restrict st,
@@ -547,7 +553,7 @@ _GL_CXXALIAS_RPL (fstatat, int,
547# if !@HAVE_FSTATAT@ 553# if !@HAVE_FSTATAT@
548_GL_FUNCDECL_SYS (fstatat, int, 554_GL_FUNCDECL_SYS (fstatat, int,
549 (int fd, char const *restrict name, struct stat *restrict st, 555 (int fd, char const *restrict name, struct stat *restrict st,
550 int flags) 556 int flags),
551 _GL_ARG_NONNULL ((2, 3))); 557 _GL_ARG_NONNULL ((2, 3)));
552# endif 558# endif
553_GL_CXXALIAS_SYS (fstatat, int, 559_GL_CXXALIAS_SYS (fstatat, int,
@@ -556,8 +562,10 @@ _GL_CXXALIAS_SYS (fstatat, int,
556# endif 562# endif
557_GL_CXXALIASWARN (fstatat); 563_GL_CXXALIASWARN (fstatat);
558#elif @GNULIB_OVERRIDES_STRUCT_STAT@ 564#elif @GNULIB_OVERRIDES_STRUCT_STAT@
559# undef fstatat 565# if !GNULIB_FSTATAT
560# define fstatat fstatat_used_without_requesting_gnulib_module_fstatat 566# undef fstatat
567# define fstatat fstatat_used_without_requesting_gnulib_module_fstatat
568# endif
561#elif defined GNULIB_POSIXCHECK 569#elif defined GNULIB_POSIXCHECK
562# undef fstatat 570# undef fstatat
563# if HAVE_RAW_DECL_FSTATAT 571# if HAVE_RAW_DECL_FSTATAT
@@ -577,11 +585,11 @@ _GL_WARN_ON_USE (fstatat, "fstatat is not portable - "
577# undef futimens 585# undef futimens
578# define futimens rpl_futimens 586# define futimens rpl_futimens
579# endif 587# endif
580_GL_FUNCDECL_RPL (futimens, int, (int fd, struct timespec const times[2])); 588_GL_FUNCDECL_RPL (futimens, int, (int fd, struct timespec const times[2]), );
581_GL_CXXALIAS_RPL (futimens, int, (int fd, struct timespec const times[2])); 589_GL_CXXALIAS_RPL (futimens, int, (int fd, struct timespec const times[2]));
582# else 590# else
583# if !@HAVE_FUTIMENS@ 591# if !@HAVE_FUTIMENS@
584_GL_FUNCDECL_SYS (futimens, int, (int fd, struct timespec const times[2])); 592_GL_FUNCDECL_SYS (futimens, int, (int fd, struct timespec const times[2]), );
585# endif 593# endif
586_GL_CXXALIAS_SYS (futimens, int, (int fd, struct timespec const times[2])); 594_GL_CXXALIAS_SYS (futimens, int, (int fd, struct timespec const times[2]));
587# endif 595# endif
@@ -600,9 +608,9 @@ _GL_WARN_ON_USE (futimens, "futimens is not portable - "
600#if @GNULIB_GETUMASK@ 608#if @GNULIB_GETUMASK@
601# if !@HAVE_GETUMASK@ 609# if !@HAVE_GETUMASK@
602# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2 610# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
603_GL_FUNCDECL_SYS (getumask, mode_t, (void) _GL_ATTRIBUTE_NOTHROW); 611_GL_FUNCDECL_SYS (getumask, mode_t, (void), ) _GL_ATTRIBUTE_NOTHROW;
604# else 612# else
605_GL_FUNCDECL_SYS (getumask, mode_t, (void)); 613_GL_FUNCDECL_SYS (getumask, mode_t, (void), );
606# endif 614# endif
607# endif 615# endif
608_GL_CXXALIAS_SYS (getumask, mode_t, (void)); 616_GL_CXXALIAS_SYS (getumask, mode_t, (void));
@@ -622,7 +630,7 @@ _GL_WARN_ON_USE (getumask, "getumask is not portable - "
622/* Change the mode of FILENAME to MODE, without dereferencing it if FILENAME 630/* Change the mode of FILENAME to MODE, without dereferencing it if FILENAME
623 denotes a symbolic link. */ 631 denotes a symbolic link. */
624# if !@HAVE_LCHMOD@ || defined __hpux 632# if !@HAVE_LCHMOD@ || defined __hpux
625_GL_FUNCDECL_SYS (lchmod, int, (const char *filename, mode_t mode) 633_GL_FUNCDECL_SYS (lchmod, int, (const char *filename, mode_t mode),
626 _GL_ARG_NONNULL ((1))); 634 _GL_ARG_NONNULL ((1)));
627# endif 635# endif
628_GL_CXXALIAS_SYS (lchmod, int, (const char *filename, mode_t mode)); 636_GL_CXXALIAS_SYS (lchmod, int, (const char *filename, mode_t mode));
@@ -642,7 +650,7 @@ _GL_WARN_ON_USE (lchmod, "lchmod is unportable - "
642# undef mkdir 650# undef mkdir
643# define mkdir rpl_mkdir 651# define mkdir rpl_mkdir
644# endif 652# endif
645_GL_FUNCDECL_RPL (mkdir, int, (char const *name, mode_t mode) 653_GL_FUNCDECL_RPL (mkdir, int, (char const *name, mode_t mode),
646 _GL_ARG_NONNULL ((1))); 654 _GL_ARG_NONNULL ((1)));
647_GL_CXXALIAS_RPL (mkdir, int, (char const *name, mode_t mode)); 655_GL_CXXALIAS_RPL (mkdir, int, (char const *name, mode_t mode));
648# elif defined _WIN32 && !defined __CYGWIN__ 656# elif defined _WIN32 && !defined __CYGWIN__
@@ -667,12 +675,6 @@ _GL_CXXALIAS_RPL (mkdir, int, (char const *name, mode_t mode));
667_GL_CXXALIAS_SYS (mkdir, int, (char const *name, mode_t mode)); 675_GL_CXXALIAS_SYS (mkdir, int, (char const *name, mode_t mode));
668# endif 676# endif
669_GL_CXXALIASWARN (mkdir); 677_GL_CXXALIASWARN (mkdir);
670#elif defined GNULIB_POSIXCHECK
671# undef mkdir
672# if HAVE_RAW_DECL_MKDIR
673_GL_WARN_ON_USE (mkdir, "mkdir does not always support two parameters - "
674 "use gnulib module mkdir for portability");
675# endif
676#elif @GNULIB_MDA_MKDIR@ 678#elif @GNULIB_MDA_MKDIR@
677/* On native Windows, map 'mkdir' to '_mkdir', so that -loldnames is not 679/* On native Windows, map 'mkdir' to '_mkdir', so that -loldnames is not
678 required. In C++ with GNULIB_NAMESPACE, avoid differences between 680 required. In C++ with GNULIB_NAMESPACE, avoid differences between
@@ -695,12 +697,18 @@ _GL_CXXALIAS_RPL (mkdir, int, (char const *name, mode_t mode));
695_GL_CXXALIAS_SYS (mkdir, int, (char const *name, mode_t mode)); 697_GL_CXXALIAS_SYS (mkdir, int, (char const *name, mode_t mode));
696# endif 698# endif
697_GL_CXXALIASWARN (mkdir); 699_GL_CXXALIASWARN (mkdir);
700#elif defined GNULIB_POSIXCHECK
701# undef mkdir
702# if HAVE_RAW_DECL_MKDIR
703_GL_WARN_ON_USE (mkdir, "mkdir does not always support two parameters - "
704 "use gnulib module mkdir for portability");
705# endif
698#endif 706#endif
699 707
700 708
701#if @GNULIB_MKDIRAT@ 709#if @GNULIB_MKDIRAT@
702# if !@HAVE_MKDIRAT@ 710# if !@HAVE_MKDIRAT@
703_GL_FUNCDECL_SYS (mkdirat, int, (int fd, char const *file, mode_t mode) 711_GL_FUNCDECL_SYS (mkdirat, int, (int fd, char const *file, mode_t mode),
704 _GL_ARG_NONNULL ((2))); 712 _GL_ARG_NONNULL ((2)));
705# endif 713# endif
706_GL_CXXALIAS_SYS (mkdirat, int, (int fd, char const *file, mode_t mode)); 714_GL_CXXALIAS_SYS (mkdirat, int, (int fd, char const *file, mode_t mode));
@@ -720,12 +728,12 @@ _GL_WARN_ON_USE (mkdirat, "mkdirat is not portable - "
720# undef mkfifo 728# undef mkfifo
721# define mkfifo rpl_mkfifo 729# define mkfifo rpl_mkfifo
722# endif 730# endif
723_GL_FUNCDECL_RPL (mkfifo, int, (char const *file, mode_t mode) 731_GL_FUNCDECL_RPL (mkfifo, int, (char const *file, mode_t mode),
724 _GL_ARG_NONNULL ((1))); 732 _GL_ARG_NONNULL ((1)));
725_GL_CXXALIAS_RPL (mkfifo, int, (char const *file, mode_t mode)); 733_GL_CXXALIAS_RPL (mkfifo, int, (char const *file, mode_t mode));
726# else 734# else
727# if !@HAVE_MKFIFO@ 735# if !@HAVE_MKFIFO@
728_GL_FUNCDECL_SYS (mkfifo, int, (char const *file, mode_t mode) 736_GL_FUNCDECL_SYS (mkfifo, int, (char const *file, mode_t mode),
729 _GL_ARG_NONNULL ((1))); 737 _GL_ARG_NONNULL ((1)));
730# endif 738# endif
731_GL_CXXALIAS_SYS (mkfifo, int, (char const *file, mode_t mode)); 739_GL_CXXALIAS_SYS (mkfifo, int, (char const *file, mode_t mode));
@@ -746,12 +754,12 @@ _GL_WARN_ON_USE (mkfifo, "mkfifo is not portable - "
746# undef mkfifoat 754# undef mkfifoat
747# define mkfifoat rpl_mkfifoat 755# define mkfifoat rpl_mkfifoat
748# endif 756# endif
749_GL_FUNCDECL_RPL (mkfifoat, int, (int fd, char const *file, mode_t mode) 757_GL_FUNCDECL_RPL (mkfifoat, int, (int fd, char const *file, mode_t mode),
750 _GL_ARG_NONNULL ((2))); 758 _GL_ARG_NONNULL ((2)));
751_GL_CXXALIAS_RPL (mkfifoat, int, (int fd, char const *file, mode_t mode)); 759_GL_CXXALIAS_RPL (mkfifoat, int, (int fd, char const *file, mode_t mode));
752# else 760# else
753# if !@HAVE_MKFIFOAT@ 761# if !@HAVE_MKFIFOAT@
754_GL_FUNCDECL_SYS (mkfifoat, int, (int fd, char const *file, mode_t mode) 762_GL_FUNCDECL_SYS (mkfifoat, int, (int fd, char const *file, mode_t mode),
755 _GL_ARG_NONNULL ((2))); 763 _GL_ARG_NONNULL ((2)));
756# endif 764# endif
757_GL_CXXALIAS_SYS (mkfifoat, int, (int fd, char const *file, mode_t mode)); 765_GL_CXXALIAS_SYS (mkfifoat, int, (int fd, char const *file, mode_t mode));
@@ -774,12 +782,12 @@ _GL_WARN_ON_USE (mkfifoat, "mkfifoat is not portable - "
774# undef mknod 782# undef mknod
775# define mknod rpl_mknod 783# define mknod rpl_mknod
776# endif 784# endif
777_GL_FUNCDECL_RPL (mknod, int, (char const *file, mode_t mode, dev_t dev) 785_GL_FUNCDECL_RPL (mknod, int, (char const *file, mode_t mode, dev_t dev),
778 _GL_ARG_NONNULL ((1))); 786 _GL_ARG_NONNULL ((1)));
779_GL_CXXALIAS_RPL (mknod, int, (char const *file, mode_t mode, dev_t dev)); 787_GL_CXXALIAS_RPL (mknod, int, (char const *file, mode_t mode, dev_t dev));
780# else 788# else
781# if !@HAVE_MKNOD@ 789# if !@HAVE_MKNOD@
782_GL_FUNCDECL_SYS (mknod, int, (char const *file, mode_t mode, dev_t dev) 790_GL_FUNCDECL_SYS (mknod, int, (char const *file, mode_t mode, dev_t dev),
783 _GL_ARG_NONNULL ((1))); 791 _GL_ARG_NONNULL ((1)));
784# endif 792# endif
785/* Need to cast, because on OSF/1 5.1, the third parameter is '...'. */ 793/* Need to cast, because on OSF/1 5.1, the third parameter is '...'. */
@@ -802,14 +810,14 @@ _GL_WARN_ON_USE (mknod, "mknod is not portable - "
802# define mknodat rpl_mknodat 810# define mknodat rpl_mknodat
803# endif 811# endif
804_GL_FUNCDECL_RPL (mknodat, int, 812_GL_FUNCDECL_RPL (mknodat, int,
805 (int fd, char const *file, mode_t mode, dev_t dev) 813 (int fd, char const *file, mode_t mode, dev_t dev),
806 _GL_ARG_NONNULL ((2))); 814 _GL_ARG_NONNULL ((2)));
807_GL_CXXALIAS_RPL (mknodat, int, 815_GL_CXXALIAS_RPL (mknodat, int,
808 (int fd, char const *file, mode_t mode, dev_t dev)); 816 (int fd, char const *file, mode_t mode, dev_t dev));
809# else 817# else
810# if !@HAVE_MKNODAT@ 818# if !@HAVE_MKNODAT@
811_GL_FUNCDECL_SYS (mknodat, int, 819_GL_FUNCDECL_SYS (mknodat, int,
812 (int fd, char const *file, mode_t mode, dev_t dev) 820 (int fd, char const *file, mode_t mode, dev_t dev),
813 _GL_ARG_NONNULL ((2))); 821 _GL_ARG_NONNULL ((2)));
814# endif 822# endif
815_GL_CXXALIAS_SYS (mknodat, int, 823_GL_CXXALIAS_SYS (mknodat, int,
@@ -841,7 +849,11 @@ _GL_WARN_ON_USE (mknodat, "mknodat is not portable - "
841# elif @WINDOWS_64_BIT_ST_SIZE@ 849# elif @WINDOWS_64_BIT_ST_SIZE@
842 /* Above, we define stat to _stati64. */ 850 /* Above, we define stat to _stati64. */
843# if defined __MINGW32__ && defined _stati64 851# if defined __MINGW32__ && defined _stati64
844# ifndef _USE_32BIT_TIME_T 852# ifdef _USE_32BIT_TIME_T
853 /* The system headers possibly define _stati64 to _stat32i64. */
854# undef _stat32i64
855# define _stat32i64(name, st) rpl_stat (name, st)
856# else
845 /* The system headers define _stati64 to _stat64. */ 857 /* The system headers define _stati64 to _stat64. */
846# undef _stat64 858# undef _stat64
847# define _stat64(name, st) rpl_stat (name, st) 859# define _stat64(name, st) rpl_stat (name, st)
@@ -916,7 +928,7 @@ _GL_CXXALIAS_RPL_1 (lstat, stat, int,
916# define lstat rpl_lstat 928# define lstat rpl_lstat
917# endif 929# endif
918_GL_FUNCDECL_RPL (lstat, int, 930_GL_FUNCDECL_RPL (lstat, int,
919 (const char *restrict name, struct stat *restrict buf) 931 (const char *restrict name, struct stat *restrict buf),
920 _GL_ARG_NONNULL ((1, 2))); 932 _GL_ARG_NONNULL ((1, 2)));
921_GL_CXXALIAS_RPL (lstat, int, 933_GL_CXXALIAS_RPL (lstat, int,
922 (const char *restrict name, struct stat *restrict buf)); 934 (const char *restrict name, struct stat *restrict buf));
@@ -928,8 +940,10 @@ _GL_CXXALIAS_SYS (lstat, int,
928_GL_CXXALIASWARN (lstat); 940_GL_CXXALIASWARN (lstat);
929# endif 941# endif
930#elif @GNULIB_OVERRIDES_STRUCT_STAT@ 942#elif @GNULIB_OVERRIDES_STRUCT_STAT@
931# undef lstat 943# if !GNULIB_LSTAT
932# define lstat lstat_used_without_requesting_gnulib_module_lstat 944# undef lstat
945# define lstat lstat_used_without_requesting_gnulib_module_lstat
946# endif
933#elif defined GNULIB_POSIXCHECK 947#elif defined GNULIB_POSIXCHECK
934# undef lstat 948# undef lstat
935# if HAVE_RAW_DECL_LSTAT 949# if HAVE_RAW_DECL_LSTAT
@@ -968,14 +982,14 @@ _GL_CXXALIASWARN (umask);
968# define utimensat rpl_utimensat 982# define utimensat rpl_utimensat
969# endif 983# endif
970_GL_FUNCDECL_RPL (utimensat, int, (int fd, char const *name, 984_GL_FUNCDECL_RPL (utimensat, int, (int fd, char const *name,
971 struct timespec const times[2], int flag) 985 struct timespec const times[2], int flag),
972 _GL_ARG_NONNULL ((2))); 986 _GL_ARG_NONNULL ((2)));
973_GL_CXXALIAS_RPL (utimensat, int, (int fd, char const *name, 987_GL_CXXALIAS_RPL (utimensat, int, (int fd, char const *name,
974 struct timespec const times[2], int flag)); 988 struct timespec const times[2], int flag));
975# else 989# else
976# if !@HAVE_UTIMENSAT@ 990# if !@HAVE_UTIMENSAT@
977_GL_FUNCDECL_SYS (utimensat, int, (int fd, char const *name, 991_GL_FUNCDECL_SYS (utimensat, int, (int fd, char const *name,
978 struct timespec const times[2], int flag) 992 struct timespec const times[2], int flag),
979 _GL_ARG_NONNULL ((2))); 993 _GL_ARG_NONNULL ((2)));
980# endif 994# endif
981_GL_CXXALIAS_SYS (utimensat, int, (int fd, char const *name, 995_GL_CXXALIAS_SYS (utimensat, int, (int fd, char const *name,
diff --git a/gl/sys_types.in.h b/gl/sys_types.in.h
index 0a0ccc3c..acf9b2f7 100644
--- a/gl/sys_types.in.h
+++ b/gl/sys_types.in.h
@@ -1,6 +1,6 @@
1/* Provide a more complete sys/types.h. 1/* Provide a more complete sys/types.h.
2 2
3 Copyright (C) 2011-2024 Free Software Foundation, Inc. 3 Copyright (C) 2011-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -60,6 +60,15 @@
60# define _GL_WINDOWS_64_BIT_OFF_T 1 60# define _GL_WINDOWS_64_BIT_OFF_T 1
61#endif 61#endif
62 62
63/* Define the off64_t type. */
64#if !@HAVE_OFF64_T@
65# if !GNULIB_defined_off64_t
66/* Define off64_t to int64_t always. */
67typedef long long off64_t;
68# define GNULIB_defined_off64_t 1
69# endif
70#endif
71
63/* Override dev_t and ino_t if distinguishable inodes support is requested 72/* Override dev_t and ino_t if distinguishable inodes support is requested
64 on native Windows. */ 73 on native Windows. */
65#if @WINDOWS_STAT_INODES@ 74#if @WINDOWS_STAT_INODES@
@@ -108,6 +117,22 @@ typedef unsigned long long int rpl_ino_t;
108# include <stddef.h> 117# include <stddef.h>
109#endif 118#endif
110 119
120/* Define blksize_t, required by POSIX:2024. */
121#if !@HAVE_BLKSIZE_T@
122# if !defined GNULIB_defined_blksize_t
123typedef int blksize_t;
124# define GNULIB_defined_blksize_t 1
125# endif
126#endif
127
128/* Define blkcnt_t, required by POSIX:2024. */
129#if !@HAVE_BLKCNT_T@
130# if !defined GNULIB_defined_blkcnt_t
131typedef long long blkcnt_t;
132# define GNULIB_defined_blkcnt_t 1
133# endif
134#endif
135
111#endif /* _@GUARD_PREFIX@_SYS_TYPES_H */ 136#endif /* _@GUARD_PREFIX@_SYS_TYPES_H */
112#endif /* _@GUARD_PREFIX@_SYS_TYPES_H */ 137#endif /* _@GUARD_PREFIX@_SYS_TYPES_H */
113#endif /* __need_XXX */ 138#endif /* __need_XXX */
diff --git a/gl/sys_uio.in.h b/gl/sys_uio.in.h
index 5e71859d..fec3a70a 100644
--- a/gl/sys_uio.in.h
+++ b/gl/sys_uio.in.h
@@ -1,5 +1,5 @@
1/* Substitute for <sys/uio.h>. 1/* Substitute for <sys/uio.h>.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 2 Copyright (C) 2011-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/time.in.h b/gl/time.in.h
index df99c8ab..3ff16e3b 100644
--- a/gl/time.in.h
+++ b/gl/time.in.h
@@ -1,6 +1,6 @@
1/* A more-standard <time.h>. 1/* A more-standard <time.h>.
2 2
3 Copyright (C) 2007-2024 Free Software Foundation, Inc. 3 Copyright (C) 2007-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -122,6 +122,23 @@ struct __time_t_must_be_integral {
122# endif 122# endif
123# endif 123# endif
124 124
125# if @GNULIB_TZNAME@
126/* tzname[0..1]: Abbreviated time zone names, set by the tzset() function. */
127# if NEED_DECL_TZNAME
128extern
129# ifdef __cplusplus
130 "C"
131# endif
132 char *tzname[];
133# endif
134# if defined _WIN32 && !defined __CYGWIN__
135/* On native Windows, map 'tzname' to '_tzname' etc., so that -loldnames is not
136 required. */
137# undef tzname
138# define tzname _tzname
139# endif
140# endif
141
125/* Set *TS to the current time, and return BASE. 142/* Set *TS to the current time, and return BASE.
126 Upon failure, return 0. */ 143 Upon failure, return 0. */
127# if @GNULIB_TIMESPEC_GET@ 144# if @GNULIB_TIMESPEC_GET@
@@ -130,12 +147,12 @@ struct __time_t_must_be_integral {
130# undef timespec_get 147# undef timespec_get
131# define timespec_get rpl_timespec_get 148# define timespec_get rpl_timespec_get
132# endif 149# endif
133_GL_FUNCDECL_RPL (timespec_get, int, (struct timespec *ts, int base) 150_GL_FUNCDECL_RPL (timespec_get, int, (struct timespec *ts, int base),
134 _GL_ARG_NONNULL ((1))); 151 _GL_ARG_NONNULL ((1)));
135_GL_CXXALIAS_RPL (timespec_get, int, (struct timespec *ts, int base)); 152_GL_CXXALIAS_RPL (timespec_get, int, (struct timespec *ts, int base));
136# else 153# else
137# if !@HAVE_TIMESPEC_GET@ 154# if !@HAVE_TIMESPEC_GET@
138_GL_FUNCDECL_SYS (timespec_get, int, (struct timespec *ts, int base) 155_GL_FUNCDECL_SYS (timespec_get, int, (struct timespec *ts, int base),
139 _GL_ARG_NONNULL ((1))); 156 _GL_ARG_NONNULL ((1)));
140# endif 157# endif
141_GL_CXXALIAS_SYS (timespec_get, int, (struct timespec *ts, int base)); 158_GL_CXXALIAS_SYS (timespec_get, int, (struct timespec *ts, int base));
@@ -159,17 +176,19 @@ _GL_WARN_ON_USE (timespec_get, "timespec_get is unportable - "
159# undef timespec_getres 176# undef timespec_getres
160# define timespec_getres rpl_timespec_getres 177# define timespec_getres rpl_timespec_getres
161# endif 178# endif
162_GL_FUNCDECL_RPL (timespec_getres, int, (struct timespec *ts, int base) 179_GL_FUNCDECL_RPL (timespec_getres, int, (struct timespec *ts, int base),
163 _GL_ARG_NONNULL ((1))); 180 _GL_ARG_NONNULL ((1)));
164_GL_CXXALIAS_RPL (timespec_getres, int, (struct timespec *ts, int base)); 181_GL_CXXALIAS_RPL (timespec_getres, int, (struct timespec *ts, int base));
165# else 182# else
166# if !@HAVE_TIMESPEC_GETRES@ 183# if !@HAVE_TIMESPEC_GETRES@
167_GL_FUNCDECL_SYS (timespec_getres, int, (struct timespec *ts, int base) 184_GL_FUNCDECL_SYS (timespec_getres, int, (struct timespec *ts, int base),
168 _GL_ARG_NONNULL ((1))); 185 _GL_ARG_NONNULL ((1)));
169# endif 186# endif
170_GL_CXXALIAS_SYS (timespec_getres, int, (struct timespec *ts, int base)); 187_GL_CXXALIAS_SYS (timespec_getres, int, (struct timespec *ts, int base));
171# endif 188# endif
189# if __GLIBC__ >= 2
172_GL_CXXALIASWARN (timespec_getres); 190_GL_CXXALIASWARN (timespec_getres);
191# endif
173# elif defined GNULIB_POSIXCHECK 192# elif defined GNULIB_POSIXCHECK
174# undef timespec_getres 193# undef timespec_getres
175# if HAVE_RAW_DECL_TIMESPEC_GETRES 194# if HAVE_RAW_DECL_TIMESPEC_GETRES
@@ -184,7 +203,7 @@ _GL_WARN_ON_USE (timespec_getres, "timespec_getres is unportable - "
184# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 203# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
185# define time rpl_time 204# define time rpl_time
186# endif 205# endif
187_GL_FUNCDECL_RPL (time, time_t, (time_t *__tp)); 206_GL_FUNCDECL_RPL (time, time_t, (time_t *__tp), );
188_GL_CXXALIAS_RPL (time, time_t, (time_t *__tp)); 207_GL_CXXALIAS_RPL (time, time_t, (time_t *__tp));
189# else 208# else
190_GL_CXXALIAS_SYS (time, time_t, (time_t *__tp)); 209_GL_CXXALIAS_SYS (time, time_t, (time_t *__tp));
@@ -209,14 +228,14 @@ _GL_WARN_ON_USE (time, "time has consistency problems - "
209# define nanosleep rpl_nanosleep 228# define nanosleep rpl_nanosleep
210# endif 229# endif
211_GL_FUNCDECL_RPL (nanosleep, int, 230_GL_FUNCDECL_RPL (nanosleep, int,
212 (struct timespec const *__rqtp, struct timespec *__rmtp) 231 (struct timespec const *__rqtp, struct timespec *__rmtp),
213 _GL_ARG_NONNULL ((1))); 232 _GL_ARG_NONNULL ((1)));
214_GL_CXXALIAS_RPL (nanosleep, int, 233_GL_CXXALIAS_RPL (nanosleep, int,
215 (struct timespec const *__rqtp, struct timespec *__rmtp)); 234 (struct timespec const *__rqtp, struct timespec *__rmtp));
216# else 235# else
217# if ! @HAVE_NANOSLEEP@ 236# if ! @HAVE_NANOSLEEP@
218_GL_FUNCDECL_SYS (nanosleep, int, 237_GL_FUNCDECL_SYS (nanosleep, int,
219 (struct timespec const *__rqtp, struct timespec *__rmtp) 238 (struct timespec const *__rqtp, struct timespec *__rmtp),
220 _GL_ARG_NONNULL ((1))); 239 _GL_ARG_NONNULL ((1)));
221# endif 240# endif
222_GL_CXXALIAS_SYS (nanosleep, int, 241_GL_CXXALIAS_SYS (nanosleep, int,
@@ -238,7 +257,7 @@ _GL_WARN_ON_USE (nanosleep, "nanosleep is unportable - "
238# undef tzset 257# undef tzset
239# define tzset rpl_tzset 258# define tzset rpl_tzset
240# endif 259# endif
241_GL_FUNCDECL_RPL (tzset, void, (void)); 260_GL_FUNCDECL_RPL (tzset, void, (void), );
242_GL_CXXALIAS_RPL (tzset, void, (void)); 261_GL_CXXALIAS_RPL (tzset, void, (void));
243# elif defined _WIN32 && !defined __CYGWIN__ 262# elif defined _WIN32 && !defined __CYGWIN__
244# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 263# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -278,7 +297,7 @@ _GL_WARN_ON_USE (tzset, "tzset has portability problems - "
278# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 297# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
279# define mktime rpl_mktime 298# define mktime rpl_mktime
280# endif 299# endif
281_GL_FUNCDECL_RPL (mktime, time_t, (struct tm *__tp) _GL_ARG_NONNULL ((1))); 300_GL_FUNCDECL_RPL (mktime, time_t, (struct tm *__tp), _GL_ARG_NONNULL ((1)));
282_GL_CXXALIAS_RPL (mktime, time_t, (struct tm *__tp)); 301_GL_CXXALIAS_RPL (mktime, time_t, (struct tm *__tp));
283# else 302# else
284_GL_CXXALIAS_SYS (mktime, time_t, (struct tm *__tp)); 303_GL_CXXALIAS_SYS (mktime, time_t, (struct tm *__tp));
@@ -304,14 +323,14 @@ _GL_WARN_ON_USE (mktime, "mktime has portability problems - "
304# define localtime_r rpl_localtime_r 323# define localtime_r rpl_localtime_r
305# endif 324# endif
306_GL_FUNCDECL_RPL (localtime_r, struct tm *, (time_t const *restrict __timer, 325_GL_FUNCDECL_RPL (localtime_r, struct tm *, (time_t const *restrict __timer,
307 struct tm *restrict __result) 326 struct tm *restrict __result),
308 _GL_ARG_NONNULL ((1, 2))); 327 _GL_ARG_NONNULL ((1, 2)));
309_GL_CXXALIAS_RPL (localtime_r, struct tm *, (time_t const *restrict __timer, 328_GL_CXXALIAS_RPL (localtime_r, struct tm *, (time_t const *restrict __timer,
310 struct tm *restrict __result)); 329 struct tm *restrict __result));
311# else 330# else
312# if ! @HAVE_DECL_LOCALTIME_R@ 331# if ! @HAVE_DECL_LOCALTIME_R@
313_GL_FUNCDECL_SYS (localtime_r, struct tm *, (time_t const *restrict __timer, 332_GL_FUNCDECL_SYS (localtime_r, struct tm *, (time_t const *restrict __timer,
314 struct tm *restrict __result) 333 struct tm *restrict __result),
315 _GL_ARG_NONNULL ((1, 2))); 334 _GL_ARG_NONNULL ((1, 2)));
316# endif 335# endif
317_GL_CXXALIAS_SYS (localtime_r, struct tm *, (time_t const *restrict __timer, 336_GL_CXXALIAS_SYS (localtime_r, struct tm *, (time_t const *restrict __timer,
@@ -326,14 +345,14 @@ _GL_CXXALIASWARN (localtime_r);
326# define gmtime_r rpl_gmtime_r 345# define gmtime_r rpl_gmtime_r
327# endif 346# endif
328_GL_FUNCDECL_RPL (gmtime_r, struct tm *, (time_t const *restrict __timer, 347_GL_FUNCDECL_RPL (gmtime_r, struct tm *, (time_t const *restrict __timer,
329 struct tm *restrict __result) 348 struct tm *restrict __result),
330 _GL_ARG_NONNULL ((1, 2))); 349 _GL_ARG_NONNULL ((1, 2)));
331_GL_CXXALIAS_RPL (gmtime_r, struct tm *, (time_t const *restrict __timer, 350_GL_CXXALIAS_RPL (gmtime_r, struct tm *, (time_t const *restrict __timer,
332 struct tm *restrict __result)); 351 struct tm *restrict __result));
333# else 352# else
334# if ! @HAVE_DECL_LOCALTIME_R@ 353# if ! @HAVE_DECL_LOCALTIME_R@
335_GL_FUNCDECL_SYS (gmtime_r, struct tm *, (time_t const *restrict __timer, 354_GL_FUNCDECL_SYS (gmtime_r, struct tm *, (time_t const *restrict __timer,
336 struct tm *restrict __result) 355 struct tm *restrict __result),
337 _GL_ARG_NONNULL ((1, 2))); 356 _GL_ARG_NONNULL ((1, 2)));
338# endif 357# endif
339_GL_CXXALIAS_SYS (gmtime_r, struct tm *, (time_t const *restrict __timer, 358_GL_CXXALIAS_SYS (gmtime_r, struct tm *, (time_t const *restrict __timer,
@@ -364,7 +383,7 @@ _GL_WARN_ON_USE (gmtime_r, "gmtime_r is unportable - "
364# undef localtime 383# undef localtime
365# define localtime rpl_localtime 384# define localtime rpl_localtime
366# endif 385# endif
367_GL_FUNCDECL_RPL (localtime, struct tm *, (time_t const *__timer) 386_GL_FUNCDECL_RPL (localtime, struct tm *, (time_t const *__timer),
368 _GL_ARG_NONNULL ((1))); 387 _GL_ARG_NONNULL ((1)));
369_GL_CXXALIAS_RPL (localtime, struct tm *, (time_t const *__timer)); 388_GL_CXXALIAS_RPL (localtime, struct tm *, (time_t const *__timer));
370# else 389# else
@@ -387,7 +406,7 @@ _GL_WARN_ON_USE (localtime, "localtime has portability problems - "
387# undef gmtime 406# undef gmtime
388# define gmtime rpl_gmtime 407# define gmtime rpl_gmtime
389# endif 408# endif
390_GL_FUNCDECL_RPL (gmtime, struct tm *, (time_t const *__timer) 409_GL_FUNCDECL_RPL (gmtime, struct tm *, (time_t const *__timer),
391 _GL_ARG_NONNULL ((1))); 410 _GL_ARG_NONNULL ((1)));
392_GL_CXXALIAS_RPL (gmtime, struct tm *, (time_t const *__timer)); 411_GL_CXXALIAS_RPL (gmtime, struct tm *, (time_t const *__timer));
393# else 412# else
@@ -403,7 +422,7 @@ _GL_CXXALIASWARN (gmtime);
403# if ! @HAVE_STRPTIME@ 422# if ! @HAVE_STRPTIME@
404_GL_FUNCDECL_SYS (strptime, char *, (char const *restrict __buf, 423_GL_FUNCDECL_SYS (strptime, char *, (char const *restrict __buf,
405 char const *restrict __format, 424 char const *restrict __format,
406 struct tm *restrict __tm) 425 struct tm *restrict __tm),
407 _GL_ARG_NONNULL ((1, 2, 3))); 426 _GL_ARG_NONNULL ((1, 2, 3)));
408# endif 427# endif
409_GL_CXXALIAS_SYS (strptime, char *, (char const *restrict __buf, 428_GL_CXXALIAS_SYS (strptime, char *, (char const *restrict __buf,
@@ -428,7 +447,7 @@ _GL_WARN_ON_USE (strptime, "strptime is unportable - "
428# ifndef __cplusplus 447# ifndef __cplusplus
429_GL_ATTRIBUTE_DEPRECATED 448_GL_ATTRIBUTE_DEPRECATED
430# endif 449# endif
431_GL_FUNCDECL_RPL (ctime, char *, (time_t const *__tp) 450_GL_FUNCDECL_RPL (ctime, char *, (time_t const *__tp),
432 _GL_ARG_NONNULL ((1))); 451 _GL_ARG_NONNULL ((1)));
433_GL_CXXALIAS_RPL (ctime, char *, (time_t const *__tp)); 452_GL_CXXALIAS_RPL (ctime, char *, (time_t const *__tp));
434# else 453# else
@@ -450,7 +469,7 @@ _GL_CXXALIASWARN (ctime);
450# endif 469# endif
451_GL_FUNCDECL_RPL (strftime, size_t, 470_GL_FUNCDECL_RPL (strftime, size_t,
452 (char *restrict __buf, size_t __bufsize, 471 (char *restrict __buf, size_t __bufsize,
453 const char *restrict __fmt, const struct tm *restrict __tp) 472 const char *restrict __fmt, const struct tm *restrict __tp),
454 _GL_ARG_NONNULL ((1, 3, 4))); 473 _GL_ARG_NONNULL ((1, 3, 4)));
455_GL_CXXALIAS_RPL (strftime, size_t, 474_GL_CXXALIAS_RPL (strftime, size_t,
456 (char *restrict __buf, size_t __bufsize, 475 (char *restrict __buf, size_t __bufsize,
@@ -471,14 +490,24 @@ _GL_WARN_ON_USE (strftime, "strftime has portability problems - "
471# endif 490# endif
472# endif 491# endif
473 492
474# if defined _GNU_SOURCE && @GNULIB_TIME_RZ@ && ! @HAVE_TIMEZONE_T@ 493# if @GNULIB_TIME_RZ@
475/* Functions that use a first-class time zone data type, instead of 494/* Functions that use a first-class time zone data type, instead of
476 relying on an implicit global time zone. 495 relying on an implicit global time zone.
477 Inspired by NetBSD. */ 496 Inspired by NetBSD. */
478 497
479/* Represents a time zone. 498/* Represents a time zone.
480 (timezone_t) NULL stands for UTC. */ 499 (timezone_t) NULL stands for UTC. */
500# if !@HAVE_TZALLOC@
501# if !GNULIB_defined_timezone_t
502# if !@HAVE_TIMEZONE_T@
481typedef struct tm_zone *timezone_t; 503typedef struct tm_zone *timezone_t;
504# else
505typedef struct tm_zone *rpl_timezone_t;
506# define timezone_t rpl_timezone_t
507# endif
508# define GNULIB_defined_timezone_t 1
509# endif
510# endif
482 511
483/* tzalloc (name) 512/* tzalloc (name)
484 Returns a time zone object for the given time zone NAME. This object 513 Returns a time zone object for the given time zone NAME. This object
@@ -488,37 +517,72 @@ typedef struct tm_zone *timezone_t;
488 would use it the TZ environment variable was unset. 517 would use it the TZ environment variable was unset.
489 May return NULL if NAME is invalid (this is platform dependent) or 518 May return NULL if NAME is invalid (this is platform dependent) or
490 upon memory allocation failure. */ 519 upon memory allocation failure. */
491_GL_FUNCDECL_SYS (tzalloc, timezone_t, (char const *__name)); 520# if !@HAVE_TZALLOC@
521_GL_FUNCDECL_SYS (tzalloc, timezone_t, (char const *__name), );
492_GL_CXXALIAS_SYS (tzalloc, timezone_t, (char const *__name)); 522_GL_CXXALIAS_SYS (tzalloc, timezone_t, (char const *__name));
523# endif
493 524
494/* tzfree (tz) 525/* tzfree (tz)
495 Frees a time zone object. 526 Frees a time zone object.
496 The argument must have been returned by tzalloc(). */ 527 The argument must have been returned by tzalloc(). */
497_GL_FUNCDECL_SYS (tzfree, void, (timezone_t __tz)); 528# if !@HAVE_TZALLOC@
529_GL_FUNCDECL_SYS (tzfree, void, (timezone_t __tz), );
498_GL_CXXALIAS_SYS (tzfree, void, (timezone_t __tz)); 530_GL_CXXALIAS_SYS (tzfree, void, (timezone_t __tz));
531# endif
499 532
500/* localtime_rz (tz, &t, &result) 533/* localtime_rz (tz, &t, &result)
501 Converts an absolute time T to a broken-down time RESULT, assuming the 534 Converts an absolute time T to a broken-down time RESULT, assuming the
502 time zone TZ. 535 time zone TZ.
503 This function is like 'localtime_r', but relies on the argument TZ instead 536 This function is like 'localtime_r', but relies on the argument TZ instead
504 of an implicit global time zone. */ 537 of an implicit global time zone. */
538# if @REPLACE_LOCALTIME_RZ@
539# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
540# undef localtime_rz
541# define localtime_rz rpl_localtime_rz
542# endif
543_GL_FUNCDECL_RPL (localtime_rz, struct tm *,
544 (timezone_t __tz, time_t const *restrict __timer,
545 struct tm *restrict __result),
546 _GL_ARG_NONNULL ((2, 3)));
547_GL_CXXALIAS_RPL (localtime_rz, struct tm *,
548 (timezone_t __tz, time_t const *restrict __timer,
549 struct tm *restrict __result));
550# else
551# if !@HAVE_TZALLOC@
505_GL_FUNCDECL_SYS (localtime_rz, struct tm *, 552_GL_FUNCDECL_SYS (localtime_rz, struct tm *,
506 (timezone_t __tz, time_t const *restrict __timer, 553 (timezone_t __tz, time_t const *restrict __timer,
507 struct tm *restrict __result) _GL_ARG_NONNULL ((2, 3))); 554 struct tm *restrict __result),
555 _GL_ARG_NONNULL ((2, 3)));
556# endif
508_GL_CXXALIAS_SYS (localtime_rz, struct tm *, 557_GL_CXXALIAS_SYS (localtime_rz, struct tm *,
509 (timezone_t __tz, time_t const *restrict __timer, 558 (timezone_t __tz, time_t const *restrict __timer,
510 struct tm *restrict __result)); 559 struct tm *restrict __result));
560# endif
511 561
512/* mktime_z (tz, &tm) 562/* mktime_z (tz, &tm)
513 Normalizes the broken-down time TM and converts it to an absolute time, 563 Normalizes the broken-down time TM and converts it to an absolute time,
514 assuming the time zone TZ. Returns the absolute time. 564 assuming the time zone TZ. Returns the absolute time.
515 This function is like 'mktime', but relies on the argument TZ instead 565 This function is like 'mktime', but relies on the argument TZ instead
516 of an implicit global time zone. */ 566 of an implicit global time zone. */
567# if @REPLACE_MKTIME_Z@
568# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
569# undef mktime_z
570# define mktime_z rpl_mktime_z
571# endif
572_GL_FUNCDECL_RPL (mktime_z, time_t,
573 (timezone_t __tz, struct tm *restrict __tm),
574 _GL_ARG_NONNULL ((2)));
575_GL_CXXALIAS_RPL (mktime_z, time_t,
576 (timezone_t __tz, struct tm *restrict __tm));
577# else
578# if !@HAVE_TZALLOC@
517_GL_FUNCDECL_SYS (mktime_z, time_t, 579_GL_FUNCDECL_SYS (mktime_z, time_t,
518 (timezone_t __tz, struct tm *restrict __tm) 580 (timezone_t __tz, struct tm *restrict __tm),
519 _GL_ARG_NONNULL ((2))); 581 _GL_ARG_NONNULL ((2)));
582# endif
520_GL_CXXALIAS_SYS (mktime_z, time_t, 583_GL_CXXALIAS_SYS (mktime_z, time_t,
521 (timezone_t __tz, struct tm *restrict __tm)); 584 (timezone_t __tz, struct tm *restrict __tm));
585# endif
522 586
523/* Time zone abbreviation strings (returned by 'localtime_rz' or 'mktime_z' 587/* Time zone abbreviation strings (returned by 'localtime_rz' or 'mktime_z'
524 in the 'tm_zone' member of 'struct tm') are valid as long as 588 in the 'tm_zone' member of 'struct tm') are valid as long as
@@ -535,11 +599,11 @@ _GL_CXXALIAS_SYS (mktime_z, time_t,
535# undef timegm 599# undef timegm
536# define timegm rpl_timegm 600# define timegm rpl_timegm
537# endif 601# endif
538_GL_FUNCDECL_RPL (timegm, time_t, (struct tm *__tm) _GL_ARG_NONNULL ((1))); 602_GL_FUNCDECL_RPL (timegm, time_t, (struct tm *__tm), _GL_ARG_NONNULL ((1)));
539_GL_CXXALIAS_RPL (timegm, time_t, (struct tm *__tm)); 603_GL_CXXALIAS_RPL (timegm, time_t, (struct tm *__tm));
540# else 604# else
541# if ! @HAVE_TIMEGM@ 605# if ! @HAVE_TIMEGM@
542_GL_FUNCDECL_SYS (timegm, time_t, (struct tm *__tm) _GL_ARG_NONNULL ((1))); 606_GL_FUNCDECL_SYS (timegm, time_t, (struct tm *__tm), _GL_ARG_NONNULL ((1)));
543# endif 607# endif
544_GL_CXXALIAS_SYS (timegm, time_t, (struct tm *__tm)); 608_GL_CXXALIAS_SYS (timegm, time_t, (struct tm *__tm));
545# endif 609# endif
diff --git a/gl/time_r.c b/gl/time_r.c
index b724f3b3..15d65d59 100644
--- a/gl/time_r.c
+++ b/gl/time_r.c
@@ -1,6 +1,6 @@
1/* Reentrant time functions like localtime_r. 1/* Reentrant time functions like localtime_r.
2 2
3 Copyright (C) 2003, 2006-2007, 2010-2024 Free Software Foundation, Inc. 3 Copyright (C) 2003, 2006-2007, 2010-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/timegm.c b/gl/timegm.c
index e5cf30c0..4c2615b9 100644
--- a/gl/timegm.c
+++ b/gl/timegm.c
@@ -1,6 +1,6 @@
1/* Convert UTC calendar time to simple time. Like mktime but assumes UTC. 1/* Convert UTC calendar time to simple time. Like mktime but assumes UTC.
2 2
3 Copyright (C) 1994-2024 Free Software Foundation, Inc. 3 Copyright (C) 1994-2025 Free Software Foundation, Inc.
4 This file is part of the GNU C Library. 4 This file is part of the GNU C Library.
5 5
6 The GNU C Library is free software; you can redistribute it and/or 6 The GNU C Library is free software; you can redistribute it and/or
@@ -30,8 +30,7 @@ __time64_t
30__timegm64 (struct tm *tmp) 30__timegm64 (struct tm *tmp)
31{ 31{
32 static mktime_offset_t gmtime_offset; 32 static mktime_offset_t gmtime_offset;
33 tmp->tm_isdst = 0; 33 return __mktime_internal (tmp, false, &gmtime_offset);
34 return __mktime_internal (tmp, __gmtime64_r, &gmtime_offset);
35} 34}
36 35
37#if defined _LIBC && __TIMESIZE != 64 36#if defined _LIBC && __TIMESIZE != 64
diff --git a/gl/uchar.h b/gl/uchar.h
new file mode 100644
index 00000000..abc636c5
--- /dev/null
+++ b/gl/uchar.h
@@ -0,0 +1,1456 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* <uchar.h> substitute - 16-bit and 32-bit wide character types.
3 Copyright (C) 2019-2025 Free Software Foundation, Inc.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18/* Written by Bruno Haible <bruno@clisp.org>, 2019. */
19
20/*
21 * ISO C 23 <uchar.h> for platforms that lack it.
22 */
23
24#ifndef _GL_UCHAR_H
25
26#if __GNUC__ >= 3
27#pragma GCC system_header
28#endif
29
30
31/* The include_next requires a split double-inclusion guard. */
32#if (defined __cplusplus ? 0 : 1)
33# if defined __HAIKU__
34/* Work around <https://dev.haiku-os.org/ticket/17040>. */
35# include <stdint.h>
36# endif
37/* On AIX 7.2 with xlclang++, /usr/include/uchar.h produces compilation errors
38 because it contains typedef definitions of char16_t and char32_t, however
39 char16_t and char32_t are keywords in this situation. To work around it,
40 define char16_t and char32_t as macros. */
41# if defined __cplusplus && defined _AIX && defined __ibmxl__ && defined __clang__
42# define char16_t gl_char16_t
43# define char32_t gl_char32_t
44# endif
45# include_next <uchar.h>
46#endif
47
48#ifndef _GL_UCHAR_H
49#define _GL_UCHAR_H
50
51/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, _GL_BEGIN_C_LINKAGE,
52 _GL_ATTRIBUTE_PURE, GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
53#if !_GL_CONFIG_H_INCLUDED
54 #error "Please include config.h first."
55#endif
56
57/* Get uint_least16_t, uint_least32_t. */
58#include <stdint.h>
59
60/* Get mbstate_t, size_t. */
61#include <wchar.h>
62
63/* For the inline functions. */
64#include <string.h>
65#include <wctype.h>
66
67/* The __attribute__ feature is available in gcc versions 2.5 and later.
68 The attribute __pure__ was added in gcc 2.96. */
69#ifndef _GL_ATTRIBUTE_PURE
70# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) || defined __clang__
71# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
72# else
73# define _GL_ATTRIBUTE_PURE /* empty */
74# endif
75#endif
76
77/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
78/* C++ compatible function declaration macros.
79 Copyright (C) 2010-2025 Free Software Foundation, Inc.
80
81 This program is free software: you can redistribute it and/or modify it
82 under the terms of the GNU Lesser General Public License as published
83 by the Free Software Foundation; either version 2 of the License, or
84 (at your option) any later version.
85
86 This program is distributed in the hope that it will be useful,
87 but WITHOUT ANY WARRANTY; without even the implied warranty of
88 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
89 Lesser General Public License for more details.
90
91 You should have received a copy of the GNU Lesser General Public License
92 along with this program. If not, see <https://www.gnu.org/licenses/>. */
93
94#ifndef _GL_CXXDEFS_H
95#define _GL_CXXDEFS_H
96
97/* Begin/end the GNULIB_NAMESPACE namespace. */
98#if defined __cplusplus && defined GNULIB_NAMESPACE
99# define _GL_BEGIN_NAMESPACE namespace GNULIB_NAMESPACE {
100# define _GL_END_NAMESPACE }
101#else
102# define _GL_BEGIN_NAMESPACE
103# define _GL_END_NAMESPACE
104#endif
105
106/* The three most frequent use cases of these macros are:
107
108 * For providing a substitute for a function that is missing on some
109 platforms, but is declared and works fine on the platforms on which
110 it exists:
111
112 #if @GNULIB_FOO@
113 # if !@HAVE_FOO@
114 _GL_FUNCDECL_SYS (foo, ...);
115 # endif
116 _GL_CXXALIAS_SYS (foo, ...);
117 _GL_CXXALIASWARN (foo);
118 #elif defined GNULIB_POSIXCHECK
119 ...
120 #endif
121
122 * For providing a replacement for a function that exists on all platforms,
123 but is broken/insufficient and needs to be replaced on some platforms:
124
125 #if @GNULIB_FOO@
126 # if @REPLACE_FOO@
127 # if !(defined __cplusplus && defined GNULIB_NAMESPACE)
128 # undef foo
129 # define foo rpl_foo
130 # endif
131 _GL_FUNCDECL_RPL (foo, ...);
132 _GL_CXXALIAS_RPL (foo, ...);
133 # else
134 _GL_CXXALIAS_SYS (foo, ...);
135 # endif
136 _GL_CXXALIASWARN (foo);
137 #elif defined GNULIB_POSIXCHECK
138 ...
139 #endif
140
141 * For providing a replacement for a function that exists on some platforms
142 but is broken/insufficient and needs to be replaced on some of them and
143 is additionally either missing or undeclared on some other platforms:
144
145 #if @GNULIB_FOO@
146 # if @REPLACE_FOO@
147 # if !(defined __cplusplus && defined GNULIB_NAMESPACE)
148 # undef foo
149 # define foo rpl_foo
150 # endif
151 _GL_FUNCDECL_RPL (foo, ...);
152 _GL_CXXALIAS_RPL (foo, ...);
153 # else
154 # if !@HAVE_FOO@ or if !@HAVE_DECL_FOO@
155 _GL_FUNCDECL_SYS (foo, ...);
156 # endif
157 _GL_CXXALIAS_SYS (foo, ...);
158 # endif
159 _GL_CXXALIASWARN (foo);
160 #elif defined GNULIB_POSIXCHECK
161 ...
162 #endif
163*/
164
165/* _GL_EXTERN_C declaration;
166 performs the declaration with C linkage. */
167#if defined __cplusplus
168# define _GL_EXTERN_C extern "C"
169#else
170# define _GL_EXTERN_C extern
171#endif
172
173/* _GL_EXTERN_C_FUNC declaration;
174 performs the declaration of a function with C linkage. */
175#if defined __cplusplus
176# define _GL_EXTERN_C_FUNC extern "C"
177#else
178/* In C mode, omit the 'extern' keyword, because attributes in bracket syntax
179 are not allowed between 'extern' and the return type (see gnulib-common.m4).
180 */
181# define _GL_EXTERN_C_FUNC
182#endif
183
184/* _GL_FUNCDECL_RPL (func, rettype, parameters, [attributes]);
185 declares a replacement function, named rpl_func, with the given prototype,
186 consisting of return type, parameters, and attributes.
187 Although attributes are optional, the comma before them is required
188 for portability to C17 and earlier. The attribute _GL_ATTRIBUTE_NOTHROW,
189 if needed, must be placed after the _GL_FUNCDECL_RPL invocation,
190 at the end of the declaration.
191 Examples:
192 _GL_FUNCDECL_RPL (free, void, (void *ptr), ) _GL_ATTRIBUTE_NOTHROW;
193 _GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...),
194 _GL_ARG_NONNULL ((1)));
195
196 Note: Attributes, such as _GL_ATTRIBUTE_DEPRECATED, are supported in front
197 of a _GL_FUNCDECL_RPL invocation only in C mode, not in C++ mode. (That's
198 because
199 [[...]] extern "C" <declaration>;
200 is invalid syntax in C++.)
201 */
202#define _GL_FUNCDECL_RPL(func,rettype,parameters,...) \
203 _GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters, __VA_ARGS__)
204#define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters,...) \
205 _GL_EXTERN_C_FUNC __VA_ARGS__ rettype rpl_func parameters
206
207/* _GL_FUNCDECL_SYS_NAME (func) expands to plain func if C++, and to
208 parenthesized func otherwise. Parenthesization is needed in C23 if
209 the function is like strchr and so is a qualifier-generic macro
210 that expands to something more complicated. */
211#ifdef __cplusplus
212# define _GL_FUNCDECL_SYS_NAME(func) func
213#else
214# define _GL_FUNCDECL_SYS_NAME(func) (func)
215#endif
216
217/* _GL_FUNCDECL_SYS (func, rettype, parameters, [attributes]);
218 declares the system function, named func, with the given prototype,
219 consisting of return type, parameters, and attributes.
220 Although attributes are optional, the comma before them is required
221 for portability to C17 and earlier. The attribute _GL_ATTRIBUTE_NOTHROW,
222 if needed, must be placed after the _GL_FUNCDECL_RPL invocation,
223 at the end of the declaration.
224 Examples:
225 _GL_FUNCDECL_SYS (getumask, mode_t, (void), ) _GL_ATTRIBUTE_NOTHROW;
226 _GL_FUNCDECL_SYS (posix_openpt, int, (int flags), _GL_ATTRIBUTE_NODISCARD);
227 */
228#define _GL_FUNCDECL_SYS(func,rettype,parameters,...) \
229 _GL_EXTERN_C_FUNC __VA_ARGS__ rettype _GL_FUNCDECL_SYS_NAME (func) parameters
230
231/* _GL_CXXALIAS_RPL (func, rettype, parameters);
232 declares a C++ alias called GNULIB_NAMESPACE::func
233 that redirects to rpl_func, if GNULIB_NAMESPACE is defined.
234 Example:
235 _GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...));
236
237 Wrapping rpl_func in an object with an inline conversion operator
238 avoids a reference to rpl_func unless GNULIB_NAMESPACE::func is
239 actually used in the program. */
240#define _GL_CXXALIAS_RPL(func,rettype,parameters) \
241 _GL_CXXALIAS_RPL_1 (func, rpl_##func, rettype, parameters)
242#if defined __cplusplus && defined GNULIB_NAMESPACE
243# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
244 namespace GNULIB_NAMESPACE \
245 { \
246 static const struct _gl_ ## func ## _wrapper \
247 { \
248 typedef rettype (*type) parameters; \
249 \
250 inline operator type () const \
251 { \
252 return ::rpl_func; \
253 } \
254 } func = {}; \
255 } \
256 _GL_EXTERN_C int _gl_cxxalias_dummy
257#else
258# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
259 _GL_EXTERN_C int _gl_cxxalias_dummy
260#endif
261
262/* _GL_CXXALIAS_MDA (func, rettype, parameters);
263 is to be used when func is a Microsoft deprecated alias, on native Windows.
264 It declares a C++ alias called GNULIB_NAMESPACE::func
265 that redirects to _func, if GNULIB_NAMESPACE is defined.
266 Example:
267 _GL_CXXALIAS_MDA (open, int, (const char *filename, int flags, ...));
268 */
269#define _GL_CXXALIAS_MDA(func,rettype,parameters) \
270 _GL_CXXALIAS_RPL_1 (func, _##func, rettype, parameters)
271
272/* _GL_CXXALIAS_RPL_CAST_1 (func, rpl_func, rettype, parameters);
273 is like _GL_CXXALIAS_RPL_1 (func, rpl_func, rettype, parameters);
274 except that the C function rpl_func may have a slightly different
275 declaration. A cast is used to silence the "invalid conversion" error
276 that would otherwise occur. */
277#if defined __cplusplus && defined GNULIB_NAMESPACE
278# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \
279 namespace GNULIB_NAMESPACE \
280 { \
281 static const struct _gl_ ## func ## _wrapper \
282 { \
283 typedef rettype (*type) parameters; \
284 \
285 inline operator type () const \
286 { \
287 return reinterpret_cast<type>(::rpl_func); \
288 } \
289 } func = {}; \
290 } \
291 _GL_EXTERN_C int _gl_cxxalias_dummy
292#else
293# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \
294 _GL_EXTERN_C int _gl_cxxalias_dummy
295#endif
296
297/* _GL_CXXALIAS_MDA_CAST (func, rettype, parameters);
298 is like _GL_CXXALIAS_MDA (func, rettype, parameters);
299 except that the C function func may have a slightly different declaration.
300 A cast is used to silence the "invalid conversion" error that would
301 otherwise occur. */
302#define _GL_CXXALIAS_MDA_CAST(func,rettype,parameters) \
303 _GL_CXXALIAS_RPL_CAST_1 (func, _##func, rettype, parameters)
304
305/* _GL_CXXALIAS_SYS (func, rettype, parameters);
306 declares a C++ alias called GNULIB_NAMESPACE::func
307 that redirects to the system provided function func, if GNULIB_NAMESPACE
308 is defined.
309 Example:
310 _GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...));
311
312 Wrapping func in an object with an inline conversion operator
313 avoids a reference to func unless GNULIB_NAMESPACE::func is
314 actually used in the program. */
315#if defined __cplusplus && defined GNULIB_NAMESPACE
316# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
317 namespace GNULIB_NAMESPACE \
318 { \
319 static const struct _gl_ ## func ## _wrapper \
320 { \
321 typedef rettype (*type) parameters; \
322 \
323 inline operator type () const \
324 { \
325 return ::func; \
326 } \
327 } func = {}; \
328 } \
329 _GL_EXTERN_C int _gl_cxxalias_dummy
330#else
331# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
332 _GL_EXTERN_C int _gl_cxxalias_dummy
333#endif
334
335/* _GL_CXXALIAS_SYS_CAST (func, rettype, parameters);
336 is like _GL_CXXALIAS_SYS (func, rettype, parameters);
337 except that the C function func may have a slightly different declaration.
338 A cast is used to silence the "invalid conversion" error that would
339 otherwise occur. */
340#if defined __cplusplus && defined GNULIB_NAMESPACE
341# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \
342 namespace GNULIB_NAMESPACE \
343 { \
344 static const struct _gl_ ## func ## _wrapper \
345 { \
346 typedef rettype (*type) parameters; \
347 \
348 inline operator type () const \
349 { \
350 return reinterpret_cast<type>(::func); \
351 } \
352 } func = {}; \
353 } \
354 _GL_EXTERN_C int _gl_cxxalias_dummy
355#else
356# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \
357 _GL_EXTERN_C int _gl_cxxalias_dummy
358#endif
359
360/* _GL_CXXALIAS_SYS_CAST2 (func, rettype, parameters, rettype2, parameters2);
361 is like _GL_CXXALIAS_SYS (func, rettype, parameters);
362 except that the C function is picked among a set of overloaded functions,
363 namely the one with rettype2 and parameters2. Two consecutive casts
364 are used to silence the "cannot find a match" and "invalid conversion"
365 errors that would otherwise occur. */
366#if defined __cplusplus && defined GNULIB_NAMESPACE
367 /* The outer cast must be a reinterpret_cast.
368 The inner cast: When the function is defined as a set of overloaded
369 functions, it works as a static_cast<>, choosing the designated variant.
370 When the function is defined as a single variant, it works as a
371 reinterpret_cast<>. The parenthesized cast syntax works both ways. */
372# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \
373 namespace GNULIB_NAMESPACE \
374 { \
375 static const struct _gl_ ## func ## _wrapper \
376 { \
377 typedef rettype (*type) parameters; \
378 \
379 inline operator type () const \
380 { \
381 return reinterpret_cast<type>((rettype2 (*) parameters2)(::func)); \
382 } \
383 } func = {}; \
384 } \
385 _GL_EXTERN_C int _gl_cxxalias_dummy
386#else
387# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \
388 _GL_EXTERN_C int _gl_cxxalias_dummy
389#endif
390
391/* _GL_CXXALIASWARN (func);
392 causes a warning to be emitted when ::func is used but not when
393 GNULIB_NAMESPACE::func is used. func must be defined without overloaded
394 variants. */
395#if defined __cplusplus && defined GNULIB_NAMESPACE
396# define _GL_CXXALIASWARN(func) \
397 _GL_CXXALIASWARN_1 (func, GNULIB_NAMESPACE)
398# define _GL_CXXALIASWARN_1(func,namespace) \
399 _GL_CXXALIASWARN_2 (func, namespace)
400/* To work around GCC bug <https://gcc.gnu.org/PR43881>,
401 we enable the warning only when not optimizing. */
402# if !(defined __GNUC__ && !defined __clang__ && __OPTIMIZE__)
403# define _GL_CXXALIASWARN_2(func,namespace) \
404 _GL_WARN_ON_USE (func, \
405 "The symbol ::" #func " refers to the system function. " \
406 "Use " #namespace "::" #func " instead.")
407# elif (__GNUC__ >= 3 || defined __clang__) && GNULIB_STRICT_CHECKING
408# define _GL_CXXALIASWARN_2(func,namespace) \
409 extern __typeof__ (func) func
410# else
411# define _GL_CXXALIASWARN_2(func,namespace) \
412 _GL_EXTERN_C int _gl_cxxalias_dummy
413# endif
414#else
415# define _GL_CXXALIASWARN(func) \
416 _GL_EXTERN_C int _gl_cxxalias_dummy
417#endif
418
419/* _GL_CXXALIASWARN1 (func, rettype, parameters_and_attributes);
420 causes a warning to be emitted when the given overloaded variant of ::func
421 is used but not when GNULIB_NAMESPACE::func is used. */
422#if defined __cplusplus && defined GNULIB_NAMESPACE
423# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \
424 _GL_CXXALIASWARN1_1 (func, rettype, parameters_and_attributes, \
425 GNULIB_NAMESPACE)
426# define _GL_CXXALIASWARN1_1(func,rettype,parameters_and_attributes,namespace) \
427 _GL_CXXALIASWARN1_2 (func, rettype, parameters_and_attributes, namespace)
428/* To work around GCC bug <https://gcc.gnu.org/PR43881>,
429 we enable the warning only when not optimizing. */
430# if !(defined __GNUC__ && !defined __clang__ && __OPTIMIZE__)
431# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \
432 _GL_WARN_ON_USE_CXX (func, rettype, rettype, parameters_and_attributes, \
433 "The symbol ::" #func " refers to the system function. " \
434 "Use " #namespace "::" #func " instead.")
435# else
436# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \
437 _GL_EXTERN_C int _gl_cxxalias_dummy
438# endif
439#else
440# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \
441 _GL_EXTERN_C int _gl_cxxalias_dummy
442#endif
443
444#endif /* _GL_CXXDEFS_H */
445
446/* The definition of _GL_ARG_NONNULL is copied here. */
447/* A C macro for declaring that specific arguments must not be NULL.
448 Copyright (C) 2009-2025 Free Software Foundation, Inc.
449
450 This program is free software: you can redistribute it and/or modify it
451 under the terms of the GNU Lesser General Public License as published
452 by the Free Software Foundation; either version 2 of the License, or
453 (at your option) any later version.
454
455 This program is distributed in the hope that it will be useful,
456 but WITHOUT ANY WARRANTY; without even the implied warranty of
457 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
458 Lesser General Public License for more details.
459
460 You should have received a copy of the GNU Lesser General Public License
461 along with this program. If not, see <https://www.gnu.org/licenses/>. */
462
463/* _GL_ARG_NONNULL((n,...,m)) tells the compiler and static analyzer tools
464 that the values passed as arguments n, ..., m must be non-NULL pointers.
465 n = 1 stands for the first argument, n = 2 for the second argument etc. */
466#ifndef _GL_ARG_NONNULL
467# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || defined __clang__
468# define _GL_ARG_NONNULL(params) __attribute__ ((__nonnull__ params))
469# else
470# define _GL_ARG_NONNULL(params)
471# endif
472#endif
473
474/* The definition of _GL_WARN_ON_USE is copied here. */
475/* A C macro for emitting warnings if a function is used.
476 Copyright (C) 2010-2025 Free Software Foundation, Inc.
477
478 This program is free software: you can redistribute it and/or modify it
479 under the terms of the GNU Lesser General Public License as published
480 by the Free Software Foundation; either version 2 of the License, or
481 (at your option) any later version.
482
483 This program is distributed in the hope that it will be useful,
484 but WITHOUT ANY WARRANTY; without even the implied warranty of
485 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
486 Lesser General Public License for more details.
487
488 You should have received a copy of the GNU Lesser General Public License
489 along with this program. If not, see <https://www.gnu.org/licenses/>. */
490
491/* _GL_WARN_ON_USE (function, "literal string") issues a declaration
492 for FUNCTION which will then trigger a compiler warning containing
493 the text of "literal string" anywhere that function is called, if
494 supported by the compiler. If the compiler does not support this
495 feature, the macro expands to an unused extern declaration.
496
497 _GL_WARN_ON_USE_ATTRIBUTE ("literal string") expands to the
498 attribute used in _GL_WARN_ON_USE. If the compiler does not support
499 this feature, it expands to empty.
500
501 These macros are useful for marking a function as a potential
502 portability trap, with the intent that "literal string" include
503 instructions on the replacement function that should be used
504 instead.
505 _GL_WARN_ON_USE is for functions with 'extern' linkage.
506 _GL_WARN_ON_USE_ATTRIBUTE is for functions with 'static' or 'inline'
507 linkage.
508
509 _GL_WARN_ON_USE should not be used more than once for a given function
510 in a given compilation unit (because this may generate a warning even
511 if the function is never called).
512
513 However, one of the reasons that a function is a portability trap is
514 if it has the wrong signature. Declaring FUNCTION with a different
515 signature in C is a compilation error, so this macro must use the
516 same type as any existing declaration so that programs that avoid
517 the problematic FUNCTION do not fail to compile merely because they
518 included a header that poisoned the function. But this implies that
519 _GL_WARN_ON_USE is only safe to use if FUNCTION is known to already
520 have a declaration. Use of this macro implies that there must not
521 be any other macro hiding the declaration of FUNCTION; but
522 undefining FUNCTION first is part of the poisoning process anyway
523 (although for symbols that are provided only via a macro, the result
524 is a compilation error rather than a warning containing
525 "literal string"). Also note that in C++, it is only safe to use if
526 FUNCTION has no overloads.
527
528 For an example, it is possible to poison 'getline' by:
529 - adding a call to gl_WARN_ON_USE_PREPARE([[#include <stdio.h>]],
530 [getline]) in configure.ac, which potentially defines
531 HAVE_RAW_DECL_GETLINE
532 - adding this code to a header that wraps the system <stdio.h>:
533 #undef getline
534 #if HAVE_RAW_DECL_GETLINE
535 _GL_WARN_ON_USE (getline, "getline is required by POSIX 2008, but"
536 "not universally present; use the gnulib module getline");
537 #endif
538
539 It is not possible to directly poison global variables. But it is
540 possible to write a wrapper accessor function, and poison that
541 (less common usage, like &environ, will cause a compilation error
542 rather than issue the nice warning, but the end result of informing
543 the developer about their portability problem is still achieved):
544 #if HAVE_RAW_DECL_ENVIRON
545 static char ***
546 rpl_environ (void) { return &environ; }
547 _GL_WARN_ON_USE (rpl_environ, "environ is not always properly declared");
548 # undef environ
549 # define environ (*rpl_environ ())
550 #endif
551 or better (avoiding contradictory use of 'static' and 'extern'):
552 #if HAVE_RAW_DECL_ENVIRON
553 static char ***
554 _GL_WARN_ON_USE_ATTRIBUTE ("environ is not always properly declared")
555 rpl_environ (void) { return &environ; }
556 # undef environ
557 # define environ (*rpl_environ ())
558 #endif
559 */
560#ifndef _GL_WARN_ON_USE
561
562# if (4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)) && !defined __clang__
563/* A compiler attribute is available in gcc versions 4.3.0 and later. */
564# define _GL_WARN_ON_USE(function, message) \
565_GL_WARN_EXTERN_C __typeof__ (function) function __attribute__ ((__warning__ (message)))
566# define _GL_WARN_ON_USE_ATTRIBUTE(message) \
567 __attribute__ ((__warning__ (message)))
568# elif __clang_major__ >= 4
569/* Another compiler attribute is available in clang. */
570# define _GL_WARN_ON_USE(function, message) \
571_GL_WARN_EXTERN_C __typeof__ (function) function \
572 __attribute__ ((__diagnose_if__ (1, message, "warning")))
573# define _GL_WARN_ON_USE_ATTRIBUTE(message) \
574 __attribute__ ((__diagnose_if__ (1, message, "warning")))
575# elif (__GNUC__ >= 3 || defined __clang__) && GNULIB_STRICT_CHECKING
576/* Verify the existence of the function. */
577# define _GL_WARN_ON_USE(function, message) \
578_GL_WARN_EXTERN_C __typeof__ (function) function
579# define _GL_WARN_ON_USE_ATTRIBUTE(message)
580# else /* Unsupported. */
581# define _GL_WARN_ON_USE(function, message) \
582_GL_WARN_EXTERN_C int _gl_warn_on_use
583# define _GL_WARN_ON_USE_ATTRIBUTE(message)
584# endif
585#endif
586
587/* _GL_WARN_ON_USE_CXX (function, rettype_gcc, rettype_clang, parameters_and_attributes, "message")
588 is like _GL_WARN_ON_USE (function, "message"), except that in C++ mode the
589 function is declared with the given prototype, consisting of return type,
590 parameters, and attributes.
591 This variant is useful for overloaded functions in C++. _GL_WARN_ON_USE does
592 not work in this case. */
593#ifndef _GL_WARN_ON_USE_CXX
594# if !defined __cplusplus
595# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
596 _GL_WARN_ON_USE (function, msg)
597# else
598# if (4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)) && !defined __clang__
599/* A compiler attribute is available in gcc versions 4.3.0 and later. */
600# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
601extern rettype_gcc function parameters_and_attributes \
602 __attribute__ ((__warning__ (msg)))
603# elif __clang_major__ >= 4
604/* Another compiler attribute is available in clang. */
605# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
606extern rettype_clang function parameters_and_attributes \
607 __attribute__ ((__diagnose_if__ (1, msg, "warning")))
608# elif (__GNUC__ >= 3 || defined __clang__) && GNULIB_STRICT_CHECKING
609/* Verify the existence of the function. */
610# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
611extern rettype_gcc function parameters_and_attributes
612# else /* Unsupported. */
613# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
614_GL_WARN_EXTERN_C int _gl_warn_on_use
615# endif
616# endif
617#endif
618
619/* _GL_WARN_EXTERN_C declaration;
620 performs the declaration with C linkage. */
621#ifndef _GL_WARN_EXTERN_C
622# if defined __cplusplus
623# define _GL_WARN_EXTERN_C extern "C"
624# else
625# define _GL_WARN_EXTERN_C extern
626# endif
627#endif
628
629
630_GL_INLINE_HEADER_BEGIN
631
632
633#if !(defined __cplusplus ? 0 || 0 : 1)
634
635/* An 8-bit variant of wchar_t.
636 Note: This type is only mandated by ISO C 23 or newer, and it does
637 denote UTF-8 units. */
638typedef unsigned char char8_t;
639
640#elif 0
641
642typedef unsigned char gl_char8_t;
643# define char8_t gl_char8_t
644
645#endif
646
647#if !(defined __cplusplus ? 0 || 0 : 1)
648
649/* A 16-bit variant of wchar_t.
650 Note: This type is only mandated by ISO C 11 or newer. In ISO C 23
651 and newer, it denotes UTF-16 units; in older versions of ISO C it did
652 so only on platforms on which __STDC_UTF_16__ was defined. */
653typedef uint_least16_t char16_t;
654
655#elif 0
656
657typedef uint_least16_t gl_char16_t;
658# define char16_t gl_char16_t
659
660#endif
661
662#if !(defined __cplusplus ? 0 || 0 : 1)
663
664/* A 32-bit variant of wchar_t.
665 Note: This type is only mandated by ISO C 11 or newer. In ISO C 23
666 and newer, it denotes UTF-32 code points; in older versions of ISO C
667 it did so only on platforms on which __STDC_UTF_32__ was defined.
668 In gnulib, we guarantee that it denotes UTF-32 code points if and
669 only if the module 'uchar-h-c23' is in use. */
670typedef uint_least32_t char32_t;
671
672#elif 0
673
674typedef uint_least32_t gl_char32_t;
675# define char32_t gl_char32_t
676
677#endif
678
679/* Define if a 'char32_t' can hold more characters than a 'wchar_t'. */
680#if 0 /* 32-bit AIX, Cygwin, native Windows */
681# define _GL_SMALL_WCHAR_T 1
682#endif
683
684/* Define if 'wchar_t', like 'char32_t',
685 - is a 32-bit type, and
686 - represents Unicode code points.
687 For this test, we can use __STDC_ISO_10646__ (defined by glibc, musl libc,
688 Cygwin) but need to consider _GL_SMALL_WCHAR_T, so as to exclude Cygwin.
689 We cannot use __STDC_UTF_16__ or __STDC_UTF_32__
690 - because these macros provide info about char16_t and char32_t (not
691 wchar_t!), and
692 - because GCC >= 4.9 defines these macros on all platforms, even on
693 FreeBSD and Solaris.
694 We should better not use __STD_UTF_16__, __STD_UTF_32__ either, because
695 these macros are misspellings, only defined by Android's <uchar.h>. */
696#if defined __STDC_ISO_10646__ && !_GL_SMALL_WCHAR_T
697/* glibc, musl libc */
698# define _GL_WCHAR_T_IS_UCS4 1
699#endif
700#if _GL_WCHAR_T_IS_UCS4
701static_assert (sizeof (char32_t) == sizeof (wchar_t));
702#endif
703
704
705/* Convert a single-byte character to a 32-bit wide character. */
706#if 0
707# if _GL_WCHAR_T_IS_UCS4 && !defined IN_BTOC32
708_GL_BEGIN_C_LINKAGE
709_GL_INLINE _GL_ATTRIBUTE_PURE wint_t
710btoc32 (int c)
711{
712 return
713# if 1 && defined __cplusplus && defined GNULIB_NAMESPACE
714 GNULIB_NAMESPACE::
715# endif
716 btowc (c);
717}
718_GL_END_C_LINKAGE
719# else
720_GL_FUNCDECL_SYS (btoc32, wint_t, (int c), _GL_ATTRIBUTE_PURE);
721# endif
722_GL_CXXALIAS_SYS (btoc32, wint_t, (int c));
723_GL_CXXALIASWARN (btoc32);
724#endif
725
726
727/* Test a specific property of a 32-bit wide character. */
728#if 1
729# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISALNUM
730_GL_BEGIN_C_LINKAGE
731_GL_INLINE int
732c32isalnum (wint_t wc)
733{
734 return
735# if defined __cplusplus && defined GNULIB_NAMESPACE
736 GNULIB_NAMESPACE::
737# endif
738 iswalnum (wc);
739}
740_GL_END_C_LINKAGE
741# else
742_GL_FUNCDECL_SYS (c32isalnum, int, (wint_t wc), );
743# endif
744_GL_CXXALIAS_SYS (c32isalnum, int, (wint_t wc));
745_GL_CXXALIASWARN (c32isalnum);
746#endif
747#if 1
748# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISALPHA
749_GL_BEGIN_C_LINKAGE
750_GL_INLINE int
751c32isalpha (wint_t wc)
752{
753 return
754# if defined __cplusplus && defined GNULIB_NAMESPACE
755 GNULIB_NAMESPACE::
756# endif
757 iswalpha (wc);
758}
759_GL_END_C_LINKAGE
760# else
761_GL_FUNCDECL_SYS (c32isalpha, int, (wint_t wc), );
762# endif
763_GL_CXXALIAS_SYS (c32isalpha, int, (wint_t wc));
764_GL_CXXALIASWARN (c32isalpha);
765#endif
766#if 1
767# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISBLANK
768_GL_BEGIN_C_LINKAGE
769_GL_INLINE int
770c32isblank (wint_t wc)
771{
772 return
773# if defined __cplusplus && defined GNULIB_NAMESPACE
774 GNULIB_NAMESPACE::
775# endif
776 iswblank (wc);
777}
778_GL_END_C_LINKAGE
779# else
780_GL_FUNCDECL_SYS (c32isblank, int, (wint_t wc), );
781# endif
782_GL_CXXALIAS_SYS (c32isblank, int, (wint_t wc));
783_GL_CXXALIASWARN (c32isblank);
784#endif
785#if 1
786# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISCNTRL
787_GL_BEGIN_C_LINKAGE
788_GL_INLINE int
789c32iscntrl (wint_t wc)
790{
791 return
792# if defined __cplusplus && defined GNULIB_NAMESPACE
793 GNULIB_NAMESPACE::
794# endif
795 iswcntrl (wc);
796}
797_GL_END_C_LINKAGE
798# else
799_GL_FUNCDECL_SYS (c32iscntrl, int, (wint_t wc), );
800# endif
801_GL_CXXALIAS_SYS (c32iscntrl, int, (wint_t wc));
802_GL_CXXALIASWARN (c32iscntrl);
803#endif
804#if 1
805# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISDIGIT
806_GL_BEGIN_C_LINKAGE
807_GL_INLINE int
808c32isdigit (wint_t wc)
809{
810 return
811# if 1 && defined __cplusplus && defined GNULIB_NAMESPACE
812 GNULIB_NAMESPACE::
813# endif
814 iswdigit (wc);
815}
816_GL_END_C_LINKAGE
817# else
818_GL_FUNCDECL_SYS (c32isdigit, int, (wint_t wc), );
819# endif
820_GL_CXXALIAS_SYS (c32isdigit, int, (wint_t wc));
821_GL_CXXALIASWARN (c32isdigit);
822#endif
823#if 1
824# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISGRAPH
825_GL_BEGIN_C_LINKAGE
826_GL_INLINE int
827c32isgraph (wint_t wc)
828{
829 return
830# if defined __cplusplus && defined GNULIB_NAMESPACE
831 GNULIB_NAMESPACE::
832# endif
833 iswgraph (wc);
834}
835_GL_END_C_LINKAGE
836# else
837_GL_FUNCDECL_SYS (c32isgraph, int, (wint_t wc), );
838# endif
839_GL_CXXALIAS_SYS (c32isgraph, int, (wint_t wc));
840_GL_CXXALIASWARN (c32isgraph);
841#endif
842#if 1
843# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISLOWER
844_GL_BEGIN_C_LINKAGE
845_GL_INLINE int
846c32islower (wint_t wc)
847{
848 return
849# if defined __cplusplus && defined GNULIB_NAMESPACE
850 GNULIB_NAMESPACE::
851# endif
852 iswlower (wc);
853}
854_GL_END_C_LINKAGE
855# else
856_GL_FUNCDECL_SYS (c32islower, int, (wint_t wc), );
857# endif
858_GL_CXXALIAS_SYS (c32islower, int, (wint_t wc));
859_GL_CXXALIASWARN (c32islower);
860#endif
861#if 1
862# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISPRINT
863_GL_BEGIN_C_LINKAGE
864_GL_INLINE int
865c32isprint (wint_t wc)
866{
867 return
868# if defined __cplusplus && defined GNULIB_NAMESPACE
869 GNULIB_NAMESPACE::
870# endif
871 iswprint (wc);
872}
873_GL_END_C_LINKAGE
874# else
875_GL_FUNCDECL_SYS (c32isprint, int, (wint_t wc), );
876# endif
877_GL_CXXALIAS_SYS (c32isprint, int, (wint_t wc));
878_GL_CXXALIASWARN (c32isprint);
879#endif
880#if 1
881# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISPUNCT
882_GL_BEGIN_C_LINKAGE
883_GL_INLINE int
884c32ispunct (wint_t wc)
885{
886 return
887# if defined __cplusplus && defined GNULIB_NAMESPACE
888 GNULIB_NAMESPACE::
889# endif
890 iswpunct (wc);
891}
892_GL_END_C_LINKAGE
893# else
894_GL_FUNCDECL_SYS (c32ispunct, int, (wint_t wc), );
895# endif
896_GL_CXXALIAS_SYS (c32ispunct, int, (wint_t wc));
897_GL_CXXALIASWARN (c32ispunct);
898#endif
899#if 1
900# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISSPACE
901_GL_BEGIN_C_LINKAGE
902_GL_INLINE int
903c32isspace (wint_t wc)
904{
905 return
906# if defined __cplusplus && defined GNULIB_NAMESPACE
907 GNULIB_NAMESPACE::
908# endif
909 iswspace (wc);
910}
911_GL_END_C_LINKAGE
912# else
913_GL_FUNCDECL_SYS (c32isspace, int, (wint_t wc), );
914# endif
915_GL_CXXALIAS_SYS (c32isspace, int, (wint_t wc));
916_GL_CXXALIASWARN (c32isspace);
917#endif
918#if 1
919# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISUPPER
920_GL_BEGIN_C_LINKAGE
921_GL_INLINE int
922c32isupper (wint_t wc)
923{
924 return
925# if defined __cplusplus && defined GNULIB_NAMESPACE
926 GNULIB_NAMESPACE::
927# endif
928 iswupper (wc);
929}
930_GL_END_C_LINKAGE
931# else
932_GL_FUNCDECL_SYS (c32isupper, int, (wint_t wc), );
933# endif
934_GL_CXXALIAS_SYS (c32isupper, int, (wint_t wc));
935_GL_CXXALIASWARN (c32isupper);
936#endif
937#if 1
938# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISXDIGIT
939_GL_BEGIN_C_LINKAGE
940_GL_INLINE int
941c32isxdigit (wint_t wc)
942{
943 return
944# if 1 && defined __cplusplus && defined GNULIB_NAMESPACE
945 GNULIB_NAMESPACE::
946# endif
947 iswxdigit (wc);
948}
949_GL_END_C_LINKAGE
950# else
951_GL_FUNCDECL_SYS (c32isxdigit, int, (wint_t wc), );
952# endif
953_GL_CXXALIAS_SYS (c32isxdigit, int, (wint_t wc));
954_GL_CXXALIASWARN (c32isxdigit);
955#endif
956
957
958/* Case mapping of a 32-bit wide character. */
959#if 1
960# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32TOLOWER
961_GL_BEGIN_C_LINKAGE
962_GL_INLINE wint_t
963c32tolower (wint_t wc)
964{
965 return
966# if defined __cplusplus && defined GNULIB_NAMESPACE
967 GNULIB_NAMESPACE::
968# endif
969 towlower (wc);
970}
971_GL_END_C_LINKAGE
972# else
973_GL_FUNCDECL_SYS (c32tolower, wint_t, (wint_t wc), );
974# endif
975_GL_CXXALIAS_SYS (c32tolower, wint_t, (wint_t wc));
976_GL_CXXALIASWARN (c32tolower);
977#endif
978#if 0
979# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32TOUPPER
980_GL_BEGIN_C_LINKAGE
981_GL_INLINE wint_t
982c32toupper (wint_t wc)
983{
984 return
985# if defined __cplusplus && defined GNULIB_NAMESPACE
986 GNULIB_NAMESPACE::
987# endif
988 towupper (wc);
989}
990_GL_END_C_LINKAGE
991# else
992_GL_FUNCDECL_SYS (c32toupper, wint_t, (wint_t wc), );
993# endif
994_GL_CXXALIAS_SYS (c32toupper, wint_t, (wint_t wc));
995_GL_CXXALIASWARN (c32toupper);
996#endif
997
998
999/* Number of screen columns needed for a 32-bit wide character. */
1000#if 1
1001# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32WIDTH
1002_GL_BEGIN_C_LINKAGE
1003_GL_INLINE int
1004c32width (char32_t wc)
1005{
1006 return
1007# if 1 && defined __cplusplus && defined GNULIB_NAMESPACE
1008 GNULIB_NAMESPACE::
1009# endif
1010 wcwidth (wc);
1011}
1012_GL_END_C_LINKAGE
1013# else
1014_GL_FUNCDECL_SYS (c32width, int, (char32_t wc), );
1015# endif
1016_GL_CXXALIAS_SYS (c32width, int, (char32_t wc));
1017_GL_CXXALIASWARN (c32width);
1018#endif
1019
1020
1021/* Converts a 32-bit wide character to a multibyte character. */
1022#if 0
1023# if 0
1024# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1025# undef c32rtomb
1026# define c32rtomb rpl_c32rtomb
1027# endif
1028_GL_FUNCDECL_RPL (c32rtomb, size_t, (char *s, char32_t wc, mbstate_t *ps), );
1029_GL_CXXALIAS_RPL (c32rtomb, size_t, (char *s, char32_t wc, mbstate_t *ps));
1030# else
1031# if !1
1032_GL_FUNCDECL_SYS (c32rtomb, size_t, (char *s, char32_t wc, mbstate_t *ps), );
1033# endif
1034_GL_CXXALIAS_SYS (c32rtomb, size_t, (char *s, char32_t wc, mbstate_t *ps));
1035# endif
1036# if __GLIBC__ + (__GLIBC_MINOR__ >= 16) > 2
1037_GL_CXXALIASWARN (c32rtomb);
1038# endif
1039#elif defined GNULIB_POSIXCHECK
1040# if HAVE_RAW_DECL_C32RTOMB
1041_GL_WARN_ON_USE (c32rtomb, "c32rtomb is not portable - "
1042 "use gnulib module c32rtomb for portability");
1043# endif
1044#endif
1045
1046
1047/* Convert a 32-bit wide string to a string. */
1048#if 0
1049# if _GL_WCHAR_T_IS_UCS4 && !defined IN_C32SNRTOMBS
1050_GL_BEGIN_C_LINKAGE
1051_GL_INLINE _GL_ARG_NONNULL ((2)) size_t
1052c32snrtombs (char *dest, const char32_t **srcp, size_t srclen, size_t len,
1053 mbstate_t *ps)
1054{
1055 return
1056# if 0 && defined __cplusplus && defined GNULIB_NAMESPACE
1057 GNULIB_NAMESPACE::
1058# endif
1059 wcsnrtombs (dest, (const wchar_t **) srcp, srclen, len, ps);
1060}
1061_GL_END_C_LINKAGE
1062# else
1063_GL_FUNCDECL_SYS (c32snrtombs, size_t,
1064 (char *dest, const char32_t **srcp, size_t srclen, size_t len,
1065 mbstate_t *ps),
1066 _GL_ARG_NONNULL ((2)));
1067# endif
1068_GL_CXXALIAS_SYS (c32snrtombs, size_t,
1069 (char *dest, const char32_t **srcp, size_t srclen, size_t len,
1070 mbstate_t *ps));
1071_GL_CXXALIASWARN (c32snrtombs);
1072#endif
1073
1074
1075/* Convert a 32-bit wide string to a string. */
1076#if 0
1077# if _GL_WCHAR_T_IS_UCS4 && !defined IN_C32SRTOMBS
1078_GL_BEGIN_C_LINKAGE
1079_GL_INLINE _GL_ARG_NONNULL ((2)) size_t
1080c32srtombs (char *dest, const char32_t **srcp, size_t len, mbstate_t *ps)
1081{
1082 return
1083# if 0 && defined __cplusplus && defined GNULIB_NAMESPACE
1084 GNULIB_NAMESPACE::
1085# endif
1086 wcsrtombs (dest, (const wchar_t **) srcp, len, ps);
1087}
1088_GL_END_C_LINKAGE
1089# else
1090_GL_FUNCDECL_SYS (c32srtombs, size_t,
1091 (char *dest, const char32_t **srcp, size_t len,
1092 mbstate_t *ps),
1093 _GL_ARG_NONNULL ((2)));
1094# endif
1095_GL_CXXALIAS_SYS (c32srtombs, size_t,
1096 (char *dest, const char32_t **srcp, size_t len,
1097 mbstate_t *ps));
1098_GL_CXXALIASWARN (c32srtombs);
1099#endif
1100
1101
1102/* Convert a 32-bit wide string to a string. */
1103#if 0
1104# if _GL_WCHAR_T_IS_UCS4 && !defined IN_C32STOMBS
1105_GL_BEGIN_C_LINKAGE
1106_GL_INLINE _GL_ARG_NONNULL ((2)) size_t
1107c32stombs (char *dest, const char32_t *src, size_t len)
1108{
1109 mbstate_t state;
1110
1111 mbszero (&state);
1112 return c32srtombs (dest, &src, len, &state);
1113}
1114_GL_END_C_LINKAGE
1115# else
1116_GL_FUNCDECL_SYS (c32stombs, size_t,
1117 (char *dest, const char32_t *src, size_t len),
1118 _GL_ARG_NONNULL ((2)));
1119# endif
1120_GL_CXXALIAS_SYS (c32stombs, size_t,
1121 (char *dest, const char32_t *src, size_t len));
1122_GL_CXXALIASWARN (c32stombs);
1123#endif
1124
1125
1126/* Number of screen columns needed for a size-bounded 32-bit wide string. */
1127#if 0
1128# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32SWIDTH
1129_GL_BEGIN_C_LINKAGE
1130_GL_INLINE _GL_ARG_NONNULL ((1)) int
1131c32swidth (const char32_t *s, size_t n)
1132{
1133 return
1134# if 0 && defined __cplusplus && defined GNULIB_NAMESPACE
1135 GNULIB_NAMESPACE::
1136# endif
1137 wcswidth ((const wchar_t *) s, n);
1138}
1139_GL_END_C_LINKAGE
1140# else
1141_GL_FUNCDECL_SYS (c32swidth, int, (const char32_t *s, size_t n),
1142 _GL_ARG_NONNULL ((1)));
1143# endif
1144_GL_CXXALIAS_SYS (c32swidth, int, (const char32_t *s, size_t n));
1145_GL_CXXALIASWARN (c32swidth);
1146#endif
1147
1148
1149/* Converts a 32-bit wide character to unibyte character.
1150 Returns the single-byte representation of WC if it exists,
1151 or EOF otherwise. */
1152#if 0
1153# if _GL_WCHAR_T_IS_UCS4 && !defined IN_C32TOB
1154_GL_BEGIN_C_LINKAGE
1155_GL_INLINE int
1156c32tob (wint_t wc)
1157{
1158 return
1159# if 0 && defined __cplusplus && defined GNULIB_NAMESPACE
1160 GNULIB_NAMESPACE::
1161# endif
1162 wctob (wc);
1163}
1164_GL_END_C_LINKAGE
1165# else
1166_GL_FUNCDECL_SYS (c32tob, int, (wint_t wc), );
1167# endif
1168_GL_CXXALIAS_SYS (c32tob, int, (wint_t wc));
1169_GL_CXXALIASWARN (c32tob);
1170#endif
1171
1172
1173/* Converts a multibyte character to a 32-bit wide character. */
1174#if 1
1175# if 1
1176# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1177# undef mbrtoc32
1178# define mbrtoc32 rpl_mbrtoc32
1179# endif
1180_GL_FUNCDECL_RPL (mbrtoc32, size_t,
1181 (char32_t *pc, const char *s, size_t n, mbstate_t *ps), );
1182_GL_CXXALIAS_RPL (mbrtoc32, size_t,
1183 (char32_t *pc, const char *s, size_t n, mbstate_t *ps));
1184# else
1185# if !1
1186_GL_FUNCDECL_SYS (mbrtoc32, size_t,
1187 (char32_t *pc, const char *s, size_t n, mbstate_t *ps), );
1188# endif
1189_GL_CXXALIAS_SYS (mbrtoc32, size_t,
1190 (char32_t *pc, const char *s, size_t n, mbstate_t *ps));
1191# endif
1192# if __GLIBC__ + (__GLIBC_MINOR__ >= 16) > 2
1193_GL_CXXALIASWARN (mbrtoc32);
1194# endif
1195#elif defined GNULIB_POSIXCHECK
1196# if HAVE_RAW_DECL_MBRTOC32
1197_GL_WARN_ON_USE (mbrtoc32, "mbrtoc32 is not portable - "
1198 "use gnulib module mbrtoc32 for portability");
1199# endif
1200#endif
1201
1202
1203/* Converts a multibyte character and returns the next 16-bit wide
1204 character. */
1205#if 0
1206# if 0
1207# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1208# undef mbrtoc16
1209# define mbrtoc16 rpl_mbrtoc16
1210# endif
1211_GL_FUNCDECL_RPL (mbrtoc16, size_t,
1212 (char16_t *pc, const char *s, size_t n, mbstate_t *ps), );
1213_GL_CXXALIAS_RPL (mbrtoc16, size_t,
1214 (char16_t *pc, const char *s, size_t n, mbstate_t *ps));
1215# else
1216# if !1
1217_GL_FUNCDECL_SYS (mbrtoc16, size_t,
1218 (char16_t *pc, const char *s, size_t n, mbstate_t *ps), );
1219# endif
1220_GL_CXXALIAS_SYS (mbrtoc16, size_t,
1221 (char16_t *pc, const char *s, size_t n, mbstate_t *ps));
1222# endif
1223# if __GLIBC__ + (__GLIBC_MINOR__ >= 16) > 2
1224_GL_CXXALIASWARN (mbrtoc16);
1225# endif
1226#elif defined GNULIB_POSIXCHECK
1227# if HAVE_RAW_DECL_MBRTOC16
1228_GL_WARN_ON_USE (mbrtoc16, "mbrtoc16 is not portable - "
1229 "use gnulib module mbrtoc16 for portability");
1230# endif
1231#endif
1232
1233
1234/* Convert a string to a 32-bit wide string. */
1235#if 0
1236# if _GL_WCHAR_T_IS_UCS4 && !defined IN_MBSNRTOC32S
1237_GL_BEGIN_C_LINKAGE
1238_GL_INLINE _GL_ARG_NONNULL ((2)) size_t
1239mbsnrtoc32s (char32_t *dest, const char **srcp, size_t srclen, size_t len,
1240 mbstate_t *ps)
1241{
1242 return
1243# if 0 && defined __cplusplus && defined GNULIB_NAMESPACE
1244 GNULIB_NAMESPACE::
1245# endif
1246 mbsnrtowcs ((wchar_t *) dest, srcp, srclen, len, ps);
1247}
1248_GL_END_C_LINKAGE
1249# else
1250_GL_FUNCDECL_SYS (mbsnrtoc32s, size_t,
1251 (char32_t *dest, const char **srcp, size_t srclen, size_t len,
1252 mbstate_t *ps),
1253 _GL_ARG_NONNULL ((2)));
1254# endif
1255_GL_CXXALIAS_SYS (mbsnrtoc32s, size_t,
1256 (char32_t *dest, const char **srcp, size_t srclen, size_t len,
1257 mbstate_t *ps));
1258_GL_CXXALIASWARN (mbsnrtoc32s);
1259#endif
1260
1261
1262/* Convert a string to a 32-bit wide string. */
1263#if 0
1264# if _GL_WCHAR_T_IS_UCS4 && !defined IN_MBSRTOC32S
1265_GL_BEGIN_C_LINKAGE
1266_GL_INLINE _GL_ARG_NONNULL ((2)) size_t
1267mbsrtoc32s (char32_t *dest, const char **srcp, size_t len, mbstate_t *ps)
1268{
1269 return
1270# if 0 && defined __cplusplus && defined GNULIB_NAMESPACE
1271 GNULIB_NAMESPACE::
1272# endif
1273 mbsrtowcs ((wchar_t *) dest, srcp, len, ps);
1274}
1275_GL_END_C_LINKAGE
1276# else
1277_GL_FUNCDECL_SYS (mbsrtoc32s, size_t,
1278 (char32_t *dest, const char **srcp, size_t len,
1279 mbstate_t *ps),
1280 _GL_ARG_NONNULL ((2)));
1281# endif
1282_GL_CXXALIAS_SYS (mbsrtoc32s, size_t,
1283 (char32_t *dest, const char **srcp, size_t len,
1284 mbstate_t *ps));
1285_GL_CXXALIASWARN (mbsrtoc32s);
1286#endif
1287
1288
1289/* Convert a string to a 32-bit wide string. */
1290#if 0
1291# if _GL_WCHAR_T_IS_UCS4 && !defined IN_MBSTOC32S
1292_GL_BEGIN_C_LINKAGE
1293_GL_INLINE _GL_ARG_NONNULL ((2)) size_t
1294mbstoc32s (char32_t *dest, const char *src, size_t len)
1295{
1296 mbstate_t state;
1297
1298 mbszero (&state);
1299 return mbsrtoc32s (dest, &src, len, &state);
1300}
1301_GL_END_C_LINKAGE
1302# else
1303_GL_FUNCDECL_SYS (mbstoc32s, size_t,
1304 (char32_t *dest, const char *src, size_t len),
1305 _GL_ARG_NONNULL ((2)));
1306# endif
1307_GL_CXXALIAS_SYS (mbstoc32s, size_t,
1308 (char32_t *dest, const char *src, size_t len));
1309_GL_CXXALIASWARN (mbstoc32s);
1310#endif
1311
1312
1313#if 0 || 0
1314/* A scalar type. Instances of this type, other than (c32_type_test_t) 0,
1315 represent a character property, sometimes also viewed as a "character class".
1316 It can be applied to 32-bit wide characters. It is the counterpart of
1317 type 'wctype_t' for wide characters.
1318 To test whether a given character has a certain property, use the function
1319 'c32_apply_type_test'. */
1320# if _GL_WCHAR_T_IS_UCS4
1321typedef wctype_t c32_type_test_t;
1322# else
1323typedef /*bool*/int (*c32_type_test_t) (wint_t wc);
1324# endif
1325#endif
1326
1327/* Return a character property with the given name, or (c32_type_test_t) 0
1328 if the designated property does not exist.
1329 This function is the counterpart of function 'wctype' for wide characters.
1330 */
1331#if 0
1332# if _GL_WCHAR_T_IS_UCS4 && !defined IN_C32_GET_TYPE_TEST
1333_GL_BEGIN_C_LINKAGE
1334_GL_INLINE _GL_ARG_NONNULL ((1)) c32_type_test_t
1335c32_get_type_test (const char *name)
1336{
1337 return
1338# if 1 && defined __cplusplus && defined GNULIB_NAMESPACE
1339 GNULIB_NAMESPACE::
1340# endif
1341 wctype (name);
1342}
1343_GL_END_C_LINKAGE
1344# else
1345_GL_FUNCDECL_SYS (c32_get_type_test, c32_type_test_t, (const char *name),
1346 _GL_ARG_NONNULL ((1)));
1347# endif
1348_GL_CXXALIAS_SYS (c32_get_type_test, c32_type_test_t, (const char *name));
1349_GL_CXXALIASWARN (c32_get_type_test);
1350#endif
1351
1352/* Test whether a given 32-bit wide character has the specified character
1353 property.
1354 Return non-zero if true, zero if false or if the argument is WEOF.
1355 This function is the counterpart of function 'iswctype' for wide characters.
1356 */
1357#if 0
1358# if _GL_WCHAR_T_IS_UCS4
1359# if !defined IN_C32_APPLY_TYPE_TEST
1360_GL_BEGIN_C_LINKAGE
1361_GL_INLINE int
1362c32_apply_type_test (wint_t wc, c32_type_test_t property)
1363{
1364 return
1365# if 1 && defined __cplusplus && defined GNULIB_NAMESPACE
1366 GNULIB_NAMESPACE::
1367# endif
1368 iswctype (wc, property);
1369}
1370_GL_END_C_LINKAGE
1371# else
1372_GL_FUNCDECL_SYS (c32_apply_type_test, int,
1373 (wint_t wc, c32_type_test_t property), );
1374# endif
1375# else
1376_GL_FUNCDECL_SYS (c32_apply_type_test, int,
1377 (wint_t wc, c32_type_test_t property),
1378 _GL_ARG_NONNULL ((2)));
1379# endif
1380_GL_CXXALIAS_SYS (c32_apply_type_test, int,
1381 (wint_t wc, c32_type_test_t property));
1382_GL_CXXALIASWARN (c32_apply_type_test);
1383#endif
1384
1385
1386#if 0 || 0
1387/* A scalar type. Instances of this type, other than (c32_mapping_t) 0,
1388 represent a character mapping. It can be applied to 32-bit wide characters.
1389 It is the counterpart of type 'wctrans_t' for wide characters.
1390 To apply a certain mapping to a given character, use the function
1391 'c32_apply_mapping'. */
1392# if _GL_WCHAR_T_IS_UCS4
1393typedef wctrans_t c32_mapping_t;
1394# else
1395typedef wint_t (*c32_mapping_t) (wint_t wc);
1396# endif
1397#endif
1398
1399/* Return a character mapping with the given name, or (c32_mapping_t) 0
1400 if the designated mapping does not exist.
1401 This function is the counterpart of function 'wctrans' for wide characters.
1402 */
1403#if 0
1404# if _GL_WCHAR_T_IS_UCS4 && !defined IN_C32_GET_MAPPING
1405_GL_BEGIN_C_LINKAGE
1406_GL_INLINE _GL_ARG_NONNULL ((1)) c32_mapping_t
1407c32_get_mapping (const char *name)
1408{
1409 return
1410# if 0 && defined __cplusplus && defined GNULIB_NAMESPACE
1411 GNULIB_NAMESPACE::
1412# endif
1413 wctrans (name);
1414}
1415_GL_END_C_LINKAGE
1416# else
1417_GL_FUNCDECL_SYS (c32_get_mapping, c32_mapping_t, (const char *name),
1418 _GL_ARG_NONNULL ((1)));
1419# endif
1420_GL_CXXALIAS_SYS (c32_get_mapping, c32_mapping_t, (const char *name));
1421_GL_CXXALIASWARN (c32_get_mapping);
1422#endif
1423
1424/* Apply the specified character mapping to a given 32-bit wide character.
1425 Return the result of this mapping. Return the WC argument unchanged if it is
1426 WEOF.
1427 This function is the counterpart of function 'towctrans' for wide characters.
1428 */
1429#if 0
1430# if _GL_WCHAR_T_IS_UCS4 && !defined IN_C32_APPLY_MAPPING
1431_GL_BEGIN_C_LINKAGE
1432_GL_INLINE _GL_ARG_NONNULL ((2)) wint_t
1433c32_apply_mapping (wint_t wc, c32_mapping_t mapping)
1434{
1435 return
1436# if 0 && defined __cplusplus && defined GNULIB_NAMESPACE
1437 GNULIB_NAMESPACE::
1438# endif
1439 towctrans (wc, mapping);
1440}
1441_GL_END_C_LINKAGE
1442# else
1443_GL_FUNCDECL_SYS (c32_apply_mapping, wint_t,
1444 (wint_t wc, c32_mapping_t mapping),
1445 _GL_ARG_NONNULL ((2)));
1446# endif
1447_GL_CXXALIAS_SYS (c32_apply_mapping, wint_t,
1448 (wint_t wc, c32_mapping_t mapping));
1449_GL_CXXALIASWARN (c32_apply_mapping);
1450#endif
1451
1452
1453_GL_INLINE_HEADER_END
1454
1455#endif /* _GL_UCHAR_H */
1456#endif /* _GL_UCHAR_H */
diff --git a/gl/uchar.in.h b/gl/uchar.in.h
new file mode 100644
index 00000000..9a65ac37
--- /dev/null
+++ b/gl/uchar.in.h
@@ -0,0 +1,912 @@
1/* <uchar.h> substitute - 16-bit and 32-bit wide character types.
2 Copyright (C) 2019-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17/* Written by Bruno Haible <bruno@clisp.org>, 2019. */
18
19/*
20 * ISO C 23 <uchar.h> for platforms that lack it.
21 */
22
23#ifndef _@GUARD_PREFIX@_UCHAR_H
24
25#if __GNUC__ >= 3
26@PRAGMA_SYSTEM_HEADER@
27#endif
28@PRAGMA_COLUMNS@
29
30/* The include_next requires a split double-inclusion guard. */
31#if (defined __cplusplus ? @CXX_HAVE_UCHAR_H@ : @HAVE_UCHAR_H@)
32# if defined __HAIKU__
33/* Work around <https://dev.haiku-os.org/ticket/17040>. */
34# include <stdint.h>
35# endif
36/* On AIX 7.2 with xlclang++, /usr/include/uchar.h produces compilation errors
37 because it contains typedef definitions of char16_t and char32_t, however
38 char16_t and char32_t are keywords in this situation. To work around it,
39 define char16_t and char32_t as macros. */
40# if defined __cplusplus && defined _AIX && defined __ibmxl__ && defined __clang__
41# define char16_t gl_char16_t
42# define char32_t gl_char32_t
43# endif
44# @INCLUDE_NEXT@ @NEXT_UCHAR_H@
45#endif
46
47#ifndef _@GUARD_PREFIX@_UCHAR_H
48#define _@GUARD_PREFIX@_UCHAR_H
49
50/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, _GL_BEGIN_C_LINKAGE,
51 _GL_ATTRIBUTE_PURE, GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
52#if !_GL_CONFIG_H_INCLUDED
53 #error "Please include config.h first."
54#endif
55
56/* Get uint_least16_t, uint_least32_t. */
57#include <stdint.h>
58
59/* Get mbstate_t, size_t. */
60#include <wchar.h>
61
62/* For the inline functions. */
63#include <string.h>
64#include <wctype.h>
65
66/* The __attribute__ feature is available in gcc versions 2.5 and later.
67 The attribute __pure__ was added in gcc 2.96. */
68#ifndef _GL_ATTRIBUTE_PURE
69# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) || defined __clang__
70# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
71# else
72# define _GL_ATTRIBUTE_PURE /* empty */
73# endif
74#endif
75
76/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
77
78/* The definition of _GL_ARG_NONNULL is copied here. */
79
80/* The definition of _GL_WARN_ON_USE is copied here. */
81
82
83_GL_INLINE_HEADER_BEGIN
84
85
86#if !(defined __cplusplus ? @CXX_HAVE_UCHAR_H@ || @CXX_HAS_CHAR8_TYPE@ : @HAVE_UCHAR_H@)
87
88/* An 8-bit variant of wchar_t.
89 Note: This type is only mandated by ISO C 23 or newer, and it does
90 denote UTF-8 units. */
91typedef unsigned char char8_t;
92
93#elif @GNULIBHEADERS_OVERRIDE_CHAR8_T@
94
95typedef unsigned char gl_char8_t;
96# define char8_t gl_char8_t
97
98#endif
99
100#if !(defined __cplusplus ? @CXX_HAVE_UCHAR_H@ || @CXX_HAS_UCHAR_TYPES@ : @HAVE_UCHAR_H@)
101
102/* A 16-bit variant of wchar_t.
103 Note: This type is only mandated by ISO C 11 or newer. In ISO C 23
104 and newer, it denotes UTF-16 units; in older versions of ISO C it did
105 so only on platforms on which __STDC_UTF_16__ was defined. */
106typedef uint_least16_t char16_t;
107
108#elif @GNULIBHEADERS_OVERRIDE_CHAR16_T@
109
110typedef uint_least16_t gl_char16_t;
111# define char16_t gl_char16_t
112
113#endif
114
115#if !(defined __cplusplus ? @CXX_HAVE_UCHAR_H@ || @CXX_HAS_UCHAR_TYPES@ : @HAVE_UCHAR_H@)
116
117/* A 32-bit variant of wchar_t.
118 Note: This type is only mandated by ISO C 11 or newer. In ISO C 23
119 and newer, it denotes UTF-32 code points; in older versions of ISO C
120 it did so only on platforms on which __STDC_UTF_32__ was defined.
121 In gnulib, we guarantee that it denotes UTF-32 code points if and
122 only if the module 'uchar-h-c23' is in use. */
123typedef uint_least32_t char32_t;
124
125#elif @GNULIBHEADERS_OVERRIDE_CHAR32_T@
126
127typedef uint_least32_t gl_char32_t;
128# define char32_t gl_char32_t
129
130#endif
131
132/* Define if a 'char32_t' can hold more characters than a 'wchar_t'. */
133#if @SMALL_WCHAR_T@ /* 32-bit AIX, Cygwin, native Windows */
134# define _GL_SMALL_WCHAR_T 1
135#endif
136
137/* Define if 'wchar_t', like 'char32_t',
138 - is a 32-bit type, and
139 - represents Unicode code points.
140 For this test, we can use __STDC_ISO_10646__ (defined by glibc, musl libc,
141 Cygwin) but need to consider _GL_SMALL_WCHAR_T, so as to exclude Cygwin.
142 We cannot use __STDC_UTF_16__ or __STDC_UTF_32__
143 - because these macros provide info about char16_t and char32_t (not
144 wchar_t!), and
145 - because GCC >= 4.9 defines these macros on all platforms, even on
146 FreeBSD and Solaris.
147 We should better not use __STD_UTF_16__, __STD_UTF_32__ either, because
148 these macros are misspellings, only defined by Android's <uchar.h>. */
149#if defined __STDC_ISO_10646__ && !_GL_SMALL_WCHAR_T
150/* glibc, musl libc */
151# define _GL_WCHAR_T_IS_UCS4 1
152#endif
153#if _GL_WCHAR_T_IS_UCS4
154static_assert (sizeof (char32_t) == sizeof (wchar_t));
155#endif
156
157
158/* Convert a single-byte character to a 32-bit wide character. */
159#if @GNULIB_BTOC32@
160# if _GL_WCHAR_T_IS_UCS4 && !defined IN_BTOC32
161_GL_BEGIN_C_LINKAGE
162_GL_INLINE _GL_ATTRIBUTE_PURE wint_t
163btoc32 (int c)
164{
165 return
166# if @GNULIB_BTOWC@ && defined __cplusplus && defined GNULIB_NAMESPACE
167 GNULIB_NAMESPACE::
168# endif
169 btowc (c);
170}
171_GL_END_C_LINKAGE
172# else
173_GL_FUNCDECL_SYS (btoc32, wint_t, (int c), _GL_ATTRIBUTE_PURE);
174# endif
175_GL_CXXALIAS_SYS (btoc32, wint_t, (int c));
176_GL_CXXALIASWARN (btoc32);
177#endif
178
179
180/* Test a specific property of a 32-bit wide character. */
181#if @GNULIB_C32ISALNUM@
182# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISALNUM
183_GL_BEGIN_C_LINKAGE
184_GL_INLINE int
185c32isalnum (wint_t wc)
186{
187 return
188# if defined __cplusplus && defined GNULIB_NAMESPACE
189 GNULIB_NAMESPACE::
190# endif
191 iswalnum (wc);
192}
193_GL_END_C_LINKAGE
194# else
195_GL_FUNCDECL_SYS (c32isalnum, int, (wint_t wc), );
196# endif
197_GL_CXXALIAS_SYS (c32isalnum, int, (wint_t wc));
198_GL_CXXALIASWARN (c32isalnum);
199#endif
200#if @GNULIB_C32ISALPHA@
201# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISALPHA
202_GL_BEGIN_C_LINKAGE
203_GL_INLINE int
204c32isalpha (wint_t wc)
205{
206 return
207# if defined __cplusplus && defined GNULIB_NAMESPACE
208 GNULIB_NAMESPACE::
209# endif
210 iswalpha (wc);
211}
212_GL_END_C_LINKAGE
213# else
214_GL_FUNCDECL_SYS (c32isalpha, int, (wint_t wc), );
215# endif
216_GL_CXXALIAS_SYS (c32isalpha, int, (wint_t wc));
217_GL_CXXALIASWARN (c32isalpha);
218#endif
219#if @GNULIB_C32ISBLANK@
220# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISBLANK
221_GL_BEGIN_C_LINKAGE
222_GL_INLINE int
223c32isblank (wint_t wc)
224{
225 return
226# if defined __cplusplus && defined GNULIB_NAMESPACE
227 GNULIB_NAMESPACE::
228# endif
229 iswblank (wc);
230}
231_GL_END_C_LINKAGE
232# else
233_GL_FUNCDECL_SYS (c32isblank, int, (wint_t wc), );
234# endif
235_GL_CXXALIAS_SYS (c32isblank, int, (wint_t wc));
236_GL_CXXALIASWARN (c32isblank);
237#endif
238#if @GNULIB_C32ISCNTRL@
239# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISCNTRL
240_GL_BEGIN_C_LINKAGE
241_GL_INLINE int
242c32iscntrl (wint_t wc)
243{
244 return
245# if defined __cplusplus && defined GNULIB_NAMESPACE
246 GNULIB_NAMESPACE::
247# endif
248 iswcntrl (wc);
249}
250_GL_END_C_LINKAGE
251# else
252_GL_FUNCDECL_SYS (c32iscntrl, int, (wint_t wc), );
253# endif
254_GL_CXXALIAS_SYS (c32iscntrl, int, (wint_t wc));
255_GL_CXXALIASWARN (c32iscntrl);
256#endif
257#if @GNULIB_C32ISDIGIT@
258# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISDIGIT
259_GL_BEGIN_C_LINKAGE
260_GL_INLINE int
261c32isdigit (wint_t wc)
262{
263 return
264# if @GNULIB_ISWDIGIT@ && defined __cplusplus && defined GNULIB_NAMESPACE
265 GNULIB_NAMESPACE::
266# endif
267 iswdigit (wc);
268}
269_GL_END_C_LINKAGE
270# else
271_GL_FUNCDECL_SYS (c32isdigit, int, (wint_t wc), );
272# endif
273_GL_CXXALIAS_SYS (c32isdigit, int, (wint_t wc));
274_GL_CXXALIASWARN (c32isdigit);
275#endif
276#if @GNULIB_C32ISGRAPH@
277# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISGRAPH
278_GL_BEGIN_C_LINKAGE
279_GL_INLINE int
280c32isgraph (wint_t wc)
281{
282 return
283# if defined __cplusplus && defined GNULIB_NAMESPACE
284 GNULIB_NAMESPACE::
285# endif
286 iswgraph (wc);
287}
288_GL_END_C_LINKAGE
289# else
290_GL_FUNCDECL_SYS (c32isgraph, int, (wint_t wc), );
291# endif
292_GL_CXXALIAS_SYS (c32isgraph, int, (wint_t wc));
293_GL_CXXALIASWARN (c32isgraph);
294#endif
295#if @GNULIB_C32ISLOWER@
296# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISLOWER
297_GL_BEGIN_C_LINKAGE
298_GL_INLINE int
299c32islower (wint_t wc)
300{
301 return
302# if defined __cplusplus && defined GNULIB_NAMESPACE
303 GNULIB_NAMESPACE::
304# endif
305 iswlower (wc);
306}
307_GL_END_C_LINKAGE
308# else
309_GL_FUNCDECL_SYS (c32islower, int, (wint_t wc), );
310# endif
311_GL_CXXALIAS_SYS (c32islower, int, (wint_t wc));
312_GL_CXXALIASWARN (c32islower);
313#endif
314#if @GNULIB_C32ISPRINT@
315# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISPRINT
316_GL_BEGIN_C_LINKAGE
317_GL_INLINE int
318c32isprint (wint_t wc)
319{
320 return
321# if defined __cplusplus && defined GNULIB_NAMESPACE
322 GNULIB_NAMESPACE::
323# endif
324 iswprint (wc);
325}
326_GL_END_C_LINKAGE
327# else
328_GL_FUNCDECL_SYS (c32isprint, int, (wint_t wc), );
329# endif
330_GL_CXXALIAS_SYS (c32isprint, int, (wint_t wc));
331_GL_CXXALIASWARN (c32isprint);
332#endif
333#if @GNULIB_C32ISPUNCT@
334# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISPUNCT
335_GL_BEGIN_C_LINKAGE
336_GL_INLINE int
337c32ispunct (wint_t wc)
338{
339 return
340# if defined __cplusplus && defined GNULIB_NAMESPACE
341 GNULIB_NAMESPACE::
342# endif
343 iswpunct (wc);
344}
345_GL_END_C_LINKAGE
346# else
347_GL_FUNCDECL_SYS (c32ispunct, int, (wint_t wc), );
348# endif
349_GL_CXXALIAS_SYS (c32ispunct, int, (wint_t wc));
350_GL_CXXALIASWARN (c32ispunct);
351#endif
352#if @GNULIB_C32ISSPACE@
353# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISSPACE
354_GL_BEGIN_C_LINKAGE
355_GL_INLINE int
356c32isspace (wint_t wc)
357{
358 return
359# if defined __cplusplus && defined GNULIB_NAMESPACE
360 GNULIB_NAMESPACE::
361# endif
362 iswspace (wc);
363}
364_GL_END_C_LINKAGE
365# else
366_GL_FUNCDECL_SYS (c32isspace, int, (wint_t wc), );
367# endif
368_GL_CXXALIAS_SYS (c32isspace, int, (wint_t wc));
369_GL_CXXALIASWARN (c32isspace);
370#endif
371#if @GNULIB_C32ISUPPER@
372# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISUPPER
373_GL_BEGIN_C_LINKAGE
374_GL_INLINE int
375c32isupper (wint_t wc)
376{
377 return
378# if defined __cplusplus && defined GNULIB_NAMESPACE
379 GNULIB_NAMESPACE::
380# endif
381 iswupper (wc);
382}
383_GL_END_C_LINKAGE
384# else
385_GL_FUNCDECL_SYS (c32isupper, int, (wint_t wc), );
386# endif
387_GL_CXXALIAS_SYS (c32isupper, int, (wint_t wc));
388_GL_CXXALIASWARN (c32isupper);
389#endif
390#if @GNULIB_C32ISXDIGIT@
391# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32ISXDIGIT
392_GL_BEGIN_C_LINKAGE
393_GL_INLINE int
394c32isxdigit (wint_t wc)
395{
396 return
397# if @GNULIB_ISWXDIGIT@ && defined __cplusplus && defined GNULIB_NAMESPACE
398 GNULIB_NAMESPACE::
399# endif
400 iswxdigit (wc);
401}
402_GL_END_C_LINKAGE
403# else
404_GL_FUNCDECL_SYS (c32isxdigit, int, (wint_t wc), );
405# endif
406_GL_CXXALIAS_SYS (c32isxdigit, int, (wint_t wc));
407_GL_CXXALIASWARN (c32isxdigit);
408#endif
409
410
411/* Case mapping of a 32-bit wide character. */
412#if @GNULIB_C32TOLOWER@
413# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32TOLOWER
414_GL_BEGIN_C_LINKAGE
415_GL_INLINE wint_t
416c32tolower (wint_t wc)
417{
418 return
419# if defined __cplusplus && defined GNULIB_NAMESPACE
420 GNULIB_NAMESPACE::
421# endif
422 towlower (wc);
423}
424_GL_END_C_LINKAGE
425# else
426_GL_FUNCDECL_SYS (c32tolower, wint_t, (wint_t wc), );
427# endif
428_GL_CXXALIAS_SYS (c32tolower, wint_t, (wint_t wc));
429_GL_CXXALIASWARN (c32tolower);
430#endif
431#if @GNULIB_C32TOUPPER@
432# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32TOUPPER
433_GL_BEGIN_C_LINKAGE
434_GL_INLINE wint_t
435c32toupper (wint_t wc)
436{
437 return
438# if defined __cplusplus && defined GNULIB_NAMESPACE
439 GNULIB_NAMESPACE::
440# endif
441 towupper (wc);
442}
443_GL_END_C_LINKAGE
444# else
445_GL_FUNCDECL_SYS (c32toupper, wint_t, (wint_t wc), );
446# endif
447_GL_CXXALIAS_SYS (c32toupper, wint_t, (wint_t wc));
448_GL_CXXALIASWARN (c32toupper);
449#endif
450
451
452/* Number of screen columns needed for a 32-bit wide character. */
453#if @GNULIB_C32WIDTH@
454# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32WIDTH
455_GL_BEGIN_C_LINKAGE
456_GL_INLINE int
457c32width (char32_t wc)
458{
459 return
460# if @GNULIB_WCWIDTH@ && defined __cplusplus && defined GNULIB_NAMESPACE
461 GNULIB_NAMESPACE::
462# endif
463 wcwidth (wc);
464}
465_GL_END_C_LINKAGE
466# else
467_GL_FUNCDECL_SYS (c32width, int, (char32_t wc), );
468# endif
469_GL_CXXALIAS_SYS (c32width, int, (char32_t wc));
470_GL_CXXALIASWARN (c32width);
471#endif
472
473
474/* Converts a 32-bit wide character to a multibyte character. */
475#if @GNULIB_C32RTOMB@
476# if @REPLACE_C32RTOMB@
477# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
478# undef c32rtomb
479# define c32rtomb rpl_c32rtomb
480# endif
481_GL_FUNCDECL_RPL (c32rtomb, size_t, (char *s, char32_t wc, mbstate_t *ps), );
482_GL_CXXALIAS_RPL (c32rtomb, size_t, (char *s, char32_t wc, mbstate_t *ps));
483# else
484# if !@HAVE_C32RTOMB@
485_GL_FUNCDECL_SYS (c32rtomb, size_t, (char *s, char32_t wc, mbstate_t *ps), );
486# endif
487_GL_CXXALIAS_SYS (c32rtomb, size_t, (char *s, char32_t wc, mbstate_t *ps));
488# endif
489# if __GLIBC__ + (__GLIBC_MINOR__ >= 16) > 2
490_GL_CXXALIASWARN (c32rtomb);
491# endif
492#elif defined GNULIB_POSIXCHECK
493# undef c32rtomb
494# if HAVE_RAW_DECL_C32RTOMB
495_GL_WARN_ON_USE (c32rtomb, "c32rtomb is not portable - "
496 "use gnulib module c32rtomb for portability");
497# endif
498#endif
499
500
501/* Convert a 32-bit wide string to a string. */
502#if @GNULIB_C32SNRTOMBS@
503# if _GL_WCHAR_T_IS_UCS4 && !defined IN_C32SNRTOMBS
504_GL_BEGIN_C_LINKAGE
505_GL_INLINE _GL_ARG_NONNULL ((2)) size_t
506c32snrtombs (char *dest, const char32_t **srcp, size_t srclen, size_t len,
507 mbstate_t *ps)
508{
509 return
510# if @GNULIB_WCSNRTOMBS@ && defined __cplusplus && defined GNULIB_NAMESPACE
511 GNULIB_NAMESPACE::
512# endif
513 wcsnrtombs (dest, (const wchar_t **) srcp, srclen, len, ps);
514}
515_GL_END_C_LINKAGE
516# else
517_GL_FUNCDECL_SYS (c32snrtombs, size_t,
518 (char *dest, const char32_t **srcp, size_t srclen, size_t len,
519 mbstate_t *ps),
520 _GL_ARG_NONNULL ((2)));
521# endif
522_GL_CXXALIAS_SYS (c32snrtombs, size_t,
523 (char *dest, const char32_t **srcp, size_t srclen, size_t len,
524 mbstate_t *ps));
525_GL_CXXALIASWARN (c32snrtombs);
526#endif
527
528
529/* Convert a 32-bit wide string to a string. */
530#if @GNULIB_C32SRTOMBS@
531# if _GL_WCHAR_T_IS_UCS4 && !defined IN_C32SRTOMBS
532_GL_BEGIN_C_LINKAGE
533_GL_INLINE _GL_ARG_NONNULL ((2)) size_t
534c32srtombs (char *dest, const char32_t **srcp, size_t len, mbstate_t *ps)
535{
536 return
537# if @GNULIB_WCSRTOMBS@ && defined __cplusplus && defined GNULIB_NAMESPACE
538 GNULIB_NAMESPACE::
539# endif
540 wcsrtombs (dest, (const wchar_t **) srcp, len, ps);
541}
542_GL_END_C_LINKAGE
543# else
544_GL_FUNCDECL_SYS (c32srtombs, size_t,
545 (char *dest, const char32_t **srcp, size_t len,
546 mbstate_t *ps),
547 _GL_ARG_NONNULL ((2)));
548# endif
549_GL_CXXALIAS_SYS (c32srtombs, size_t,
550 (char *dest, const char32_t **srcp, size_t len,
551 mbstate_t *ps));
552_GL_CXXALIASWARN (c32srtombs);
553#endif
554
555
556/* Convert a 32-bit wide string to a string. */
557#if @GNULIB_C32STOMBS@
558# if _GL_WCHAR_T_IS_UCS4 && !defined IN_C32STOMBS
559_GL_BEGIN_C_LINKAGE
560_GL_INLINE _GL_ARG_NONNULL ((2)) size_t
561c32stombs (char *dest, const char32_t *src, size_t len)
562{
563 mbstate_t state;
564
565 mbszero (&state);
566 return c32srtombs (dest, &src, len, &state);
567}
568_GL_END_C_LINKAGE
569# else
570_GL_FUNCDECL_SYS (c32stombs, size_t,
571 (char *dest, const char32_t *src, size_t len),
572 _GL_ARG_NONNULL ((2)));
573# endif
574_GL_CXXALIAS_SYS (c32stombs, size_t,
575 (char *dest, const char32_t *src, size_t len));
576_GL_CXXALIASWARN (c32stombs);
577#endif
578
579
580/* Number of screen columns needed for a size-bounded 32-bit wide string. */
581#if @GNULIB_C32SWIDTH@
582# if (_GL_WCHAR_T_IS_UCS4 && !GNULIB_defined_mbstate_t) && !defined IN_C32SWIDTH
583_GL_BEGIN_C_LINKAGE
584_GL_INLINE _GL_ARG_NONNULL ((1)) int
585c32swidth (const char32_t *s, size_t n)
586{
587 return
588# if @GNULIB_WCSWIDTH@ && defined __cplusplus && defined GNULIB_NAMESPACE
589 GNULIB_NAMESPACE::
590# endif
591 wcswidth ((const wchar_t *) s, n);
592}
593_GL_END_C_LINKAGE
594# else
595_GL_FUNCDECL_SYS (c32swidth, int, (const char32_t *s, size_t n),
596 _GL_ARG_NONNULL ((1)));
597# endif
598_GL_CXXALIAS_SYS (c32swidth, int, (const char32_t *s, size_t n));
599_GL_CXXALIASWARN (c32swidth);
600#endif
601
602
603/* Converts a 32-bit wide character to unibyte character.
604 Returns the single-byte representation of WC if it exists,
605 or EOF otherwise. */
606#if @GNULIB_C32TOB@
607# if _GL_WCHAR_T_IS_UCS4 && !defined IN_C32TOB
608_GL_BEGIN_C_LINKAGE
609_GL_INLINE int
610c32tob (wint_t wc)
611{
612 return
613# if @GNULIB_WCTOB@ && defined __cplusplus && defined GNULIB_NAMESPACE
614 GNULIB_NAMESPACE::
615# endif
616 wctob (wc);
617}
618_GL_END_C_LINKAGE
619# else
620_GL_FUNCDECL_SYS (c32tob, int, (wint_t wc), );
621# endif
622_GL_CXXALIAS_SYS (c32tob, int, (wint_t wc));
623_GL_CXXALIASWARN (c32tob);
624#endif
625
626
627/* Converts a multibyte character to a 32-bit wide character. */
628#if @GNULIB_MBRTOC32@
629# if @REPLACE_MBRTOC32@
630# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
631# undef mbrtoc32
632# define mbrtoc32 rpl_mbrtoc32
633# endif
634_GL_FUNCDECL_RPL (mbrtoc32, size_t,
635 (char32_t *pc, const char *s, size_t n, mbstate_t *ps), );
636_GL_CXXALIAS_RPL (mbrtoc32, size_t,
637 (char32_t *pc, const char *s, size_t n, mbstate_t *ps));
638# else
639# if !@HAVE_MBRTOC32@
640_GL_FUNCDECL_SYS (mbrtoc32, size_t,
641 (char32_t *pc, const char *s, size_t n, mbstate_t *ps), );
642# endif
643_GL_CXXALIAS_SYS (mbrtoc32, size_t,
644 (char32_t *pc, const char *s, size_t n, mbstate_t *ps));
645# endif
646# if __GLIBC__ + (__GLIBC_MINOR__ >= 16) > 2
647_GL_CXXALIASWARN (mbrtoc32);
648# endif
649#elif defined GNULIB_POSIXCHECK
650# undef mbrtoc32
651# if HAVE_RAW_DECL_MBRTOC32
652_GL_WARN_ON_USE (mbrtoc32, "mbrtoc32 is not portable - "
653 "use gnulib module mbrtoc32 for portability");
654# endif
655#endif
656
657
658/* Converts a multibyte character and returns the next 16-bit wide
659 character. */
660#if @GNULIB_MBRTOC16@
661# if @REPLACE_MBRTOC16@
662# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
663# undef mbrtoc16
664# define mbrtoc16 rpl_mbrtoc16
665# endif
666_GL_FUNCDECL_RPL (mbrtoc16, size_t,
667 (char16_t *pc, const char *s, size_t n, mbstate_t *ps), );
668_GL_CXXALIAS_RPL (mbrtoc16, size_t,
669 (char16_t *pc, const char *s, size_t n, mbstate_t *ps));
670# else
671# if !@HAVE_MBRTOC16@
672_GL_FUNCDECL_SYS (mbrtoc16, size_t,
673 (char16_t *pc, const char *s, size_t n, mbstate_t *ps), );
674# endif
675_GL_CXXALIAS_SYS (mbrtoc16, size_t,
676 (char16_t *pc, const char *s, size_t n, mbstate_t *ps));
677# endif
678# if __GLIBC__ + (__GLIBC_MINOR__ >= 16) > 2
679_GL_CXXALIASWARN (mbrtoc16);
680# endif
681#elif defined GNULIB_POSIXCHECK
682# undef mbrtoc16
683# if HAVE_RAW_DECL_MBRTOC16
684_GL_WARN_ON_USE (mbrtoc16, "mbrtoc16 is not portable - "
685 "use gnulib module mbrtoc16 for portability");
686# endif
687#endif
688
689
690/* Convert a string to a 32-bit wide string. */
691#if @GNULIB_MBSNRTOC32S@
692# if _GL_WCHAR_T_IS_UCS4 && !defined IN_MBSNRTOC32S
693_GL_BEGIN_C_LINKAGE
694_GL_INLINE _GL_ARG_NONNULL ((2)) size_t
695mbsnrtoc32s (char32_t *dest, const char **srcp, size_t srclen, size_t len,
696 mbstate_t *ps)
697{
698 return
699# if @GNULIB_MBSNRTOWCS@ && defined __cplusplus && defined GNULIB_NAMESPACE
700 GNULIB_NAMESPACE::
701# endif
702 mbsnrtowcs ((wchar_t *) dest, srcp, srclen, len, ps);
703}
704_GL_END_C_LINKAGE
705# else
706_GL_FUNCDECL_SYS (mbsnrtoc32s, size_t,
707 (char32_t *dest, const char **srcp, size_t srclen, size_t len,
708 mbstate_t *ps),
709 _GL_ARG_NONNULL ((2)));
710# endif
711_GL_CXXALIAS_SYS (mbsnrtoc32s, size_t,
712 (char32_t *dest, const char **srcp, size_t srclen, size_t len,
713 mbstate_t *ps));
714_GL_CXXALIASWARN (mbsnrtoc32s);
715#endif
716
717
718/* Convert a string to a 32-bit wide string. */
719#if @GNULIB_MBSRTOC32S@
720# if _GL_WCHAR_T_IS_UCS4 && !defined IN_MBSRTOC32S
721_GL_BEGIN_C_LINKAGE
722_GL_INLINE _GL_ARG_NONNULL ((2)) size_t
723mbsrtoc32s (char32_t *dest, const char **srcp, size_t len, mbstate_t *ps)
724{
725 return
726# if @GNULIB_MBSRTOWCS@ && defined __cplusplus && defined GNULIB_NAMESPACE
727 GNULIB_NAMESPACE::
728# endif
729 mbsrtowcs ((wchar_t *) dest, srcp, len, ps);
730}
731_GL_END_C_LINKAGE
732# else
733_GL_FUNCDECL_SYS (mbsrtoc32s, size_t,
734 (char32_t *dest, const char **srcp, size_t len,
735 mbstate_t *ps),
736 _GL_ARG_NONNULL ((2)));
737# endif
738_GL_CXXALIAS_SYS (mbsrtoc32s, size_t,
739 (char32_t *dest, const char **srcp, size_t len,
740 mbstate_t *ps));
741_GL_CXXALIASWARN (mbsrtoc32s);
742#endif
743
744
745/* Convert a string to a 32-bit wide string. */
746#if @GNULIB_MBSTOC32S@
747# if _GL_WCHAR_T_IS_UCS4 && !defined IN_MBSTOC32S
748_GL_BEGIN_C_LINKAGE
749_GL_INLINE _GL_ARG_NONNULL ((2)) size_t
750mbstoc32s (char32_t *dest, const char *src, size_t len)
751{
752 mbstate_t state;
753
754 mbszero (&state);
755 return mbsrtoc32s (dest, &src, len, &state);
756}
757_GL_END_C_LINKAGE
758# else
759_GL_FUNCDECL_SYS (mbstoc32s, size_t,
760 (char32_t *dest, const char *src, size_t len),
761 _GL_ARG_NONNULL ((2)));
762# endif
763_GL_CXXALIAS_SYS (mbstoc32s, size_t,
764 (char32_t *dest, const char *src, size_t len));
765_GL_CXXALIASWARN (mbstoc32s);
766#endif
767
768
769#if @GNULIB_C32_GET_TYPE_TEST@ || @GNULIB_C32_APPLY_TYPE_TEST@
770/* A scalar type. Instances of this type, other than (c32_type_test_t) 0,
771 represent a character property, sometimes also viewed as a "character class".
772 It can be applied to 32-bit wide characters. It is the counterpart of
773 type 'wctype_t' for wide characters.
774 To test whether a given character has a certain property, use the function
775 'c32_apply_type_test'. */
776# if _GL_WCHAR_T_IS_UCS4
777typedef wctype_t c32_type_test_t;
778# else
779typedef /*bool*/int (*c32_type_test_t) (wint_t wc);
780# endif
781#endif
782
783/* Return a character property with the given name, or (c32_type_test_t) 0
784 if the designated property does not exist.
785 This function is the counterpart of function 'wctype' for wide characters.
786 */
787#if @GNULIB_C32_GET_TYPE_TEST@
788# if _GL_WCHAR_T_IS_UCS4 && !defined IN_C32_GET_TYPE_TEST
789_GL_BEGIN_C_LINKAGE
790_GL_INLINE _GL_ARG_NONNULL ((1)) c32_type_test_t
791c32_get_type_test (const char *name)
792{
793 return
794# if @GNULIB_WCTYPE@ && defined __cplusplus && defined GNULIB_NAMESPACE
795 GNULIB_NAMESPACE::
796# endif
797 wctype (name);
798}
799_GL_END_C_LINKAGE
800# else
801_GL_FUNCDECL_SYS (c32_get_type_test, c32_type_test_t, (const char *name),
802 _GL_ARG_NONNULL ((1)));
803# endif
804_GL_CXXALIAS_SYS (c32_get_type_test, c32_type_test_t, (const char *name));
805_GL_CXXALIASWARN (c32_get_type_test);
806#endif
807
808/* Test whether a given 32-bit wide character has the specified character
809 property.
810 Return non-zero if true, zero if false or if the argument is WEOF.
811 This function is the counterpart of function 'iswctype' for wide characters.
812 */
813#if @GNULIB_C32_APPLY_TYPE_TEST@
814# if _GL_WCHAR_T_IS_UCS4
815# if !defined IN_C32_APPLY_TYPE_TEST
816_GL_BEGIN_C_LINKAGE
817_GL_INLINE int
818c32_apply_type_test (wint_t wc, c32_type_test_t property)
819{
820 return
821# if @GNULIB_ISWCTYPE@ && defined __cplusplus && defined GNULIB_NAMESPACE
822 GNULIB_NAMESPACE::
823# endif
824 iswctype (wc, property);
825}
826_GL_END_C_LINKAGE
827# else
828_GL_FUNCDECL_SYS (c32_apply_type_test, int,
829 (wint_t wc, c32_type_test_t property), );
830# endif
831# else
832_GL_FUNCDECL_SYS (c32_apply_type_test, int,
833 (wint_t wc, c32_type_test_t property),
834 _GL_ARG_NONNULL ((2)));
835# endif
836_GL_CXXALIAS_SYS (c32_apply_type_test, int,
837 (wint_t wc, c32_type_test_t property));
838_GL_CXXALIASWARN (c32_apply_type_test);
839#endif
840
841
842#if @GNULIB_C32_GET_MAPPING@ || @GNULIB_C32_APPLY_MAPPING@
843/* A scalar type. Instances of this type, other than (c32_mapping_t) 0,
844 represent a character mapping. It can be applied to 32-bit wide characters.
845 It is the counterpart of type 'wctrans_t' for wide characters.
846 To apply a certain mapping to a given character, use the function
847 'c32_apply_mapping'. */
848# if _GL_WCHAR_T_IS_UCS4
849typedef wctrans_t c32_mapping_t;
850# else
851typedef wint_t (*c32_mapping_t) (wint_t wc);
852# endif
853#endif
854
855/* Return a character mapping with the given name, or (c32_mapping_t) 0
856 if the designated mapping does not exist.
857 This function is the counterpart of function 'wctrans' for wide characters.
858 */
859#if @GNULIB_C32_GET_MAPPING@
860# if _GL_WCHAR_T_IS_UCS4 && !defined IN_C32_GET_MAPPING
861_GL_BEGIN_C_LINKAGE
862_GL_INLINE _GL_ARG_NONNULL ((1)) c32_mapping_t
863c32_get_mapping (const char *name)
864{
865 return
866# if @GNULIB_WCTRANS@ && defined __cplusplus && defined GNULIB_NAMESPACE
867 GNULIB_NAMESPACE::
868# endif
869 wctrans (name);
870}
871_GL_END_C_LINKAGE
872# else
873_GL_FUNCDECL_SYS (c32_get_mapping, c32_mapping_t, (const char *name),
874 _GL_ARG_NONNULL ((1)));
875# endif
876_GL_CXXALIAS_SYS (c32_get_mapping, c32_mapping_t, (const char *name));
877_GL_CXXALIASWARN (c32_get_mapping);
878#endif
879
880/* Apply the specified character mapping to a given 32-bit wide character.
881 Return the result of this mapping. Return the WC argument unchanged if it is
882 WEOF.
883 This function is the counterpart of function 'towctrans' for wide characters.
884 */
885#if @GNULIB_C32_APPLY_MAPPING@
886# if _GL_WCHAR_T_IS_UCS4 && !defined IN_C32_APPLY_MAPPING
887_GL_BEGIN_C_LINKAGE
888_GL_INLINE _GL_ARG_NONNULL ((2)) wint_t
889c32_apply_mapping (wint_t wc, c32_mapping_t mapping)
890{
891 return
892# if @GNULIB_TOWCTRANS@ && defined __cplusplus && defined GNULIB_NAMESPACE
893 GNULIB_NAMESPACE::
894# endif
895 towctrans (wc, mapping);
896}
897_GL_END_C_LINKAGE
898# else
899_GL_FUNCDECL_SYS (c32_apply_mapping, wint_t,
900 (wint_t wc, c32_mapping_t mapping),
901 _GL_ARG_NONNULL ((2)));
902# endif
903_GL_CXXALIAS_SYS (c32_apply_mapping, wint_t,
904 (wint_t wc, c32_mapping_t mapping));
905_GL_CXXALIASWARN (c32_apply_mapping);
906#endif
907
908
909_GL_INLINE_HEADER_END
910
911#endif /* _@GUARD_PREFIX@_UCHAR_H */
912#endif /* _@GUARD_PREFIX@_UCHAR_H */
diff --git a/gl/unicase.h b/gl/unicase.h
new file mode 100644
index 00000000..507a83d0
--- /dev/null
+++ b/gl/unicase.h
@@ -0,0 +1,472 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* Unicode character case mappings.
3 Copyright (C) 2002, 2009-2025 Free Software Foundation, Inc.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#ifndef _UNICASE_H
19#define _UNICASE_H
20
21#include "unitypes.h"
22
23/* Get bool. */
24#include <stdbool.h>
25
26/* Get size_t. */
27#include <stddef.h>
28
29/* Get uninorm_t. */
30#include "uninorm.h"
31
32#if 0
33# include <unistring/woe32dll.h>
34#else
35# define LIBUNISTRING_DLL_VARIABLE
36#endif
37
38#ifdef __cplusplus
39extern "C" {
40#endif
41
42/* ========================================================================= */
43
44/* Character case mappings.
45 These mappings are locale and context independent.
46 WARNING! These functions are not sufficient for languages such as German.
47 Better use the functions below that treat an entire string at once and are
48 language aware. */
49
50/* Return the uppercase mapping of a Unicode character. */
51extern ucs4_t
52 uc_toupper (ucs4_t uc)
53 _UC_ATTRIBUTE_CONST;
54
55/* Return the lowercase mapping of a Unicode character. */
56extern ucs4_t
57 uc_tolower (ucs4_t uc)
58 _UC_ATTRIBUTE_CONST;
59
60/* Return the titlecase mapping of a Unicode character. */
61extern ucs4_t
62 uc_totitle (ucs4_t uc)
63 _UC_ATTRIBUTE_CONST;
64
65/* ========================================================================= */
66
67/* String case mappings. */
68
69/* These functions are locale dependent. The iso639_language argument
70 identifies the language (e.g. "tr" for Turkish). NULL means to use
71 locale independent case mappings. */
72
73/* Return the ISO 639 language code of the current locale.
74 Return "" if it is unknown, or in the "C" locale. */
75extern const char *
76 uc_locale_language (void)
77 _UC_ATTRIBUTE_PURE;
78
79/* Conventions:
80
81 All functions prefixed with u8_ operate on UTF-8 encoded strings.
82 Their unit is an uint8_t (1 byte).
83
84 All functions prefixed with u16_ operate on UTF-16 encoded strings.
85 Their unit is an uint16_t (a 2-byte word).
86
87 All functions prefixed with u32_ operate on UCS-4 encoded strings.
88 Their unit is an uint32_t (a 4-byte word).
89
90 All argument pairs (s, n) denote a Unicode string s[0..n-1] with exactly
91 n units.
92
93 Functions returning a string result take a (resultbuf, lengthp) argument
94 pair. If resultbuf is not NULL and the result fits into *lengthp units,
95 it is put in resultbuf, and resultbuf is returned. Otherwise, a freshly
96 allocated string is returned. In both cases, *lengthp is set to the
97 length (number of units) of the returned string. In case of error,
98 NULL is returned and errno is set. */
99
100/* Return the uppercase mapping of a string.
101 The nf argument identifies the normalization form to apply after the
102 case-mapping. It can also be NULL, for no normalization. */
103extern uint8_t *
104 u8_toupper (const uint8_t *s, size_t n, const char *iso639_language,
105 uninorm_t nf,
106 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
107extern uint16_t *
108 u16_toupper (const uint16_t *s, size_t n, const char *iso639_language,
109 uninorm_t nf,
110 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
111extern uint32_t *
112 u32_toupper (const uint32_t *s, size_t n, const char *iso639_language,
113 uninorm_t nf,
114 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
115
116/* Return the lowercase mapping of a string.
117 The nf argument identifies the normalization form to apply after the
118 case-mapping. It can also be NULL, for no normalization. */
119extern uint8_t *
120 u8_tolower (const uint8_t *s, size_t n, const char *iso639_language,
121 uninorm_t nf,
122 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
123extern uint16_t *
124 u16_tolower (const uint16_t *s, size_t n, const char *iso639_language,
125 uninorm_t nf,
126 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
127extern uint32_t *
128 u32_tolower (const uint32_t *s, size_t n, const char *iso639_language,
129 uninorm_t nf,
130 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
131
132/* Return the titlecase mapping of a string.
133 The nf argument identifies the normalization form to apply after the
134 case-mapping. It can also be NULL, for no normalization. */
135extern uint8_t *
136 u8_totitle (const uint8_t *s, size_t n, const char *iso639_language,
137 uninorm_t nf,
138 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
139extern uint16_t *
140 u16_totitle (const uint16_t *s, size_t n, const char *iso639_language,
141 uninorm_t nf,
142 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
143extern uint32_t *
144 u32_totitle (const uint32_t *s, size_t n, const char *iso639_language,
145 uninorm_t nf,
146 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
147
148/* The case-mapping context given by a prefix string. */
149typedef struct casing_prefix_context
150 {
151 /* These fields are private, undocumented. */
152 uint32_t last_char_except_ignorable;
153 uint32_t last_char_normal_or_above;
154 }
155 casing_prefix_context_t;
156/* The case-mapping context of the empty prefix string. */
157extern LIBUNISTRING_DLL_VARIABLE const casing_prefix_context_t unicase_empty_prefix_context;
158/* Return the case-mapping context of a given prefix string. */
159extern casing_prefix_context_t
160 u8_casing_prefix_context (const uint8_t *s, size_t n);
161extern casing_prefix_context_t
162 u16_casing_prefix_context (const uint16_t *s, size_t n);
163extern casing_prefix_context_t
164 u32_casing_prefix_context (const uint32_t *s, size_t n);
165/* Return the case-mapping context of the prefix concat(A, S), given the
166 case-mapping context of the prefix A. */
167extern casing_prefix_context_t
168 u8_casing_prefixes_context (const uint8_t *s, size_t n,
169 casing_prefix_context_t a_context);
170extern casing_prefix_context_t
171 u16_casing_prefixes_context (const uint16_t *s, size_t n,
172 casing_prefix_context_t a_context);
173extern casing_prefix_context_t
174 u32_casing_prefixes_context (const uint32_t *s, size_t n,
175 casing_prefix_context_t a_context);
176
177/* The case-mapping context given by a suffix string. */
178typedef struct casing_suffix_context
179 {
180 /* These fields are private, undocumented. */
181 uint32_t first_char_except_ignorable;
182 uint32_t bits;
183 }
184 casing_suffix_context_t;
185/* The case-mapping context of the empty suffix string. */
186extern LIBUNISTRING_DLL_VARIABLE const casing_suffix_context_t unicase_empty_suffix_context;
187/* Return the case-mapping context of a given suffix string. */
188extern casing_suffix_context_t
189 u8_casing_suffix_context (const uint8_t *s, size_t n);
190extern casing_suffix_context_t
191 u16_casing_suffix_context (const uint16_t *s, size_t n);
192extern casing_suffix_context_t
193 u32_casing_suffix_context (const uint32_t *s, size_t n);
194/* Return the case-mapping context of the suffix concat(S, A), given the
195 case-mapping context of the suffix A. */
196extern casing_suffix_context_t
197 u8_casing_suffixes_context (const uint8_t *s, size_t n,
198 casing_suffix_context_t a_context);
199extern casing_suffix_context_t
200 u16_casing_suffixes_context (const uint16_t *s, size_t n,
201 casing_suffix_context_t a_context);
202extern casing_suffix_context_t
203 u32_casing_suffixes_context (const uint32_t *s, size_t n,
204 casing_suffix_context_t a_context);
205
206/* Return the uppercase mapping of a string that is surrounded by a prefix
207 and a suffix. */
208extern uint8_t *
209 u8_ct_toupper (const uint8_t *s, size_t n,
210 casing_prefix_context_t prefix_context,
211 casing_suffix_context_t suffix_context,
212 const char *iso639_language,
213 uninorm_t nf,
214 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
215extern uint16_t *
216 u16_ct_toupper (const uint16_t *s, size_t n,
217 casing_prefix_context_t prefix_context,
218 casing_suffix_context_t suffix_context,
219 const char *iso639_language,
220 uninorm_t nf,
221 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
222extern uint32_t *
223 u32_ct_toupper (const uint32_t *s, size_t n,
224 casing_prefix_context_t prefix_context,
225 casing_suffix_context_t suffix_context,
226 const char *iso639_language,
227 uninorm_t nf,
228 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
229
230/* Return the lowercase mapping of a string that is surrounded by a prefix
231 and a suffix. */
232extern uint8_t *
233 u8_ct_tolower (const uint8_t *s, size_t n,
234 casing_prefix_context_t prefix_context,
235 casing_suffix_context_t suffix_context,
236 const char *iso639_language,
237 uninorm_t nf,
238 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
239extern uint16_t *
240 u16_ct_tolower (const uint16_t *s, size_t n,
241 casing_prefix_context_t prefix_context,
242 casing_suffix_context_t suffix_context,
243 const char *iso639_language,
244 uninorm_t nf,
245 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
246extern uint32_t *
247 u32_ct_tolower (const uint32_t *s, size_t n,
248 casing_prefix_context_t prefix_context,
249 casing_suffix_context_t suffix_context,
250 const char *iso639_language,
251 uninorm_t nf,
252 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
253
254/* Return the titlecase mapping of a string that is surrounded by a prefix
255 and a suffix. */
256extern uint8_t *
257 u8_ct_totitle (const uint8_t *s, size_t n,
258 casing_prefix_context_t prefix_context,
259 casing_suffix_context_t suffix_context,
260 const char *iso639_language,
261 uninorm_t nf,
262 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
263extern uint16_t *
264 u16_ct_totitle (const uint16_t *s, size_t n,
265 casing_prefix_context_t prefix_context,
266 casing_suffix_context_t suffix_context,
267 const char *iso639_language,
268 uninorm_t nf,
269 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
270extern uint32_t *
271 u32_ct_totitle (const uint32_t *s, size_t n,
272 casing_prefix_context_t prefix_context,
273 casing_suffix_context_t suffix_context,
274 const char *iso639_language,
275 uninorm_t nf,
276 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
277
278/* Return the case folded string.
279 Comparing uN_casefold (S1) and uN_casefold (S2) with uN_cmp2() is equivalent
280 to comparing S1 and S2 with uN_casecmp().
281 The nf argument identifies the normalization form to apply after the
282 case-mapping. It can also be NULL, for no normalization. */
283extern uint8_t *
284 u8_casefold (const uint8_t *s, size_t n, const char *iso639_language,
285 uninorm_t nf,
286 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
287extern uint16_t *
288 u16_casefold (const uint16_t *s, size_t n, const char *iso639_language,
289 uninorm_t nf,
290 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
291extern uint32_t *
292 u32_casefold (const uint32_t *s, size_t n, const char *iso639_language,
293 uninorm_t nf,
294 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
295/* Likewise, for a string that is surrounded by a prefix and a suffix. */
296extern uint8_t *
297 u8_ct_casefold (const uint8_t *s, size_t n,
298 casing_prefix_context_t prefix_context,
299 casing_suffix_context_t suffix_context,
300 const char *iso639_language,
301 uninorm_t nf,
302 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
303extern uint16_t *
304 u16_ct_casefold (const uint16_t *s, size_t n,
305 casing_prefix_context_t prefix_context,
306 casing_suffix_context_t suffix_context,
307 const char *iso639_language,
308 uninorm_t nf,
309 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
310extern uint32_t *
311 u32_ct_casefold (const uint32_t *s, size_t n,
312 casing_prefix_context_t prefix_context,
313 casing_suffix_context_t suffix_context,
314 const char *iso639_language,
315 uninorm_t nf,
316 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
317
318/* Compare S1 and S2, ignoring differences in case and normalization.
319 The nf argument identifies the normalization form to apply after the
320 case-mapping. It can also be NULL, for no normalization.
321 If successful, set *RESULTP to -1 if S1 < S2, 0 if S1 = S2, 1 if S1 > S2, and
322 return 0. Upon failure, return -1 with errno set. */
323extern int
324 u8_casecmp (const uint8_t *s1, size_t n1,
325 const uint8_t *s2, size_t n2,
326 const char *iso639_language, uninorm_t nf, int *resultp);
327extern int
328 u16_casecmp (const uint16_t *s1, size_t n1,
329 const uint16_t *s2, size_t n2,
330 const char *iso639_language, uninorm_t nf, int *resultp);
331extern int
332 u32_casecmp (const uint32_t *s1, size_t n1,
333 const uint32_t *s2, size_t n2,
334 const char *iso639_language, uninorm_t nf, int *resultp);
335extern int
336 ulc_casecmp (const char *s1, size_t n1,
337 const char *s2, size_t n2,
338 const char *iso639_language, uninorm_t nf, int *resultp);
339
340/* Convert the string S of length N to a NUL-terminated byte sequence, in such
341 a way that comparing uN_casexfrm (S1) and uN_casexfrm (S2) with the gnulib
342 function memcmp2() is equivalent to comparing S1 and S2 with uN_casecoll().
343 NF must be either UNINORM_NFC, UNINORM_NFKC, or NULL for no normalization. */
344extern char *
345 u8_casexfrm (const uint8_t *s, size_t n, const char *iso639_language,
346 uninorm_t nf,
347 char *_UC_RESTRICT resultbuf, size_t *lengthp);
348extern char *
349 u16_casexfrm (const uint16_t *s, size_t n, const char *iso639_language,
350 uninorm_t nf,
351 char *_UC_RESTRICT resultbuf, size_t *lengthp);
352extern char *
353 u32_casexfrm (const uint32_t *s, size_t n, const char *iso639_language,
354 uninorm_t nf,
355 char *_UC_RESTRICT resultbuf, size_t *lengthp);
356extern char *
357 ulc_casexfrm (const char *s, size_t n, const char *iso639_language,
358 uninorm_t nf,
359 char *_UC_RESTRICT resultbuf, size_t *lengthp);
360
361/* Compare S1 and S2, ignoring differences in case and normalization, using the
362 collation rules of the current locale.
363 The nf argument identifies the normalization form to apply after the
364 case-mapping. It must be either UNINORM_NFC or UNINORM_NFKC. It can also
365 be NULL, for no normalization.
366 If successful, set *RESULTP to -1 if S1 < S2, 0 if S1 = S2, 1 if S1 > S2, and
367 return 0. Upon failure, return -1 with errno set. */
368extern int
369 u8_casecoll (const uint8_t *s1, size_t n1,
370 const uint8_t *s2, size_t n2,
371 const char *iso639_language, uninorm_t nf, int *resultp);
372extern int
373 u16_casecoll (const uint16_t *s1, size_t n1,
374 const uint16_t *s2, size_t n2,
375 const char *iso639_language, uninorm_t nf, int *resultp);
376extern int
377 u32_casecoll (const uint32_t *s1, size_t n1,
378 const uint32_t *s2, size_t n2,
379 const char *iso639_language, uninorm_t nf, int *resultp);
380extern int
381 ulc_casecoll (const char *s1, size_t n1,
382 const char *s2, size_t n2,
383 const char *iso639_language, uninorm_t nf, int *resultp);
384
385
386/* Set *RESULTP to true if mapping NFD(S) to upper case is a no-op, or to false
387 otherwise, and return 0. Upon failure, return -1 with errno set. */
388extern int
389 u8_is_uppercase (const uint8_t *s, size_t n,
390 const char *iso639_language,
391 bool *resultp);
392extern int
393 u16_is_uppercase (const uint16_t *s, size_t n,
394 const char *iso639_language,
395 bool *resultp);
396extern int
397 u32_is_uppercase (const uint32_t *s, size_t n,
398 const char *iso639_language,
399 bool *resultp);
400
401/* Set *RESULTP to true if mapping NFD(S) to lower case is a no-op, or to false
402 otherwise, and return 0. Upon failure, return -1 with errno set. */
403extern int
404 u8_is_lowercase (const uint8_t *s, size_t n,
405 const char *iso639_language,
406 bool *resultp);
407extern int
408 u16_is_lowercase (const uint16_t *s, size_t n,
409 const char *iso639_language,
410 bool *resultp);
411extern int
412 u32_is_lowercase (const uint32_t *s, size_t n,
413 const char *iso639_language,
414 bool *resultp);
415
416/* Set *RESULTP to true if mapping NFD(S) to title case is a no-op, or to false
417 otherwise, and return 0. Upon failure, return -1 with errno set. */
418extern int
419 u8_is_titlecase (const uint8_t *s, size_t n,
420 const char *iso639_language,
421 bool *resultp);
422extern int
423 u16_is_titlecase (const uint16_t *s, size_t n,
424 const char *iso639_language,
425 bool *resultp);
426extern int
427 u32_is_titlecase (const uint32_t *s, size_t n,
428 const char *iso639_language,
429 bool *resultp);
430
431/* Set *RESULTP to true if applying case folding to NFD(S) is a no-op, or to
432 false otherwise, and return 0. Upon failure, return -1 with errno set. */
433extern int
434 u8_is_casefolded (const uint8_t *s, size_t n,
435 const char *iso639_language,
436 bool *resultp);
437extern int
438 u16_is_casefolded (const uint16_t *s, size_t n,
439 const char *iso639_language,
440 bool *resultp);
441extern int
442 u32_is_casefolded (const uint32_t *s, size_t n,
443 const char *iso639_language,
444 bool *resultp);
445
446/* Set *RESULTP to true if case matters for S, that is, if mapping NFD(S) to
447 either upper case or lower case or title case is not a no-op.
448 Set *RESULTP to false if NFD(S) maps to itself under the upper case mapping,
449 under the lower case mapping, and under the title case mapping; in other
450 words, when NFD(S) consists entirely of caseless characters.
451 Upon failure, return -1 with errno set. */
452extern int
453 u8_is_cased (const uint8_t *s, size_t n,
454 const char *iso639_language,
455 bool *resultp);
456extern int
457 u16_is_cased (const uint16_t *s, size_t n,
458 const char *iso639_language,
459 bool *resultp);
460extern int
461 u32_is_cased (const uint32_t *s, size_t n,
462 const char *iso639_language,
463 bool *resultp);
464
465
466/* ========================================================================= */
467
468#ifdef __cplusplus
469}
470#endif
471
472#endif /* _UNICASE_H */
diff --git a/gl/unicase.in.h b/gl/unicase.in.h
new file mode 100644
index 00000000..c6df04b3
--- /dev/null
+++ b/gl/unicase.in.h
@@ -0,0 +1,471 @@
1/* Unicode character case mappings.
2 Copyright (C) 2002, 2009-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#ifndef _UNICASE_H
18#define _UNICASE_H
19
20#include "unitypes.h"
21
22/* Get bool. */
23#include <stdbool.h>
24
25/* Get size_t. */
26#include <stddef.h>
27
28/* Get uninorm_t. */
29#include "uninorm.h"
30
31#if @HAVE_UNISTRING_WOE32DLL_H@
32# include <unistring/woe32dll.h>
33#else
34# define LIBUNISTRING_DLL_VARIABLE
35#endif
36
37#ifdef __cplusplus
38extern "C" {
39#endif
40
41/* ========================================================================= */
42
43/* Character case mappings.
44 These mappings are locale and context independent.
45 WARNING! These functions are not sufficient for languages such as German.
46 Better use the functions below that treat an entire string at once and are
47 language aware. */
48
49/* Return the uppercase mapping of a Unicode character. */
50extern ucs4_t
51 uc_toupper (ucs4_t uc)
52 _UC_ATTRIBUTE_CONST;
53
54/* Return the lowercase mapping of a Unicode character. */
55extern ucs4_t
56 uc_tolower (ucs4_t uc)
57 _UC_ATTRIBUTE_CONST;
58
59/* Return the titlecase mapping of a Unicode character. */
60extern ucs4_t
61 uc_totitle (ucs4_t uc)
62 _UC_ATTRIBUTE_CONST;
63
64/* ========================================================================= */
65
66/* String case mappings. */
67
68/* These functions are locale dependent. The iso639_language argument
69 identifies the language (e.g. "tr" for Turkish). NULL means to use
70 locale independent case mappings. */
71
72/* Return the ISO 639 language code of the current locale.
73 Return "" if it is unknown, or in the "C" locale. */
74extern const char *
75 uc_locale_language (void)
76 _UC_ATTRIBUTE_PURE;
77
78/* Conventions:
79
80 All functions prefixed with u8_ operate on UTF-8 encoded strings.
81 Their unit is an uint8_t (1 byte).
82
83 All functions prefixed with u16_ operate on UTF-16 encoded strings.
84 Their unit is an uint16_t (a 2-byte word).
85
86 All functions prefixed with u32_ operate on UCS-4 encoded strings.
87 Their unit is an uint32_t (a 4-byte word).
88
89 All argument pairs (s, n) denote a Unicode string s[0..n-1] with exactly
90 n units.
91
92 Functions returning a string result take a (resultbuf, lengthp) argument
93 pair. If resultbuf is not NULL and the result fits into *lengthp units,
94 it is put in resultbuf, and resultbuf is returned. Otherwise, a freshly
95 allocated string is returned. In both cases, *lengthp is set to the
96 length (number of units) of the returned string. In case of error,
97 NULL is returned and errno is set. */
98
99/* Return the uppercase mapping of a string.
100 The nf argument identifies the normalization form to apply after the
101 case-mapping. It can also be NULL, for no normalization. */
102extern uint8_t *
103 u8_toupper (const uint8_t *s, size_t n, const char *iso639_language,
104 uninorm_t nf,
105 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
106extern uint16_t *
107 u16_toupper (const uint16_t *s, size_t n, const char *iso639_language,
108 uninorm_t nf,
109 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
110extern uint32_t *
111 u32_toupper (const uint32_t *s, size_t n, const char *iso639_language,
112 uninorm_t nf,
113 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
114
115/* Return the lowercase mapping of a string.
116 The nf argument identifies the normalization form to apply after the
117 case-mapping. It can also be NULL, for no normalization. */
118extern uint8_t *
119 u8_tolower (const uint8_t *s, size_t n, const char *iso639_language,
120 uninorm_t nf,
121 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
122extern uint16_t *
123 u16_tolower (const uint16_t *s, size_t n, const char *iso639_language,
124 uninorm_t nf,
125 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
126extern uint32_t *
127 u32_tolower (const uint32_t *s, size_t n, const char *iso639_language,
128 uninorm_t nf,
129 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
130
131/* Return the titlecase mapping of a string.
132 The nf argument identifies the normalization form to apply after the
133 case-mapping. It can also be NULL, for no normalization. */
134extern uint8_t *
135 u8_totitle (const uint8_t *s, size_t n, const char *iso639_language,
136 uninorm_t nf,
137 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
138extern uint16_t *
139 u16_totitle (const uint16_t *s, size_t n, const char *iso639_language,
140 uninorm_t nf,
141 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
142extern uint32_t *
143 u32_totitle (const uint32_t *s, size_t n, const char *iso639_language,
144 uninorm_t nf,
145 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
146
147/* The case-mapping context given by a prefix string. */
148typedef struct casing_prefix_context
149 {
150 /* These fields are private, undocumented. */
151 uint32_t last_char_except_ignorable;
152 uint32_t last_char_normal_or_above;
153 }
154 casing_prefix_context_t;
155/* The case-mapping context of the empty prefix string. */
156extern @GNULIB_UNICASE_EMPTY_PREFIX_CONTEXT_DLL_VARIABLE@ const casing_prefix_context_t unicase_empty_prefix_context;
157/* Return the case-mapping context of a given prefix string. */
158extern casing_prefix_context_t
159 u8_casing_prefix_context (const uint8_t *s, size_t n);
160extern casing_prefix_context_t
161 u16_casing_prefix_context (const uint16_t *s, size_t n);
162extern casing_prefix_context_t
163 u32_casing_prefix_context (const uint32_t *s, size_t n);
164/* Return the case-mapping context of the prefix concat(A, S), given the
165 case-mapping context of the prefix A. */
166extern casing_prefix_context_t
167 u8_casing_prefixes_context (const uint8_t *s, size_t n,
168 casing_prefix_context_t a_context);
169extern casing_prefix_context_t
170 u16_casing_prefixes_context (const uint16_t *s, size_t n,
171 casing_prefix_context_t a_context);
172extern casing_prefix_context_t
173 u32_casing_prefixes_context (const uint32_t *s, size_t n,
174 casing_prefix_context_t a_context);
175
176/* The case-mapping context given by a suffix string. */
177typedef struct casing_suffix_context
178 {
179 /* These fields are private, undocumented. */
180 uint32_t first_char_except_ignorable;
181 uint32_t bits;
182 }
183 casing_suffix_context_t;
184/* The case-mapping context of the empty suffix string. */
185extern @GNULIB_UNICASE_EMPTY_SUFFIX_CONTEXT_DLL_VARIABLE@ const casing_suffix_context_t unicase_empty_suffix_context;
186/* Return the case-mapping context of a given suffix string. */
187extern casing_suffix_context_t
188 u8_casing_suffix_context (const uint8_t *s, size_t n);
189extern casing_suffix_context_t
190 u16_casing_suffix_context (const uint16_t *s, size_t n);
191extern casing_suffix_context_t
192 u32_casing_suffix_context (const uint32_t *s, size_t n);
193/* Return the case-mapping context of the suffix concat(S, A), given the
194 case-mapping context of the suffix A. */
195extern casing_suffix_context_t
196 u8_casing_suffixes_context (const uint8_t *s, size_t n,
197 casing_suffix_context_t a_context);
198extern casing_suffix_context_t
199 u16_casing_suffixes_context (const uint16_t *s, size_t n,
200 casing_suffix_context_t a_context);
201extern casing_suffix_context_t
202 u32_casing_suffixes_context (const uint32_t *s, size_t n,
203 casing_suffix_context_t a_context);
204
205/* Return the uppercase mapping of a string that is surrounded by a prefix
206 and a suffix. */
207extern uint8_t *
208 u8_ct_toupper (const uint8_t *s, size_t n,
209 casing_prefix_context_t prefix_context,
210 casing_suffix_context_t suffix_context,
211 const char *iso639_language,
212 uninorm_t nf,
213 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
214extern uint16_t *
215 u16_ct_toupper (const uint16_t *s, size_t n,
216 casing_prefix_context_t prefix_context,
217 casing_suffix_context_t suffix_context,
218 const char *iso639_language,
219 uninorm_t nf,
220 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
221extern uint32_t *
222 u32_ct_toupper (const uint32_t *s, size_t n,
223 casing_prefix_context_t prefix_context,
224 casing_suffix_context_t suffix_context,
225 const char *iso639_language,
226 uninorm_t nf,
227 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
228
229/* Return the lowercase mapping of a string that is surrounded by a prefix
230 and a suffix. */
231extern uint8_t *
232 u8_ct_tolower (const uint8_t *s, size_t n,
233 casing_prefix_context_t prefix_context,
234 casing_suffix_context_t suffix_context,
235 const char *iso639_language,
236 uninorm_t nf,
237 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
238extern uint16_t *
239 u16_ct_tolower (const uint16_t *s, size_t n,
240 casing_prefix_context_t prefix_context,
241 casing_suffix_context_t suffix_context,
242 const char *iso639_language,
243 uninorm_t nf,
244 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
245extern uint32_t *
246 u32_ct_tolower (const uint32_t *s, size_t n,
247 casing_prefix_context_t prefix_context,
248 casing_suffix_context_t suffix_context,
249 const char *iso639_language,
250 uninorm_t nf,
251 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
252
253/* Return the titlecase mapping of a string that is surrounded by a prefix
254 and a suffix. */
255extern uint8_t *
256 u8_ct_totitle (const uint8_t *s, size_t n,
257 casing_prefix_context_t prefix_context,
258 casing_suffix_context_t suffix_context,
259 const char *iso639_language,
260 uninorm_t nf,
261 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
262extern uint16_t *
263 u16_ct_totitle (const uint16_t *s, size_t n,
264 casing_prefix_context_t prefix_context,
265 casing_suffix_context_t suffix_context,
266 const char *iso639_language,
267 uninorm_t nf,
268 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
269extern uint32_t *
270 u32_ct_totitle (const uint32_t *s, size_t n,
271 casing_prefix_context_t prefix_context,
272 casing_suffix_context_t suffix_context,
273 const char *iso639_language,
274 uninorm_t nf,
275 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
276
277/* Return the case folded string.
278 Comparing uN_casefold (S1) and uN_casefold (S2) with uN_cmp2() is equivalent
279 to comparing S1 and S2 with uN_casecmp().
280 The nf argument identifies the normalization form to apply after the
281 case-mapping. It can also be NULL, for no normalization. */
282extern uint8_t *
283 u8_casefold (const uint8_t *s, size_t n, const char *iso639_language,
284 uninorm_t nf,
285 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
286extern uint16_t *
287 u16_casefold (const uint16_t *s, size_t n, const char *iso639_language,
288 uninorm_t nf,
289 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
290extern uint32_t *
291 u32_casefold (const uint32_t *s, size_t n, const char *iso639_language,
292 uninorm_t nf,
293 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
294/* Likewise, for a string that is surrounded by a prefix and a suffix. */
295extern uint8_t *
296 u8_ct_casefold (const uint8_t *s, size_t n,
297 casing_prefix_context_t prefix_context,
298 casing_suffix_context_t suffix_context,
299 const char *iso639_language,
300 uninorm_t nf,
301 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
302extern uint16_t *
303 u16_ct_casefold (const uint16_t *s, size_t n,
304 casing_prefix_context_t prefix_context,
305 casing_suffix_context_t suffix_context,
306 const char *iso639_language,
307 uninorm_t nf,
308 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
309extern uint32_t *
310 u32_ct_casefold (const uint32_t *s, size_t n,
311 casing_prefix_context_t prefix_context,
312 casing_suffix_context_t suffix_context,
313 const char *iso639_language,
314 uninorm_t nf,
315 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
316
317/* Compare S1 and S2, ignoring differences in case and normalization.
318 The nf argument identifies the normalization form to apply after the
319 case-mapping. It can also be NULL, for no normalization.
320 If successful, set *RESULTP to -1 if S1 < S2, 0 if S1 = S2, 1 if S1 > S2, and
321 return 0. Upon failure, return -1 with errno set. */
322extern int
323 u8_casecmp (const uint8_t *s1, size_t n1,
324 const uint8_t *s2, size_t n2,
325 const char *iso639_language, uninorm_t nf, int *resultp);
326extern int
327 u16_casecmp (const uint16_t *s1, size_t n1,
328 const uint16_t *s2, size_t n2,
329 const char *iso639_language, uninorm_t nf, int *resultp);
330extern int
331 u32_casecmp (const uint32_t *s1, size_t n1,
332 const uint32_t *s2, size_t n2,
333 const char *iso639_language, uninorm_t nf, int *resultp);
334extern int
335 ulc_casecmp (const char *s1, size_t n1,
336 const char *s2, size_t n2,
337 const char *iso639_language, uninorm_t nf, int *resultp);
338
339/* Convert the string S of length N to a NUL-terminated byte sequence, in such
340 a way that comparing uN_casexfrm (S1) and uN_casexfrm (S2) with the gnulib
341 function memcmp2() is equivalent to comparing S1 and S2 with uN_casecoll().
342 NF must be either UNINORM_NFC, UNINORM_NFKC, or NULL for no normalization. */
343extern char *
344 u8_casexfrm (const uint8_t *s, size_t n, const char *iso639_language,
345 uninorm_t nf,
346 char *_UC_RESTRICT resultbuf, size_t *lengthp);
347extern char *
348 u16_casexfrm (const uint16_t *s, size_t n, const char *iso639_language,
349 uninorm_t nf,
350 char *_UC_RESTRICT resultbuf, size_t *lengthp);
351extern char *
352 u32_casexfrm (const uint32_t *s, size_t n, const char *iso639_language,
353 uninorm_t nf,
354 char *_UC_RESTRICT resultbuf, size_t *lengthp);
355extern char *
356 ulc_casexfrm (const char *s, size_t n, const char *iso639_language,
357 uninorm_t nf,
358 char *_UC_RESTRICT resultbuf, size_t *lengthp);
359
360/* Compare S1 and S2, ignoring differences in case and normalization, using the
361 collation rules of the current locale.
362 The nf argument identifies the normalization form to apply after the
363 case-mapping. It must be either UNINORM_NFC or UNINORM_NFKC. It can also
364 be NULL, for no normalization.
365 If successful, set *RESULTP to -1 if S1 < S2, 0 if S1 = S2, 1 if S1 > S2, and
366 return 0. Upon failure, return -1 with errno set. */
367extern int
368 u8_casecoll (const uint8_t *s1, size_t n1,
369 const uint8_t *s2, size_t n2,
370 const char *iso639_language, uninorm_t nf, int *resultp);
371extern int
372 u16_casecoll (const uint16_t *s1, size_t n1,
373 const uint16_t *s2, size_t n2,
374 const char *iso639_language, uninorm_t nf, int *resultp);
375extern int
376 u32_casecoll (const uint32_t *s1, size_t n1,
377 const uint32_t *s2, size_t n2,
378 const char *iso639_language, uninorm_t nf, int *resultp);
379extern int
380 ulc_casecoll (const char *s1, size_t n1,
381 const char *s2, size_t n2,
382 const char *iso639_language, uninorm_t nf, int *resultp);
383
384
385/* Set *RESULTP to true if mapping NFD(S) to upper case is a no-op, or to false
386 otherwise, and return 0. Upon failure, return -1 with errno set. */
387extern int
388 u8_is_uppercase (const uint8_t *s, size_t n,
389 const char *iso639_language,
390 bool *resultp);
391extern int
392 u16_is_uppercase (const uint16_t *s, size_t n,
393 const char *iso639_language,
394 bool *resultp);
395extern int
396 u32_is_uppercase (const uint32_t *s, size_t n,
397 const char *iso639_language,
398 bool *resultp);
399
400/* Set *RESULTP to true if mapping NFD(S) to lower case is a no-op, or to false
401 otherwise, and return 0. Upon failure, return -1 with errno set. */
402extern int
403 u8_is_lowercase (const uint8_t *s, size_t n,
404 const char *iso639_language,
405 bool *resultp);
406extern int
407 u16_is_lowercase (const uint16_t *s, size_t n,
408 const char *iso639_language,
409 bool *resultp);
410extern int
411 u32_is_lowercase (const uint32_t *s, size_t n,
412 const char *iso639_language,
413 bool *resultp);
414
415/* Set *RESULTP to true if mapping NFD(S) to title case is a no-op, or to false
416 otherwise, and return 0. Upon failure, return -1 with errno set. */
417extern int
418 u8_is_titlecase (const uint8_t *s, size_t n,
419 const char *iso639_language,
420 bool *resultp);
421extern int
422 u16_is_titlecase (const uint16_t *s, size_t n,
423 const char *iso639_language,
424 bool *resultp);
425extern int
426 u32_is_titlecase (const uint32_t *s, size_t n,
427 const char *iso639_language,
428 bool *resultp);
429
430/* Set *RESULTP to true if applying case folding to NFD(S) is a no-op, or to
431 false otherwise, and return 0. Upon failure, return -1 with errno set. */
432extern int
433 u8_is_casefolded (const uint8_t *s, size_t n,
434 const char *iso639_language,
435 bool *resultp);
436extern int
437 u16_is_casefolded (const uint16_t *s, size_t n,
438 const char *iso639_language,
439 bool *resultp);
440extern int
441 u32_is_casefolded (const uint32_t *s, size_t n,
442 const char *iso639_language,
443 bool *resultp);
444
445/* Set *RESULTP to true if case matters for S, that is, if mapping NFD(S) to
446 either upper case or lower case or title case is not a no-op.
447 Set *RESULTP to false if NFD(S) maps to itself under the upper case mapping,
448 under the lower case mapping, and under the title case mapping; in other
449 words, when NFD(S) consists entirely of caseless characters.
450 Upon failure, return -1 with errno set. */
451extern int
452 u8_is_cased (const uint8_t *s, size_t n,
453 const char *iso639_language,
454 bool *resultp);
455extern int
456 u16_is_cased (const uint16_t *s, size_t n,
457 const char *iso639_language,
458 bool *resultp);
459extern int
460 u32_is_cased (const uint32_t *s, size_t n,
461 const char *iso639_language,
462 bool *resultp);
463
464
465/* ========================================================================= */
466
467#ifdef __cplusplus
468}
469#endif
470
471#endif /* _UNICASE_H */
diff --git a/gl/unicase/.deps/.dirstamp b/gl/unicase/.deps/.dirstamp
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gl/unicase/.deps/.dirstamp
diff --git a/gl/unicase/.deps/libgnu_a-tolower.Po b/gl/unicase/.deps/libgnu_a-tolower.Po
new file mode 100644
index 00000000..1ba6bacb
--- /dev/null
+++ b/gl/unicase/.deps/libgnu_a-tolower.Po
@@ -0,0 +1,49 @@
1unicase/libgnu_a-tolower.o: unicase/tolower.c /usr/include/stdc-predef.h \
2 ../config.h unicase.h unitypes.h \
3 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h /usr/include/stdint.h \
4 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
5 /usr/include/features.h /usr/include/features-time64.h \
6 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
7 /usr/include/x86_64-linux-gnu/bits/timesize.h \
8 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
9 /usr/include/x86_64-linux-gnu/bits/long-double.h \
10 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
11 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
12 /usr/include/x86_64-linux-gnu/bits/types.h \
13 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
14 /usr/include/x86_64-linux-gnu/bits/time64.h \
15 /usr/include/x86_64-linux-gnu/bits/wchar.h \
16 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
17 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
18 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
19 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h stddef.h \
20 /usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h uninorm.h \
21 unicase/tolower.h unicase/simple-mapping.h
22/usr/include/stdc-predef.h:
23../config.h:
24unicase.h:
25unitypes.h:
26/usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h:
27/usr/include/stdint.h:
28/usr/include/x86_64-linux-gnu/bits/libc-header-start.h:
29/usr/include/features.h:
30/usr/include/features-time64.h:
31/usr/include/x86_64-linux-gnu/bits/wordsize.h:
32/usr/include/x86_64-linux-gnu/bits/timesize.h:
33/usr/include/x86_64-linux-gnu/sys/cdefs.h:
34/usr/include/x86_64-linux-gnu/bits/long-double.h:
35/usr/include/x86_64-linux-gnu/gnu/stubs.h:
36/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
37/usr/include/x86_64-linux-gnu/bits/types.h:
38/usr/include/x86_64-linux-gnu/bits/typesizes.h:
39/usr/include/x86_64-linux-gnu/bits/time64.h:
40/usr/include/x86_64-linux-gnu/bits/wchar.h:
41/usr/include/x86_64-linux-gnu/bits/stdint-intn.h:
42/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h:
43/usr/include/x86_64-linux-gnu/bits/stdint-least.h:
44/usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h:
45stddef.h:
46/usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h:
47uninorm.h:
48unicase/tolower.h:
49unicase/simple-mapping.h:
diff --git a/gl/unicase/.dirstamp b/gl/unicase/.dirstamp
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gl/unicase/.dirstamp
diff --git a/gl/unicase/simple-mapping.h b/gl/unicase/simple-mapping.h
new file mode 100644
index 00000000..0c4c75b3
--- /dev/null
+++ b/gl/unicase/simple-mapping.h
@@ -0,0 +1,39 @@
1/* Simple case mapping for Unicode characters.
2 Copyright (C) 2002, 2006, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2009.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18ucs4_t
19FUNC (ucs4_t uc)
20{
21 unsigned int index1 = uc >> mapping_header_0;
22 if (index1 < mapping_header_1)
23 {
24 int lookup1 = u_mapping.level1[index1];
25 if (lookup1 >= 0)
26 {
27 unsigned int index2 = (uc >> mapping_header_2) & mapping_header_3;
28 int lookup2 = u_mapping.level2[lookup1 + index2];
29 if (lookup2 >= 0)
30 {
31 unsigned int index3 = (uc & mapping_header_4);
32 int lookup3 = u_mapping.level3[lookup2 + index3];
33
34 return uc + lookup3;
35 }
36 }
37 }
38 return uc;
39}
diff --git a/gl/unicase/tolower.c b/gl/unicase/tolower.c
new file mode 100644
index 00000000..a1c898ef
--- /dev/null
+++ b/gl/unicase/tolower.c
@@ -0,0 +1,27 @@
1/* Lowercase mapping for Unicode characters (locale and context independent).
2 Copyright (C) 2002, 2006, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2009.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include "unicase.h"
22
23/* Define u_mapping table. */
24#include "tolower.h"
25
26#define FUNC uc_tolower
27#include "simple-mapping.h"
diff --git a/gl/unicase/tolower.h b/gl/unicase/tolower.h
new file mode 100644
index 00000000..794f4c0c
--- /dev/null
+++ b/gl/unicase/tolower.h
@@ -0,0 +1,743 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* Simple character mapping of Unicode characters. */
3/* Generated automatically by gen-uni-tables.c for Unicode 16.0.0. */
4
5/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
6
7 This file is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 This file is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19
20#define mapping_header_0 16
21#define mapping_header_1 2
22#define mapping_header_2 7
23#define mapping_header_3 511
24#define mapping_header_4 127
25static const
26struct
27 {
28 int level1[2];
29 short level2[2 << 9];
30 int level3[36 << 7];
31 }
32u_mapping =
33{
34 { 0, 512 },
35 {
36 0, 128, 256, 384, 512, -1, 640, 768,
37 896, 1024, 1152, -1, -1, -1, -1, -1,
38 -1, -1, -1, -1, -1, -1, -1, -1,
39 -1, -1, -1, -1, -1, -1, -1, -1,
40 -1, 1280, -1, -1, -1, -1, -1, 1408,
41 -1, -1, -1, -1, -1, -1, -1, -1,
42 -1, -1, -1, -1, -1, -1, -1, -1,
43 -1, 1536, -1, -1, 1664, 1792, 1920, 2048,
44 -1, -1, 2176, 2304, -1, -1, -1, -1,
45 -1, 2432, -1, -1, -1, -1, -1, -1,
46 -1, -1, -1, -1, -1, -1, -1, -1,
47 2560, 2688, -1, -1, -1, -1, -1, -1,
48 -1, -1, -1, -1, -1, -1, -1, -1,
49 -1, -1, -1, -1, -1, -1, -1, -1,
50 -1, -1, -1, -1, -1, -1, -1, -1,
51 -1, -1, -1, -1, -1, -1, -1, -1,
52 -1, -1, -1, -1, -1, -1, -1, -1,
53 -1, -1, -1, -1, -1, -1, -1, -1,
54 -1, -1, -1, -1, -1, -1, -1, -1,
55 -1, -1, -1, -1, -1, -1, -1, -1,
56 -1, -1, -1, -1, -1, -1, -1, -1,
57 -1, -1, -1, -1, -1, -1, -1, -1,
58 -1, -1, -1, -1, -1, -1, -1, -1,
59 -1, -1, -1, -1, -1, -1, -1, -1,
60 -1, -1, -1, -1, -1, -1, -1, -1,
61 -1, -1, -1, -1, -1, -1, -1, -1,
62 -1, -1, -1, -1, -1, -1, -1, -1,
63 -1, -1, -1, -1, -1, -1, -1, -1,
64 -1, -1, -1, -1, -1, -1, -1, -1,
65 -1, -1, -1, -1, -1, -1, -1, -1,
66 -1, -1, -1, -1, -1, -1, -1, -1,
67 -1, -1, -1, -1, -1, -1, -1, -1,
68 -1, -1, -1, -1, -1, -1, -1, -1,
69 -1, -1, -1, -1, -1, -1, -1, -1,
70 -1, -1, -1, -1, -1, -1, -1, -1,
71 -1, -1, -1, -1, -1, -1, -1, -1,
72 -1, -1, -1, -1, -1, -1, -1, -1,
73 -1, -1, -1, -1, -1, -1, -1, -1,
74 -1, -1, -1, -1, -1, -1, -1, -1,
75 -1, -1, -1, -1, -1, -1, -1, -1,
76 -1, -1, -1, -1, -1, -1, -1, -1,
77 -1, -1, -1, -1, 2816, 2944, 3072, 3200,
78 -1, -1, -1, -1, -1, -1, -1, -1,
79 -1, -1, -1, -1, -1, -1, -1, -1,
80 -1, -1, -1, -1, -1, -1, -1, -1,
81 -1, -1, -1, -1, -1, -1, -1, -1,
82 -1, -1, -1, -1, -1, -1, -1, -1,
83 -1, -1, -1, -1, -1, -1, -1, -1,
84 -1, -1, -1, -1, -1, -1, -1, -1,
85 -1, -1, -1, -1, -1, -1, -1, -1,
86 -1, -1, -1, -1, -1, -1, -1, -1,
87 -1, -1, -1, -1, -1, -1, -1, -1,
88 -1, -1, -1, -1, -1, -1, -1, -1,
89 -1, -1, -1, -1, -1, -1, -1, -1,
90 -1, -1, -1, -1, -1, -1, -1, -1,
91 -1, -1, -1, -1, -1, -1, -1, -1,
92 -1, -1, -1, -1, -1, -1, -1, -1,
93 -1, -1, -1, -1, -1, -1, -1, -1,
94 -1, -1, -1, -1, -1, -1, -1, -1,
95 -1, -1, -1, -1, -1, -1, -1, -1,
96 -1, -1, -1, -1, -1, -1, -1, -1,
97 -1, -1, -1, -1, -1, -1, -1, -1,
98 -1, -1, -1, -1, -1, -1, -1, -1,
99 -1, -1, -1, -1, -1, -1, 3328, -1,
100 -1, -1, -1, -1, -1, -1, -1, -1,
101 3456, 3584, 3712, 3840, -1, -1, -1, -1,
102 -1, -1, -1, -1, -1, -1, -1, -1,
103 -1, 3968, 4096, -1, -1, -1, -1, -1,
104 -1, -1, -1, -1, -1, -1, -1, -1,
105 -1, -1, -1, -1, -1, -1, -1, -1,
106 -1, 4224, -1, -1, -1, -1, -1, -1,
107 -1, -1, -1, -1, -1, -1, -1, -1,
108 -1, -1, -1, -1, -1, -1, -1, -1,
109 -1, -1, -1, -1, -1, -1, -1, -1,
110 -1, -1, -1, -1, -1, -1, -1, -1,
111 -1, -1, -1, -1, -1, -1, -1, -1,
112 -1, -1, -1, -1, -1, -1, -1, -1,
113 -1, -1, -1, -1, -1, -1, -1, -1,
114 -1, -1, -1, -1, -1, -1, -1, -1,
115 -1, -1, -1, -1, -1, -1, -1, -1,
116 -1, -1, -1, -1, -1, -1, -1, -1,
117 -1, -1, -1, -1, -1, -1, -1, -1,
118 -1, -1, -1, -1, -1, -1, -1, -1,
119 -1, -1, -1, -1, -1, -1, -1, -1,
120 -1, -1, -1, -1, -1, -1, -1, -1,
121 -1, -1, -1, -1, -1, -1, -1, -1,
122 -1, -1, -1, -1, -1, -1, -1, -1,
123 -1, -1, -1, -1, -1, -1, -1, -1,
124 -1, -1, -1, -1, -1, -1, -1, -1,
125 -1, -1, -1, -1, -1, -1, -1, -1,
126 -1, -1, -1, -1, -1, -1, -1, -1,
127 -1, -1, -1, -1, 4352, -1, -1, -1,
128 -1, -1, -1, -1, -1, -1, -1, -1,
129 -1, -1, -1, -1, -1, -1, -1, -1,
130 -1, -1, -1, -1, -1, -1, -1, -1,
131 -1, -1, -1, -1, -1, -1, -1, -1,
132 -1, -1, -1, -1, -1, -1, -1, -1,
133 -1, -1, -1, -1, -1, -1, -1, -1,
134 -1, -1, -1, -1, -1, -1, -1, -1,
135 -1, -1, -1, -1, -1, -1, -1, -1,
136 -1, -1, -1, -1, -1, -1, -1, -1,
137 -1, -1, -1, -1, -1, -1, -1, -1,
138 -1, -1, -1, -1, -1, -1, -1, -1,
139 -1, -1, -1, -1, -1, -1, -1, -1,
140 -1, -1, -1, -1, -1, -1, -1, -1,
141 -1, -1, -1, -1, -1, -1, -1, -1,
142 -1, -1, -1, -1, -1, -1, -1, -1,
143 -1, -1, -1, -1, -1, -1, -1, -1,
144 -1, -1, -1, -1, -1, -1, -1, -1,
145 -1, -1, -1, -1, -1, -1, -1, -1,
146 -1, -1, -1, -1, -1, -1, -1, -1,
147 -1, -1, -1, -1, -1, -1, -1, -1,
148 -1, -1, -1, -1, -1, -1, -1, -1,
149 -1, -1, -1, -1, -1, -1, -1, -1,
150 -1, -1, -1, -1, -1, -1, -1, -1,
151 -1, -1, -1, -1, -1, -1, -1, -1,
152 -1, -1, -1, -1, -1, -1, -1, -1,
153 -1, -1, -1, -1, -1, -1, -1, -1,
154 -1, -1, -1, -1, -1, -1, -1, -1,
155 -1, -1, -1, -1, -1, -1, -1, -1,
156 -1, -1, -1, -1, -1, -1, -1, -1,
157 -1, -1, -1, -1, -1, -1, -1, -1,
158 -1, -1, 4480, -1, -1, -1, -1, -1,
159 -1, -1, -1, -1, -1, -1, -1, -1,
160 -1, -1, -1, -1, -1, -1, -1, -1,
161 -1, -1, -1, -1, -1, -1, -1, -1,
162 -1, -1, -1, -1, -1, -1, -1, -1,
163 -1, -1, -1, -1, -1, -1, -1, -1
164 },
165 {
166 0, 0, 0, 0, 0, 0, 0, 0,
167 0, 0, 0, 0, 0, 0, 0, 0,
168 0, 0, 0, 0, 0, 0, 0, 0,
169 0, 0, 0, 0, 0, 0, 0, 0,
170 0, 0, 0, 0, 0, 0, 0, 0,
171 0, 0, 0, 0, 0, 0, 0, 0,
172 0, 0, 0, 0, 0, 0, 0, 0,
173 0, 0, 0, 0, 0, 0, 0, 0,
174 0, 32, 32, 32, 32, 32, 32, 32,
175 32, 32, 32, 32, 32, 32, 32, 32,
176 32, 32, 32, 32, 32, 32, 32, 32,
177 32, 32, 32, 0, 0, 0, 0, 0,
178 0, 0, 0, 0, 0, 0, 0, 0,
179 0, 0, 0, 0, 0, 0, 0, 0,
180 0, 0, 0, 0, 0, 0, 0, 0,
181 0, 0, 0, 0, 0, 0, 0, 0,
182 0, 0, 0, 0, 0, 0, 0, 0,
183 0, 0, 0, 0, 0, 0, 0, 0,
184 0, 0, 0, 0, 0, 0, 0, 0,
185 0, 0, 0, 0, 0, 0, 0, 0,
186 0, 0, 0, 0, 0, 0, 0, 0,
187 0, 0, 0, 0, 0, 0, 0, 0,
188 0, 0, 0, 0, 0, 0, 0, 0,
189 0, 0, 0, 0, 0, 0, 0, 0,
190 32, 32, 32, 32, 32, 32, 32, 32,
191 32, 32, 32, 32, 32, 32, 32, 32,
192 32, 32, 32, 32, 32, 32, 32, 0,
193 32, 32, 32, 32, 32, 32, 32, 0,
194 0, 0, 0, 0, 0, 0, 0, 0,
195 0, 0, 0, 0, 0, 0, 0, 0,
196 0, 0, 0, 0, 0, 0, 0, 0,
197 0, 0, 0, 0, 0, 0, 0, 0,
198 1, 0, 1, 0, 1, 0, 1, 0,
199 1, 0, 1, 0, 1, 0, 1, 0,
200 1, 0, 1, 0, 1, 0, 1, 0,
201 1, 0, 1, 0, 1, 0, 1, 0,
202 1, 0, 1, 0, 1, 0, 1, 0,
203 1, 0, 1, 0, 1, 0, 1, 0,
204 -199, 0, 1, 0, 1, 0, 1, 0,
205 0, 1, 0, 1, 0, 1, 0, 1,
206 0, 1, 0, 1, 0, 1, 0, 1,
207 0, 0, 1, 0, 1, 0, 1, 0,
208 1, 0, 1, 0, 1, 0, 1, 0,
209 1, 0, 1, 0, 1, 0, 1, 0,
210 1, 0, 1, 0, 1, 0, 1, 0,
211 1, 0, 1, 0, 1, 0, 1, 0,
212 1, 0, 1, 0, 1, 0, 1, 0,
213 -121, 1, 0, 1, 0, 1, 0, 0,
214 0, 210, 1, 0, 1, 0, 206, 1,
215 0, 205, 205, 1, 0, 0, 79, 202,
216 203, 1, 0, 205, 207, 0, 211, 209,
217 1, 0, 0, 0, 211, 213, 0, 214,
218 1, 0, 1, 0, 1, 0, 218, 1,
219 0, 218, 0, 0, 1, 0, 218, 1,
220 0, 217, 217, 1, 0, 1, 0, 219,
221 1, 0, 0, 0, 1, 0, 0, 0,
222 0, 0, 0, 0, 2, 1, 0, 2,
223 1, 0, 2, 1, 0, 1, 0, 1,
224 0, 1, 0, 1, 0, 1, 0, 1,
225 0, 1, 0, 1, 0, 0, 1, 0,
226 1, 0, 1, 0, 1, 0, 1, 0,
227 1, 0, 1, 0, 1, 0, 1, 0,
228 0, 2, 1, 0, 1, 0, -97, -56,
229 1, 0, 1, 0, 1, 0, 1, 0,
230 1, 0, 1, 0, 1, 0, 1, 0,
231 1, 0, 1, 0, 1, 0, 1, 0,
232 1, 0, 1, 0, 1, 0, 1, 0,
233 1, 0, 1, 0, 1, 0, 1, 0,
234 -130, 0, 1, 0, 1, 0, 1, 0,
235 1, 0, 1, 0, 1, 0, 1, 0,
236 1, 0, 1, 0, 0, 0, 0, 0,
237 0, 0, 10795, 1, 0, -163, 10792, 0,
238 0, 1, 0, -195, 69, 71, 1, 0,
239 1, 0, 1, 0, 1, 0, 1, 0,
240 0, 0, 0, 0, 0, 0, 0, 0,
241 0, 0, 0, 0, 0, 0, 0, 0,
242 0, 0, 0, 0, 0, 0, 0, 0,
243 0, 0, 0, 0, 0, 0, 0, 0,
244 0, 0, 0, 0, 0, 0, 0, 0,
245 0, 0, 0, 0, 0, 0, 0, 0,
246 0, 0, 0, 0, 0, 0, 0, 0,
247 0, 0, 0, 0, 0, 0, 0, 0,
248 0, 0, 0, 0, 0, 0, 0, 0,
249 0, 0, 0, 0, 0, 0, 0, 0,
250 0, 0, 0, 0, 0, 0, 0, 0,
251 0, 0, 0, 0, 0, 0, 0, 0,
252 0, 0, 0, 0, 0, 0, 0, 0,
253 0, 0, 0, 0, 0, 0, 0, 0,
254 0, 0, 0, 0, 0, 0, 0, 0,
255 0, 0, 0, 0, 0, 0, 0, 0,
256 0, 0, 0, 0, 0, 0, 0, 0,
257 0, 0, 0, 0, 0, 0, 0, 0,
258 0, 0, 0, 0, 0, 0, 0, 0,
259 0, 0, 0, 0, 0, 0, 0, 0,
260 1, 0, 1, 0, 0, 0, 1, 0,
261 0, 0, 0, 0, 0, 0, 0, 116,
262 0, 0, 0, 0, 0, 0, 38, 0,
263 37, 37, 37, 0, 64, 0, 63, 63,
264 0, 32, 32, 32, 32, 32, 32, 32,
265 32, 32, 32, 32, 32, 32, 32, 32,
266 32, 32, 0, 32, 32, 32, 32, 32,
267 32, 32, 32, 32, 0, 0, 0, 0,
268 0, 0, 0, 0, 0, 0, 0, 0,
269 0, 0, 0, 0, 0, 0, 0, 0,
270 0, 0, 0, 0, 0, 0, 0, 0,
271 0, 0, 0, 0, 0, 0, 0, 8,
272 0, 0, 0, 0, 0, 0, 0, 0,
273 1, 0, 1, 0, 1, 0, 1, 0,
274 1, 0, 1, 0, 1, 0, 1, 0,
275 1, 0, 1, 0, 1, 0, 1, 0,
276 0, 0, 0, 0, -60, 0, 0, 1,
277 0, -7, 1, 0, 0, -130, -130, -130,
278 80, 80, 80, 80, 80, 80, 80, 80,
279 80, 80, 80, 80, 80, 80, 80, 80,
280 32, 32, 32, 32, 32, 32, 32, 32,
281 32, 32, 32, 32, 32, 32, 32, 32,
282 32, 32, 32, 32, 32, 32, 32, 32,
283 32, 32, 32, 32, 32, 32, 32, 32,
284 0, 0, 0, 0, 0, 0, 0, 0,
285 0, 0, 0, 0, 0, 0, 0, 0,
286 0, 0, 0, 0, 0, 0, 0, 0,
287 0, 0, 0, 0, 0, 0, 0, 0,
288 0, 0, 0, 0, 0, 0, 0, 0,
289 0, 0, 0, 0, 0, 0, 0, 0,
290 1, 0, 1, 0, 1, 0, 1, 0,
291 1, 0, 1, 0, 1, 0, 1, 0,
292 1, 0, 1, 0, 1, 0, 1, 0,
293 1, 0, 1, 0, 1, 0, 1, 0,
294 1, 0, 0, 0, 0, 0, 0, 0,
295 0, 0, 1, 0, 1, 0, 1, 0,
296 1, 0, 1, 0, 1, 0, 1, 0,
297 1, 0, 1, 0, 1, 0, 1, 0,
298 1, 0, 1, 0, 1, 0, 1, 0,
299 1, 0, 1, 0, 1, 0, 1, 0,
300 1, 0, 1, 0, 1, 0, 1, 0,
301 1, 0, 1, 0, 1, 0, 1, 0,
302 15, 1, 0, 1, 0, 1, 0, 1,
303 0, 1, 0, 1, 0, 1, 0, 0,
304 1, 0, 1, 0, 1, 0, 1, 0,
305 1, 0, 1, 0, 1, 0, 1, 0,
306 1, 0, 1, 0, 1, 0, 1, 0,
307 1, 0, 1, 0, 1, 0, 1, 0,
308 1, 0, 1, 0, 1, 0, 1, 0,
309 1, 0, 1, 0, 1, 0, 1, 0,
310 1, 0, 1, 0, 1, 0, 1, 0,
311 1, 0, 1, 0, 1, 0, 1, 0,
312 1, 0, 1, 0, 1, 0, 1, 0,
313 1, 0, 1, 0, 1, 0, 1, 0,
314 1, 0, 1, 0, 1, 0, 1, 0,
315 1, 0, 1, 0, 1, 0, 1, 0,
316 0, 48, 48, 48, 48, 48, 48, 48,
317 48, 48, 48, 48, 48, 48, 48, 48,
318 48, 48, 48, 48, 48, 48, 48, 48,
319 48, 48, 48, 48, 48, 48, 48, 48,
320 48, 48, 48, 48, 48, 48, 48, 0,
321 0, 0, 0, 0, 0, 0, 0, 0,
322 0, 0, 0, 0, 0, 0, 0, 0,
323 0, 0, 0, 0, 0, 0, 0, 0,
324 0, 0, 0, 0, 0, 0, 0, 0,
325 0, 0, 0, 0, 0, 0, 0, 0,
326 0, 0, 0, 0, 0, 0, 0, 0,
327 0, 0, 0, 0, 0, 0, 0, 0,
328 0, 0, 0, 0, 0, 0, 0, 0,
329 0, 0, 0, 0, 0, 0, 0, 0,
330 7264, 7264, 7264, 7264, 7264, 7264, 7264, 7264,
331 7264, 7264, 7264, 7264, 7264, 7264, 7264, 7264,
332 7264, 7264, 7264, 7264, 7264, 7264, 7264, 7264,
333 7264, 7264, 7264, 7264, 7264, 7264, 7264, 7264,
334 7264, 7264, 7264, 7264, 7264, 7264, 0, 7264,
335 0, 0, 0, 0, 0, 7264, 0, 0,
336 0, 0, 0, 0, 0, 0, 0, 0,
337 0, 0, 0, 0, 0, 0, 0, 0,
338 0, 0, 0, 0, 0, 0, 0, 0,
339 0, 0, 0, 0, 0, 0, 0, 0,
340 0, 0, 0, 0, 0, 0, 0, 0,
341 0, 0, 0, 0, 0, 0, 0, 0,
342 0, 0, 0, 0, 0, 0, 0, 0,
343 0, 0, 0, 0, 0, 0, 0, 0,
344 0, 0, 0, 0, 0, 0, 0, 0,
345 0, 0, 0, 0, 0, 0, 0, 0,
346 38864, 38864, 38864, 38864, 38864, 38864, 38864, 38864,
347 38864, 38864, 38864, 38864, 38864, 38864, 38864, 38864,
348 38864, 38864, 38864, 38864, 38864, 38864, 38864, 38864,
349 38864, 38864, 38864, 38864, 38864, 38864, 38864, 38864,
350 38864, 38864, 38864, 38864, 38864, 38864, 38864, 38864,
351 38864, 38864, 38864, 38864, 38864, 38864, 38864, 38864,
352 38864, 38864, 38864, 38864, 38864, 38864, 38864, 38864,
353 38864, 38864, 38864, 38864, 38864, 38864, 38864, 38864,
354 38864, 38864, 38864, 38864, 38864, 38864, 38864, 38864,
355 38864, 38864, 38864, 38864, 38864, 38864, 38864, 38864,
356 8, 8, 8, 8, 8, 8, 0, 0,
357 0, 0, 0, 0, 0, 0, 0, 0,
358 0, 0, 0, 0, 0, 0, 0, 0,
359 0, 1, 0, 0, 0, 0, 0, 0,
360 -3008, -3008, -3008, -3008, -3008, -3008, -3008, -3008,
361 -3008, -3008, -3008, -3008, -3008, -3008, -3008, -3008,
362 -3008, -3008, -3008, -3008, -3008, -3008, -3008, -3008,
363 -3008, -3008, -3008, -3008, -3008, -3008, -3008, -3008,
364 -3008, -3008, -3008, -3008, -3008, -3008, -3008, -3008,
365 -3008, -3008, -3008, 0, 0, -3008, -3008, -3008,
366 0, 0, 0, 0, 0, 0, 0, 0,
367 0, 0, 0, 0, 0, 0, 0, 0,
368 0, 0, 0, 0, 0, 0, 0, 0,
369 0, 0, 0, 0, 0, 0, 0, 0,
370 0, 0, 0, 0, 0, 0, 0, 0,
371 0, 0, 0, 0, 0, 0, 0, 0,
372 0, 0, 0, 0, 0, 0, 0, 0,
373 0, 0, 0, 0, 0, 0, 0, 0,
374 1, 0, 1, 0, 1, 0, 1, 0,
375 1, 0, 1, 0, 1, 0, 1, 0,
376 1, 0, 1, 0, 1, 0, 1, 0,
377 1, 0, 1, 0, 1, 0, 1, 0,
378 1, 0, 1, 0, 1, 0, 1, 0,
379 1, 0, 1, 0, 1, 0, 1, 0,
380 1, 0, 1, 0, 1, 0, 1, 0,
381 1, 0, 1, 0, 1, 0, 1, 0,
382 1, 0, 1, 0, 1, 0, 1, 0,
383 1, 0, 1, 0, 1, 0, 1, 0,
384 1, 0, 1, 0, 1, 0, 1, 0,
385 1, 0, 1, 0, 1, 0, 1, 0,
386 1, 0, 1, 0, 1, 0, 1, 0,
387 1, 0, 1, 0, 1, 0, 1, 0,
388 1, 0, 1, 0, 1, 0, 1, 0,
389 1, 0, 1, 0, 1, 0, 1, 0,
390 1, 0, 1, 0, 1, 0, 1, 0,
391 1, 0, 1, 0, 1, 0, 1, 0,
392 1, 0, 1, 0, 1, 0, 0, 0,
393 0, 0, 0, 0, 0, 0, -7615, 0,
394 1, 0, 1, 0, 1, 0, 1, 0,
395 1, 0, 1, 0, 1, 0, 1, 0,
396 1, 0, 1, 0, 1, 0, 1, 0,
397 1, 0, 1, 0, 1, 0, 1, 0,
398 1, 0, 1, 0, 1, 0, 1, 0,
399 1, 0, 1, 0, 1, 0, 1, 0,
400 1, 0, 1, 0, 1, 0, 1, 0,
401 1, 0, 1, 0, 1, 0, 1, 0,
402 1, 0, 1, 0, 1, 0, 1, 0,
403 1, 0, 1, 0, 1, 0, 1, 0,
404 1, 0, 1, 0, 1, 0, 1, 0,
405 1, 0, 1, 0, 1, 0, 1, 0,
406 0, 0, 0, 0, 0, 0, 0, 0,
407 -8, -8, -8, -8, -8, -8, -8, -8,
408 0, 0, 0, 0, 0, 0, 0, 0,
409 -8, -8, -8, -8, -8, -8, 0, 0,
410 0, 0, 0, 0, 0, 0, 0, 0,
411 -8, -8, -8, -8, -8, -8, -8, -8,
412 0, 0, 0, 0, 0, 0, 0, 0,
413 -8, -8, -8, -8, -8, -8, -8, -8,
414 0, 0, 0, 0, 0, 0, 0, 0,
415 -8, -8, -8, -8, -8, -8, 0, 0,
416 0, 0, 0, 0, 0, 0, 0, 0,
417 0, -8, 0, -8, 0, -8, 0, -8,
418 0, 0, 0, 0, 0, 0, 0, 0,
419 -8, -8, -8, -8, -8, -8, -8, -8,
420 0, 0, 0, 0, 0, 0, 0, 0,
421 0, 0, 0, 0, 0, 0, 0, 0,
422 0, 0, 0, 0, 0, 0, 0, 0,
423 -8, -8, -8, -8, -8, -8, -8, -8,
424 0, 0, 0, 0, 0, 0, 0, 0,
425 -8, -8, -8, -8, -8, -8, -8, -8,
426 0, 0, 0, 0, 0, 0, 0, 0,
427 -8, -8, -8, -8, -8, -8, -8, -8,
428 0, 0, 0, 0, 0, 0, 0, 0,
429 -8, -8, -74, -74, -9, 0, 0, 0,
430 0, 0, 0, 0, 0, 0, 0, 0,
431 -86, -86, -86, -86, -9, 0, 0, 0,
432 0, 0, 0, 0, 0, 0, 0, 0,
433 -8, -8, -100, -100, 0, 0, 0, 0,
434 0, 0, 0, 0, 0, 0, 0, 0,
435 -8, -8, -112, -112, -7, 0, 0, 0,
436 0, 0, 0, 0, 0, 0, 0, 0,
437 -128, -128, -126, -126, -9, 0, 0, 0,
438 0, 0, 0, 0, 0, 0, 0, 0,
439 0, 0, 0, 0, 0, 0, 0, 0,
440 0, 0, 0, 0, 0, 0, 0, 0,
441 0, 0, 0, 0, 0, 0, 0, 0,
442 0, 0, 0, 0, 0, 0, -7517, 0,
443 0, 0, -8383, -8262, 0, 0, 0, 0,
444 0, 0, 28, 0, 0, 0, 0, 0,
445 0, 0, 0, 0, 0, 0, 0, 0,
446 0, 0, 0, 0, 0, 0, 0, 0,
447 0, 0, 0, 0, 0, 0, 0, 0,
448 0, 0, 0, 0, 0, 0, 0, 0,
449 0, 0, 0, 0, 0, 0, 0, 0,
450 16, 16, 16, 16, 16, 16, 16, 16,
451 16, 16, 16, 16, 16, 16, 16, 16,
452 0, 0, 0, 0, 0, 0, 0, 0,
453 0, 0, 0, 0, 0, 0, 0, 0,
454 0, 0, 0, 1, 0, 0, 0, 0,
455 0, 0, 0, 0, 0, 0, 0, 0,
456 0, 0, 0, 0, 0, 0, 0, 0,
457 0, 0, 0, 0, 0, 0, 0, 0,
458 0, 0, 0, 0, 0, 0, 0, 0,
459 0, 0, 0, 0, 0, 0, 0, 0,
460 0, 0, 0, 0, 0, 0, 0, 0,
461 0, 0, 0, 0, 0, 0, 0, 0,
462 0, 0, 0, 0, 0, 0, 0, 0,
463 0, 0, 0, 0, 0, 0, 0, 0,
464 0, 0, 0, 0, 0, 0, 0, 0,
465 0, 0, 0, 0, 0, 0, 0, 0,
466 0, 0, 0, 0, 0, 0, 0, 0,
467 0, 0, 0, 0, 0, 0, 0, 0,
468 0, 0, 0, 0, 0, 0, 0, 0,
469 0, 0, 0, 0, 0, 0, 0, 0,
470 0, 0, 0, 0, 0, 0, 0, 0,
471 0, 0, 0, 0, 0, 0, 0, 0,
472 0, 0, 0, 0, 0, 0, 0, 0,
473 0, 0, 0, 0, 0, 0, 0, 0,
474 0, 0, 0, 0, 0, 0, 0, 0,
475 0, 0, 0, 0, 0, 0, 0, 0,
476 0, 0, 0, 0, 0, 0, 26, 26,
477 26, 26, 26, 26, 26, 26, 26, 26,
478 26, 26, 26, 26, 26, 26, 26, 26,
479 26, 26, 26, 26, 26, 26, 26, 26,
480 0, 0, 0, 0, 0, 0, 0, 0,
481 0, 0, 0, 0, 0, 0, 0, 0,
482 0, 0, 0, 0, 0, 0, 0, 0,
483 0, 0, 0, 0, 0, 0, 0, 0,
484 0, 0, 0, 0, 0, 0, 0, 0,
485 0, 0, 0, 0, 0, 0, 0, 0,
486 48, 48, 48, 48, 48, 48, 48, 48,
487 48, 48, 48, 48, 48, 48, 48, 48,
488 48, 48, 48, 48, 48, 48, 48, 48,
489 48, 48, 48, 48, 48, 48, 48, 48,
490 48, 48, 48, 48, 48, 48, 48, 48,
491 48, 48, 48, 48, 48, 48, 48, 48,
492 0, 0, 0, 0, 0, 0, 0, 0,
493 0, 0, 0, 0, 0, 0, 0, 0,
494 0, 0, 0, 0, 0, 0, 0, 0,
495 0, 0, 0, 0, 0, 0, 0, 0,
496 0, 0, 0, 0, 0, 0, 0, 0,
497 0, 0, 0, 0, 0, 0, 0, 0,
498 1, 0, -10743, -3814, -10727, 0, 0, 1,
499 0, 1, 0, 1, 0, -10780, -10749, -10783,
500 -10782, 0, 1, 0, 0, 1, 0, 0,
501 0, 0, 0, 0, 0, 0, -10815, -10815,
502 1, 0, 1, 0, 1, 0, 1, 0,
503 1, 0, 1, 0, 1, 0, 1, 0,
504 1, 0, 1, 0, 1, 0, 1, 0,
505 1, 0, 1, 0, 1, 0, 1, 0,
506 1, 0, 1, 0, 1, 0, 1, 0,
507 1, 0, 1, 0, 1, 0, 1, 0,
508 1, 0, 1, 0, 1, 0, 1, 0,
509 1, 0, 1, 0, 1, 0, 1, 0,
510 1, 0, 1, 0, 1, 0, 1, 0,
511 1, 0, 1, 0, 1, 0, 1, 0,
512 1, 0, 1, 0, 1, 0, 1, 0,
513 1, 0, 1, 0, 1, 0, 1, 0,
514 1, 0, 1, 0, 0, 0, 0, 0,
515 0, 0, 0, 1, 0, 1, 0, 0,
516 0, 0, 1, 0, 0, 0, 0, 0,
517 0, 0, 0, 0, 0, 0, 0, 0,
518 0, 0, 0, 0, 0, 0, 0, 0,
519 0, 0, 0, 0, 0, 0, 0, 0,
520 0, 0, 0, 0, 0, 0, 0, 0,
521 0, 0, 0, 0, 0, 0, 0, 0,
522 0, 0, 0, 0, 0, 0, 0, 0,
523 0, 0, 0, 0, 0, 0, 0, 0,
524 0, 0, 0, 0, 0, 0, 0, 0,
525 0, 0, 0, 0, 0, 0, 0, 0,
526 1, 0, 1, 0, 1, 0, 1, 0,
527 1, 0, 1, 0, 1, 0, 1, 0,
528 1, 0, 1, 0, 1, 0, 1, 0,
529 1, 0, 1, 0, 1, 0, 1, 0,
530 1, 0, 1, 0, 1, 0, 1, 0,
531 1, 0, 1, 0, 1, 0, 0, 0,
532 0, 0, 0, 0, 0, 0, 0, 0,
533 0, 0, 0, 0, 0, 0, 0, 0,
534 1, 0, 1, 0, 1, 0, 1, 0,
535 1, 0, 1, 0, 1, 0, 1, 0,
536 1, 0, 1, 0, 1, 0, 1, 0,
537 1, 0, 1, 0, 0, 0, 0, 0,
538 0, 0, 0, 0, 0, 0, 0, 0,
539 0, 0, 0, 0, 0, 0, 0, 0,
540 0, 0, 0, 0, 0, 0, 0, 0,
541 0, 0, 0, 0, 0, 0, 0, 0,
542 0, 0, 0, 0, 0, 0, 0, 0,
543 0, 0, 0, 0, 0, 0, 0, 0,
544 0, 0, 0, 0, 0, 0, 0, 0,
545 0, 0, 0, 0, 0, 0, 0, 0,
546 0, 0, 0, 0, 0, 0, 0, 0,
547 0, 0, 0, 0, 0, 0, 0, 0,
548 0, 0, 0, 0, 0, 0, 0, 0,
549 0, 0, 0, 0, 0, 0, 0, 0,
550 0, 0, 0, 0, 0, 0, 0, 0,
551 0, 0, 0, 0, 0, 0, 0, 0,
552 0, 0, 0, 0, 0, 0, 0, 0,
553 0, 0, 0, 0, 0, 0, 0, 0,
554 0, 0, 1, 0, 1, 0, 1, 0,
555 1, 0, 1, 0, 1, 0, 1, 0,
556 0, 0, 1, 0, 1, 0, 1, 0,
557 1, 0, 1, 0, 1, 0, 1, 0,
558 1, 0, 1, 0, 1, 0, 1, 0,
559 1, 0, 1, 0, 1, 0, 1, 0,
560 1, 0, 1, 0, 1, 0, 1, 0,
561 1, 0, 1, 0, 1, 0, 1, 0,
562 1, 0, 1, 0, 1, 0, 1, 0,
563 1, 0, 1, 0, 1, 0, 1, 0,
564 0, 0, 0, 0, 0, 0, 0, 0,
565 0, 1, 0, 1, 0, -35332, 1, 0,
566 1, 0, 1, 0, 1, 0, 1, 0,
567 0, 0, 0, 1, 0, -42280, 0, 0,
568 1, 0, 1, 0, 0, 0, 1, 0,
569 1, 0, 1, 0, 1, 0, 1, 0,
570 1, 0, 1, 0, 1, 0, 1, 0,
571 1, 0, -42308, -42319, -42315, -42305, -42308, 0,
572 -42258, -42282, -42261, 928, 1, 0, 1, 0,
573 1, 0, 1, 0, 1, 0, 1, 0,
574 1, 0, 1, 0, -48, -42307, -35384, 1,
575 0, 1, 0, -42343, 1, 0, 0, 0,
576 1, 0, 0, 0, 0, 0, 1, 0,
577 1, 0, 1, 0, -42561, 0, 0, 0,
578 0, 0, 0, 0, 0, 0, 0, 0,
579 0, 0, 0, 0, 0, 0, 0, 0,
580 0, 0, 0, 0, 0, 1, 0, 0,
581 0, 0, 0, 0, 0, 0, 0, 0,
582 0, 0, 0, 0, 0, 0, 0, 0,
583 0, 0, 0, 0, 0, 0, 0, 0,
584 0, 0, 0, 0, 0, 0, 0, 0,
585 0, 0, 0, 0, 0, 0, 0, 0,
586 0, 32, 32, 32, 32, 32, 32, 32,
587 32, 32, 32, 32, 32, 32, 32, 32,
588 32, 32, 32, 32, 32, 32, 32, 32,
589 32, 32, 32, 0, 0, 0, 0, 0,
590 0, 0, 0, 0, 0, 0, 0, 0,
591 0, 0, 0, 0, 0, 0, 0, 0,
592 0, 0, 0, 0, 0, 0, 0, 0,
593 0, 0, 0, 0, 0, 0, 0, 0,
594 0, 0, 0, 0, 0, 0, 0, 0,
595 0, 0, 0, 0, 0, 0, 0, 0,
596 0, 0, 0, 0, 0, 0, 0, 0,
597 0, 0, 0, 0, 0, 0, 0, 0,
598 40, 40, 40, 40, 40, 40, 40, 40,
599 40, 40, 40, 40, 40, 40, 40, 40,
600 40, 40, 40, 40, 40, 40, 40, 40,
601 40, 40, 40, 40, 40, 40, 40, 40,
602 40, 40, 40, 40, 40, 40, 40, 40,
603 0, 0, 0, 0, 0, 0, 0, 0,
604 0, 0, 0, 0, 0, 0, 0, 0,
605 0, 0, 0, 0, 0, 0, 0, 0,
606 0, 0, 0, 0, 0, 0, 0, 0,
607 0, 0, 0, 0, 0, 0, 0, 0,
608 0, 0, 0, 0, 0, 0, 0, 0,
609 0, 0, 0, 0, 0, 0, 0, 0,
610 0, 0, 0, 0, 0, 0, 0, 0,
611 0, 0, 0, 0, 0, 0, 0, 0,
612 0, 0, 0, 0, 0, 0, 0, 0,
613 0, 0, 0, 0, 0, 0, 0, 0,
614 0, 0, 0, 0, 0, 0, 0, 0,
615 0, 0, 0, 0, 0, 0, 0, 0,
616 0, 0, 0, 0, 0, 0, 0, 0,
617 0, 0, 0, 0, 0, 0, 0, 0,
618 0, 0, 0, 0, 0, 0, 0, 0,
619 0, 0, 0, 0, 0, 0, 0, 0,
620 40, 40, 40, 40, 40, 40, 40, 40,
621 40, 40, 40, 40, 40, 40, 40, 40,
622 40, 40, 40, 40, 40, 40, 40, 40,
623 40, 40, 40, 40, 40, 40, 40, 40,
624 40, 40, 40, 40, 0, 0, 0, 0,
625 0, 0, 0, 0, 0, 0, 0, 0,
626 0, 0, 0, 0, 0, 0, 0, 0,
627 0, 0, 0, 0, 0, 0, 0, 0,
628 0, 0, 0, 0, 0, 0, 0, 0,
629 0, 0, 0, 0, 0, 0, 0, 0,
630 0, 0, 0, 0, 0, 0, 0, 0,
631 0, 0, 0, 0, 0, 0, 0, 0,
632 0, 0, 0, 0, 0, 0, 0, 0,
633 0, 0, 0, 0, 0, 0, 0, 0,
634 0, 0, 0, 0, 0, 0, 0, 0,
635 0, 0, 0, 0, 0, 0, 0, 0,
636 0, 0, 0, 0, 0, 0, 0, 0,
637 0, 0, 0, 0, 0, 0, 0, 0,
638 0, 0, 0, 0, 0, 0, 0, 0,
639 0, 0, 0, 0, 0, 0, 0, 0,
640 0, 0, 0, 0, 0, 0, 0, 0,
641 0, 0, 0, 0, 0, 0, 0, 0,
642 0, 0, 0, 0, 0, 0, 0, 0,
643 0, 0, 0, 0, 0, 0, 0, 0,
644 39, 39, 39, 39, 39, 39, 39, 39,
645 39, 39, 39, 0, 39, 39, 39, 39,
646 39, 39, 39, 39, 39, 39, 39, 39,
647 39, 39, 39, 0, 39, 39, 39, 39,
648 39, 39, 39, 0, 39, 39, 0, 0,
649 0, 0, 0, 0, 0, 0, 0, 0,
650 0, 0, 0, 0, 0, 0, 0, 0,
651 0, 0, 0, 0, 0, 0, 0, 0,
652 0, 0, 0, 0, 0, 0, 0, 0,
653 0, 0, 0, 0, 0, 0, 0, 0,
654 0, 0, 0, 0, 0, 0, 0, 0,
655 0, 0, 0, 0, 0, 0, 0, 0,
656 0, 0, 0, 0, 0, 0, 0, 0,
657 0, 0, 0, 0, 0, 0, 0, 0,
658 0, 0, 0, 0, 0, 0, 0, 0,
659 0, 0, 0, 0, 0, 0, 0, 0,
660 0, 0, 0, 0, 0, 0, 0, 0,
661 0, 0, 0, 0, 0, 0, 0, 0,
662 64, 64, 64, 64, 64, 64, 64, 64,
663 64, 64, 64, 64, 64, 64, 64, 64,
664 64, 64, 64, 64, 64, 64, 64, 64,
665 64, 64, 64, 64, 64, 64, 64, 64,
666 64, 64, 64, 64, 64, 64, 64, 64,
667 64, 64, 64, 64, 64, 64, 64, 64,
668 64, 64, 64, 0, 0, 0, 0, 0,
669 0, 0, 0, 0, 0, 0, 0, 0,
670 0, 0, 0, 0, 0, 0, 0, 0,
671 0, 0, 0, 0, 0, 0, 0, 0,
672 0, 0, 0, 0, 0, 0, 0, 0,
673 0, 0, 0, 0, 0, 0, 0, 0,
674 0, 0, 0, 0, 0, 0, 0, 0,
675 0, 0, 0, 0, 0, 0, 0, 0,
676 0, 0, 0, 0, 0, 0, 0, 0,
677 0, 0, 0, 0, 0, 0, 0, 0,
678 0, 0, 0, 0, 0, 0, 0, 0,
679 0, 0, 0, 0, 0, 0, 0, 0,
680 0, 0, 0, 0, 0, 0, 0, 0,
681 0, 0, 0, 0, 0, 0, 0, 0,
682 0, 0, 0, 0, 0, 0, 0, 0,
683 0, 0, 0, 0, 0, 0, 0, 0,
684 0, 0, 0, 0, 0, 0, 0, 0,
685 0, 0, 0, 0, 0, 0, 0, 0,
686 0, 0, 0, 0, 0, 0, 0, 0,
687 0, 0, 0, 0, 0, 0, 0, 0,
688 32, 32, 32, 32, 32, 32, 32, 32,
689 32, 32, 32, 32, 32, 32, 32, 32,
690 32, 32, 32, 32, 32, 32, 0, 0,
691 0, 0, 0, 0, 0, 0, 0, 0,
692 0, 0, 0, 0, 0, 0, 0, 0,
693 0, 0, 0, 0, 0, 0, 0, 0,
694 0, 0, 0, 0, 0, 0, 0, 0,
695 0, 0, 0, 0, 0, 0, 0, 0,
696 0, 0, 0, 0, 0, 0, 0, 0,
697 0, 0, 0, 0, 0, 0, 0, 0,
698 32, 32, 32, 32, 32, 32, 32, 32,
699 32, 32, 32, 32, 32, 32, 32, 32,
700 32, 32, 32, 32, 32, 32, 32, 32,
701 32, 32, 32, 32, 32, 32, 32, 32,
702 0, 0, 0, 0, 0, 0, 0, 0,
703 0, 0, 0, 0, 0, 0, 0, 0,
704 0, 0, 0, 0, 0, 0, 0, 0,
705 0, 0, 0, 0, 0, 0, 0, 0,
706 0, 0, 0, 0, 0, 0, 0, 0,
707 0, 0, 0, 0, 0, 0, 0, 0,
708 0, 0, 0, 0, 0, 0, 0, 0,
709 0, 0, 0, 0, 0, 0, 0, 0,
710 0, 0, 0, 0, 0, 0, 0, 0,
711 0, 0, 0, 0, 0, 0, 0, 0,
712 0, 0, 0, 0, 0, 0, 0, 0,
713 0, 0, 0, 0, 0, 0, 0, 0,
714 0, 0, 0, 0, 0, 0, 0, 0,
715 0, 0, 0, 0, 0, 0, 0, 0,
716 0, 0, 0, 0, 0, 0, 0, 0,
717 0, 0, 0, 0, 0, 0, 0, 0,
718 32, 32, 32, 32, 32, 32, 32, 32,
719 32, 32, 32, 32, 32, 32, 32, 32,
720 32, 32, 32, 32, 32, 32, 32, 32,
721 32, 32, 32, 32, 32, 32, 32, 32,
722 0, 0, 0, 0, 0, 0, 0, 0,
723 0, 0, 0, 0, 0, 0, 0, 0,
724 0, 0, 0, 0, 0, 0, 0, 0,
725 0, 0, 0, 0, 0, 0, 0, 0,
726 34, 34, 34, 34, 34, 34, 34, 34,
727 34, 34, 34, 34, 34, 34, 34, 34,
728 34, 34, 34, 34, 34, 34, 34, 34,
729 34, 34, 34, 34, 34, 34, 34, 34,
730 34, 34, 0, 0, 0, 0, 0, 0,
731 0, 0, 0, 0, 0, 0, 0, 0,
732 0, 0, 0, 0, 0, 0, 0, 0,
733 0, 0, 0, 0, 0, 0, 0, 0,
734 0, 0, 0, 0, 0, 0, 0, 0,
735 0, 0, 0, 0, 0, 0, 0, 0,
736 0, 0, 0, 0, 0, 0, 0, 0,
737 0, 0, 0, 0, 0, 0, 0, 0,
738 0, 0, 0, 0, 0, 0, 0, 0,
739 0, 0, 0, 0, 0, 0, 0, 0,
740 0, 0, 0, 0, 0, 0, 0, 0,
741 0, 0, 0, 0, 0, 0, 0, 0
742 }
743};
diff --git a/gl/unictype.h b/gl/unictype.h
new file mode 100644
index 00000000..78072c2a
--- /dev/null
+++ b/gl/unictype.h
@@ -0,0 +1,1148 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* Unicode character classification and properties.
3 Copyright (C) 2002, 2005-2025 Free Software Foundation, Inc.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#ifndef _UNICTYPE_H
19#define _UNICTYPE_H
20
21#include "unitypes.h"
22
23/* Get bool. */
24#include <stdbool.h>
25
26/* Get size_t. */
27#include <stddef.h>
28
29#if 0
30# include <unistring/woe32dll.h>
31#else
32# define LIBUNISTRING_DLL_VARIABLE
33#endif
34
35#ifdef __cplusplus
36extern "C" {
37#endif
38
39/* ========================================================================= */
40
41/* Field 1 of Unicode Character Database: Character name.
42 See "uniname.h". */
43
44/* ========================================================================= */
45
46/* Field 2 of Unicode Character Database: General category. */
47
48/* Data type denoting a General category value. This is not just a bitmask,
49 but rather a bitmask and a pointer to the lookup table, so that programs
50 that use only the predefined bitmasks (i.e. don't combine bitmasks with &
51 and |) don't have a link-time dependency towards the big general table. */
52typedef struct
53{
54 uint32_t bitmask : 31;
55 /*bool*/ unsigned int generic : 1;
56 union
57 {
58 const void *table; /* when generic is 0 */
59 bool (*lookup_fn) (ucs4_t uc, uint32_t bitmask); /* when generic is 1 */
60 } lookup;
61}
62uc_general_category_t;
63
64/* Bits and bit masks denoting General category values. UnicodeData-3.2.0.html
65 says a 32-bit integer will always suffice to represent them.
66 These bit masks can only be used with the uc_is_general_category_withtable
67 function. */
68enum
69{
70 UC_CATEGORY_MASK_L = 0x0000001f,
71 UC_CATEGORY_MASK_LC = 0x00000007,
72 UC_CATEGORY_MASK_Lu = 0x00000001,
73 UC_CATEGORY_MASK_Ll = 0x00000002,
74 UC_CATEGORY_MASK_Lt = 0x00000004,
75 UC_CATEGORY_MASK_Lm = 0x00000008,
76 UC_CATEGORY_MASK_Lo = 0x00000010,
77 UC_CATEGORY_MASK_M = 0x000000e0,
78 UC_CATEGORY_MASK_Mn = 0x00000020,
79 UC_CATEGORY_MASK_Mc = 0x00000040,
80 UC_CATEGORY_MASK_Me = 0x00000080,
81 UC_CATEGORY_MASK_N = 0x00000700,
82 UC_CATEGORY_MASK_Nd = 0x00000100,
83 UC_CATEGORY_MASK_Nl = 0x00000200,
84 UC_CATEGORY_MASK_No = 0x00000400,
85 UC_CATEGORY_MASK_P = 0x0003f800,
86 UC_CATEGORY_MASK_Pc = 0x00000800,
87 UC_CATEGORY_MASK_Pd = 0x00001000,
88 UC_CATEGORY_MASK_Ps = 0x00002000,
89 UC_CATEGORY_MASK_Pe = 0x00004000,
90 UC_CATEGORY_MASK_Pi = 0x00008000,
91 UC_CATEGORY_MASK_Pf = 0x00010000,
92 UC_CATEGORY_MASK_Po = 0x00020000,
93 UC_CATEGORY_MASK_S = 0x003c0000,
94 UC_CATEGORY_MASK_Sm = 0x00040000,
95 UC_CATEGORY_MASK_Sc = 0x00080000,
96 UC_CATEGORY_MASK_Sk = 0x00100000,
97 UC_CATEGORY_MASK_So = 0x00200000,
98 UC_CATEGORY_MASK_Z = 0x01c00000,
99 UC_CATEGORY_MASK_Zs = 0x00400000,
100 UC_CATEGORY_MASK_Zl = 0x00800000,
101 UC_CATEGORY_MASK_Zp = 0x01000000,
102 UC_CATEGORY_MASK_C = 0x3e000000,
103 UC_CATEGORY_MASK_Cc = 0x02000000,
104 UC_CATEGORY_MASK_Cf = 0x04000000,
105 UC_CATEGORY_MASK_Cs = 0x08000000,
106 UC_CATEGORY_MASK_Co = 0x10000000,
107 UC_CATEGORY_MASK_Cn = 0x20000000
108};
109
110/* Predefined General category values. */
111extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_L;
112extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_LC;
113extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Lu;
114extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Ll;
115extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Lt;
116extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Lm;
117extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Lo;
118extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_M;
119extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Mn;
120extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Mc;
121extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Me;
122extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_N;
123extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Nd;
124extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Nl;
125extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_No;
126extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_P;
127extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Pc;
128extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Pd;
129extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Ps;
130extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Pe;
131extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Pi;
132extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Pf;
133extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Po;
134extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_S;
135extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Sm;
136extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Sc;
137extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Sk;
138extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_So;
139extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Z;
140extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Zs;
141extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Zl;
142extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Zp;
143extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_C;
144extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Cc;
145extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Cf;
146extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Cs;
147extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Co;
148extern LIBUNISTRING_DLL_VARIABLE const uc_general_category_t UC_CATEGORY_Cn;
149/* Non-public. */
150extern const uc_general_category_t _UC_CATEGORY_NONE;
151
152/* Alias names for predefined General category values. */
153#define UC_LETTER UC_CATEGORY_L
154#define UC_CASED_LETTER UC_CATEGORY_LC
155#define UC_UPPERCASE_LETTER UC_CATEGORY_Lu
156#define UC_LOWERCASE_LETTER UC_CATEGORY_Ll
157#define UC_TITLECASE_LETTER UC_CATEGORY_Lt
158#define UC_MODIFIER_LETTER UC_CATEGORY_Lm
159#define UC_OTHER_LETTER UC_CATEGORY_Lo
160#define UC_MARK UC_CATEGORY_M
161#define UC_NON_SPACING_MARK UC_CATEGORY_Mn
162#define UC_COMBINING_SPACING_MARK UC_CATEGORY_Mc
163#define UC_ENCLOSING_MARK UC_CATEGORY_Me
164#define UC_NUMBER UC_CATEGORY_N
165#define UC_DECIMAL_DIGIT_NUMBER UC_CATEGORY_Nd
166#define UC_LETTER_NUMBER UC_CATEGORY_Nl
167#define UC_OTHER_NUMBER UC_CATEGORY_No
168#define UC_PUNCTUATION UC_CATEGORY_P
169#define UC_CONNECTOR_PUNCTUATION UC_CATEGORY_Pc
170#define UC_DASH_PUNCTUATION UC_CATEGORY_Pd
171#define UC_OPEN_PUNCTUATION UC_CATEGORY_Ps /* a.k.a. UC_START_PUNCTUATION */
172#define UC_CLOSE_PUNCTUATION UC_CATEGORY_Pe /* a.k.a. UC_END_PUNCTUATION */
173#define UC_INITIAL_QUOTE_PUNCTUATION UC_CATEGORY_Pi
174#define UC_FINAL_QUOTE_PUNCTUATION UC_CATEGORY_Pf
175#define UC_OTHER_PUNCTUATION UC_CATEGORY_Po
176#define UC_SYMBOL UC_CATEGORY_S
177#define UC_MATH_SYMBOL UC_CATEGORY_Sm
178#define UC_CURRENCY_SYMBOL UC_CATEGORY_Sc
179#define UC_MODIFIER_SYMBOL UC_CATEGORY_Sk
180#define UC_OTHER_SYMBOL UC_CATEGORY_So
181#define UC_SEPARATOR UC_CATEGORY_Z
182#define UC_SPACE_SEPARATOR UC_CATEGORY_Zs
183#define UC_LINE_SEPARATOR UC_CATEGORY_Zl
184#define UC_PARAGRAPH_SEPARATOR UC_CATEGORY_Zp
185#define UC_OTHER UC_CATEGORY_C
186#define UC_CONTROL UC_CATEGORY_Cc
187#define UC_FORMAT UC_CATEGORY_Cf
188#define UC_SURROGATE UC_CATEGORY_Cs /* all of them are invalid characters */
189#define UC_PRIVATE_USE UC_CATEGORY_Co
190#define UC_UNASSIGNED UC_CATEGORY_Cn /* some of them are invalid characters */
191
192/* Return the union of two general categories.
193 This corresponds to the unions of the two sets of characters. */
194extern uc_general_category_t
195 uc_general_category_or (uc_general_category_t category1,
196 uc_general_category_t category2);
197
198/* Return the intersection of two general categories as bit masks.
199 This *does*not* correspond to the intersection of the two sets of
200 characters. */
201extern uc_general_category_t
202 uc_general_category_and (uc_general_category_t category1,
203 uc_general_category_t category2);
204
205/* Return the intersection of a general category with the complement of a
206 second general category, as bit masks.
207 This *does*not* correspond to the intersection with complement, when
208 viewing the categories as sets of characters. */
209extern uc_general_category_t
210 uc_general_category_and_not (uc_general_category_t category1,
211 uc_general_category_t category2);
212
213/* Return the name of a general category. */
214extern const char *
215 uc_general_category_name (uc_general_category_t category)
216 _UC_ATTRIBUTE_PURE;
217
218/* Return the long name of a general category. */
219extern const char *
220 uc_general_category_long_name (uc_general_category_t category)
221 _UC_ATTRIBUTE_PURE;
222
223/* Return the general category given by name, e.g. "Lu", or by long name,
224 e.g. "Uppercase Letter". */
225extern uc_general_category_t
226 uc_general_category_byname (const char *category_name)
227 _UC_ATTRIBUTE_PURE;
228
229/* Return the general category of a Unicode character. */
230extern uc_general_category_t
231 uc_general_category (ucs4_t uc)
232 _UC_ATTRIBUTE_PURE;
233
234/* Test whether a Unicode character belongs to a given category.
235 The CATEGORY argument can be the combination of several predefined
236 general categories. */
237extern bool
238 uc_is_general_category (ucs4_t uc, uc_general_category_t category)
239 _UC_ATTRIBUTE_PURE;
240/* Likewise. This function uses a big table comprising all categories. */
241extern bool
242 uc_is_general_category_withtable (ucs4_t uc, uint32_t bitmask)
243 _UC_ATTRIBUTE_CONST;
244
245/* ========================================================================= */
246
247/* Field 3 of Unicode Character Database: Canonical combining class. */
248
249/* The possible results of uc_combining_class (0..255) are described in
250 UCD.html. The list here is not definitive; more values can be added
251 in future versions. */
252enum
253{
254 UC_CCC_NR = 0, /* Not Reordered */
255 UC_CCC_OV = 1, /* Overlay */
256 UC_CCC_NK = 7, /* Nukta */
257 UC_CCC_KV = 8, /* Kana Voicing */
258 UC_CCC_VR = 9, /* Virama */
259 UC_CCC_ATBL = 200, /* Attached Below Left */
260 UC_CCC_ATB = 202, /* Attached Below */
261 UC_CCC_ATA = 214, /* Attached Above */
262 UC_CCC_ATAR = 216, /* Attached Above Right */
263 UC_CCC_BL = 218, /* Below Left */
264 UC_CCC_B = 220, /* Below */
265 UC_CCC_BR = 222, /* Below Right */
266 UC_CCC_L = 224, /* Left */
267 UC_CCC_R = 226, /* Right */
268 UC_CCC_AL = 228, /* Above Left */
269 UC_CCC_A = 230, /* Above */
270 UC_CCC_AR = 232, /* Above Right */
271 UC_CCC_DB = 233, /* Double Below */
272 UC_CCC_DA = 234, /* Double Above */
273 UC_CCC_IS = 240 /* Iota Subscript */
274};
275
276/* Return the canonical combining class of a Unicode character. */
277extern int
278 uc_combining_class (ucs4_t uc)
279 _UC_ATTRIBUTE_CONST;
280
281/* Return the name of a canonical combining class. */
282extern const char *
283 uc_combining_class_name (int ccc)
284 _UC_ATTRIBUTE_CONST;
285
286/* Return the long name of a canonical combining class. */
287extern const char *
288 uc_combining_class_long_name (int ccc)
289 _UC_ATTRIBUTE_CONST;
290
291/* Return the canonical combining class given by name, e.g. "BL", or by long
292 name, e.g. "Below Left". */
293extern int
294 uc_combining_class_byname (const char *ccc_name)
295 _UC_ATTRIBUTE_PURE;
296
297/* ========================================================================= */
298
299/* Field 4 of Unicode Character Database: Bidi class.
300 Before Unicode 4.0, this field was called "Bidirectional category". */
301
302enum
303{
304 UC_BIDI_L, /* Left-to-Right */
305 UC_BIDI_LRE, /* Left-to-Right Embedding */
306 UC_BIDI_LRO, /* Left-to-Right Override */
307 UC_BIDI_R, /* Right-to-Left */
308 UC_BIDI_AL, /* Right-to-Left Arabic */
309 UC_BIDI_RLE, /* Right-to-Left Embedding */
310 UC_BIDI_RLO, /* Right-to-Left Override */
311 UC_BIDI_PDF, /* Pop Directional Format */
312 UC_BIDI_EN, /* European Number */
313 UC_BIDI_ES, /* European Number Separator */
314 UC_BIDI_ET, /* European Number Terminator */
315 UC_BIDI_AN, /* Arabic Number */
316 UC_BIDI_CS, /* Common Number Separator */
317 UC_BIDI_NSM, /* Non-Spacing Mark */
318 UC_BIDI_BN, /* Boundary Neutral */
319 UC_BIDI_B, /* Paragraph Separator */
320 UC_BIDI_S, /* Segment Separator */
321 UC_BIDI_WS, /* Whitespace */
322 UC_BIDI_ON, /* Other Neutral */
323 UC_BIDI_LRI, /* Left-to-Right Isolate */
324 UC_BIDI_RLI, /* Right-to-Left Isolate */
325 UC_BIDI_FSI, /* First Strong Isolate */
326 UC_BIDI_PDI /* Pop Directional Isolate */
327};
328
329/* Return the name of a bidi class. */
330extern const char *
331 uc_bidi_class_name (int bidi_class)
332 _UC_ATTRIBUTE_CONST;
333/* Same; obsolete function name. */
334extern const char *
335 uc_bidi_category_name (int category)
336 _UC_ATTRIBUTE_CONST;
337
338/* Return the long name of a bidi class. */
339extern const char *
340 uc_bidi_class_long_name (int bidi_class)
341 _UC_ATTRIBUTE_CONST;
342
343/* Return the bidi class given by name, e.g. "LRE", or by long name, e.g.
344 "Left-to-Right Embedding". */
345extern int
346 uc_bidi_class_byname (const char *bidi_class_name)
347 _UC_ATTRIBUTE_PURE;
348/* Same; obsolete function name. */
349extern int
350 uc_bidi_category_byname (const char *category_name)
351 _UC_ATTRIBUTE_PURE;
352
353/* Return the bidi class of a Unicode character. */
354extern int
355 uc_bidi_class (ucs4_t uc)
356 _UC_ATTRIBUTE_CONST;
357/* Same; obsolete function name. */
358extern int
359 uc_bidi_category (ucs4_t uc)
360 _UC_ATTRIBUTE_CONST;
361
362/* Test whether a Unicode character belongs to a given bidi class. */
363extern bool
364 uc_is_bidi_class (ucs4_t uc, int bidi_class)
365 _UC_ATTRIBUTE_CONST;
366/* Same; obsolete function name. */
367extern bool
368 uc_is_bidi_category (ucs4_t uc, int category)
369 _UC_ATTRIBUTE_CONST;
370
371/* ========================================================================= */
372
373/* Field 5 of Unicode Character Database: Character decomposition mapping.
374 See "uninorm.h". */
375
376/* ========================================================================= */
377
378/* Field 6 of Unicode Character Database: Decimal digit value. */
379
380/* Return the decimal digit value of a Unicode character. */
381extern int
382 uc_decimal_value (ucs4_t uc)
383 _UC_ATTRIBUTE_CONST;
384
385/* ========================================================================= */
386
387/* Field 7 of Unicode Character Database: Digit value. */
388
389/* Return the digit value of a Unicode character. */
390extern int
391 uc_digit_value (ucs4_t uc)
392 _UC_ATTRIBUTE_CONST;
393
394/* ========================================================================= */
395
396/* Field 8 of Unicode Character Database: Numeric value. */
397
398/* Return the numeric value of a Unicode character. */
399typedef struct
400{
401 int numerator;
402 int denominator;
403}
404uc_fraction_t;
405extern uc_fraction_t
406 uc_numeric_value (ucs4_t uc)
407 _UC_ATTRIBUTE_CONST;
408
409/* ========================================================================= */
410
411/* Field 9 of Unicode Character Database: Mirrored. */
412
413/* Return the mirrored character of a Unicode character UC in *PUC. */
414extern bool
415 uc_mirror_char (ucs4_t uc, ucs4_t *puc);
416
417/* ========================================================================= */
418
419/* Field 10 of Unicode Character Database: Unicode 1.0 Name.
420 Not available in this library. */
421
422/* ========================================================================= */
423
424/* Field 11 of Unicode Character Database: ISO 10646 comment.
425 Not available in this library. */
426
427/* ========================================================================= */
428
429/* Field 12, 13, 14 of Unicode Character Database: Uppercase mapping,
430 lowercase mapping, titlecase mapping. See "unicase.h". */
431
432/* ========================================================================= */
433
434/* Field 2 of the file ArabicShaping.txt in the Unicode Character Database. */
435
436/* Possible joining types. */
437enum
438{
439 UC_JOINING_TYPE_U, /* Non_Joining */
440 UC_JOINING_TYPE_T, /* Transparent */
441 UC_JOINING_TYPE_C, /* Join_Causing */
442 UC_JOINING_TYPE_L, /* Left_Joining */
443 UC_JOINING_TYPE_R, /* Right_Joining */
444 UC_JOINING_TYPE_D /* Dual_Joining */
445};
446
447/* Return the name of a joining type. */
448extern const char *
449 uc_joining_type_name (int joining_type)
450 _UC_ATTRIBUTE_CONST;
451
452/* Return the long name of a joining type. */
453extern const char *
454 uc_joining_type_long_name (int joining_type)
455 _UC_ATTRIBUTE_CONST;
456
457/* Return the joining type given by name, e.g. "D", or by long name, e.g.
458 "Dual Joining". */
459extern int
460 uc_joining_type_byname (const char *joining_type_name)
461 _UC_ATTRIBUTE_PURE;
462
463/* Return the joining type of a Unicode character. */
464extern int
465 uc_joining_type (ucs4_t uc)
466 _UC_ATTRIBUTE_CONST;
467
468/* ========================================================================= */
469
470/* Field 3 of the file ArabicShaping.txt in the Unicode Character Database. */
471
472/* Possible joining groups.
473 This enumeration may be extended in the future. */
474enum
475{
476 UC_JOINING_GROUP_NONE, /* No_Joining_Group */
477 UC_JOINING_GROUP_AIN, /* Ain */
478 UC_JOINING_GROUP_ALAPH, /* Alaph */
479 UC_JOINING_GROUP_ALEF, /* Alef */
480 UC_JOINING_GROUP_BEH, /* Beh */
481 UC_JOINING_GROUP_BETH, /* Beth */
482 UC_JOINING_GROUP_BURUSHASKI_YEH_BARREE, /* Burushaski_Yeh_Barree */
483 UC_JOINING_GROUP_DAL, /* Dal */
484 UC_JOINING_GROUP_DALATH_RISH, /* Dalath_Rish */
485 UC_JOINING_GROUP_E, /* E */
486 UC_JOINING_GROUP_FARSI_YEH, /* Farsi_Yeh */
487 UC_JOINING_GROUP_FE, /* Fe */
488 UC_JOINING_GROUP_FEH, /* Feh */
489 UC_JOINING_GROUP_FINAL_SEMKATH, /* Final_Semkath */
490 UC_JOINING_GROUP_GAF, /* Gaf */
491 UC_JOINING_GROUP_GAMAL, /* Gamal */
492 UC_JOINING_GROUP_HAH, /* Hah */
493 UC_JOINING_GROUP_HE, /* He */
494 UC_JOINING_GROUP_HEH, /* Heh */
495 UC_JOINING_GROUP_HEH_GOAL, /* Heh_Goal */
496 UC_JOINING_GROUP_HETH, /* Heth */
497 UC_JOINING_GROUP_KAF, /* Kaf */
498 UC_JOINING_GROUP_KAPH, /* Kaph */
499 UC_JOINING_GROUP_KHAPH, /* Khaph */
500 UC_JOINING_GROUP_KNOTTED_HEH, /* Knotted_Heh */
501 UC_JOINING_GROUP_LAM, /* Lam */
502 UC_JOINING_GROUP_LAMADH, /* Lamadh */
503 UC_JOINING_GROUP_MEEM, /* Meem */
504 UC_JOINING_GROUP_MIM, /* Mim */
505 UC_JOINING_GROUP_NOON, /* Noon */
506 UC_JOINING_GROUP_NUN, /* Nun */
507 UC_JOINING_GROUP_NYA, /* Nya */
508 UC_JOINING_GROUP_PE, /* Pe */
509 UC_JOINING_GROUP_QAF, /* Qaf */
510 UC_JOINING_GROUP_QAPH, /* Qaph */
511 UC_JOINING_GROUP_REH, /* Reh */
512 UC_JOINING_GROUP_REVERSED_PE, /* Reversed_Pe */
513 UC_JOINING_GROUP_SAD, /* Sad */
514 UC_JOINING_GROUP_SADHE, /* Sadhe */
515 UC_JOINING_GROUP_SEEN, /* Seen */
516 UC_JOINING_GROUP_SEMKATH, /* Semkath */
517 UC_JOINING_GROUP_SHIN, /* Shin */
518 UC_JOINING_GROUP_SWASH_KAF, /* Swash_Kaf */
519 UC_JOINING_GROUP_SYRIAC_WAW, /* Syriac_Waw */
520 UC_JOINING_GROUP_TAH, /* Tah */
521 UC_JOINING_GROUP_TAW, /* Taw */
522 UC_JOINING_GROUP_TEH_MARBUTA, /* Teh_Marbuta */
523 UC_JOINING_GROUP_TEH_MARBUTA_GOAL, /* Teh_Marbuta_Goal */
524 UC_JOINING_GROUP_TETH, /* Teth */
525 UC_JOINING_GROUP_WAW, /* Waw */
526 UC_JOINING_GROUP_YEH, /* Yeh */
527 UC_JOINING_GROUP_YEH_BARREE, /* Yeh_Barree */
528 UC_JOINING_GROUP_YEH_WITH_TAIL, /* Yeh_With_Tail */
529 UC_JOINING_GROUP_YUDH, /* Yudh */
530 UC_JOINING_GROUP_YUDH_HE, /* Yudh_He */
531 UC_JOINING_GROUP_ZAIN, /* Zain */
532 UC_JOINING_GROUP_ZHAIN, /* Zhain */
533 UC_JOINING_GROUP_ROHINGYA_YEH, /* Rohingya_Yeh */
534 UC_JOINING_GROUP_STRAIGHT_WAW, /* Straight_Waw */
535 UC_JOINING_GROUP_MANICHAEAN_ALEPH, /* Manichaean_Aleph */
536 UC_JOINING_GROUP_MANICHAEAN_BETH, /* Manichaean_Beth */
537 UC_JOINING_GROUP_MANICHAEAN_GIMEL, /* Manichaean_Gimel */
538 UC_JOINING_GROUP_MANICHAEAN_DALETH, /* Manichaean_Daleth */
539 UC_JOINING_GROUP_MANICHAEAN_WAW, /* Manichaean_Waw */
540 UC_JOINING_GROUP_MANICHAEAN_ZAYIN, /* Manichaean_Zayin */
541 UC_JOINING_GROUP_MANICHAEAN_HETH, /* Manichaean_Heth */
542 UC_JOINING_GROUP_MANICHAEAN_TETH, /* Manichaean_Teth */
543 UC_JOINING_GROUP_MANICHAEAN_YODH, /* Manichaean_Yodh */
544 UC_JOINING_GROUP_MANICHAEAN_KAPH, /* Manichaean_Kaph */
545 UC_JOINING_GROUP_MANICHAEAN_LAMEDH, /* Manichaean_Lamedh */
546 UC_JOINING_GROUP_MANICHAEAN_DHAMEDH, /* Manichaean_Dhamedh */
547 UC_JOINING_GROUP_MANICHAEAN_THAMEDH, /* Manichaean_Thamedh */
548 UC_JOINING_GROUP_MANICHAEAN_MEM, /* Manichaean_Mem */
549 UC_JOINING_GROUP_MANICHAEAN_NUN, /* Manichaean_Nun */
550 UC_JOINING_GROUP_MANICHAEAN_SAMEKH, /* Manichaean_Aleph */
551 UC_JOINING_GROUP_MANICHAEAN_AYIN, /* Manichaean_Ayin */
552 UC_JOINING_GROUP_MANICHAEAN_PE, /* Manichaean_Pe */
553 UC_JOINING_GROUP_MANICHAEAN_SADHE, /* Manichaean_Sadhe */
554 UC_JOINING_GROUP_MANICHAEAN_QOPH, /* Manichaean_Qoph */
555 UC_JOINING_GROUP_MANICHAEAN_RESH, /* Manichaean_Resh */
556 UC_JOINING_GROUP_MANICHAEAN_TAW, /* Manichaean_Taw */
557 UC_JOINING_GROUP_MANICHAEAN_ONE, /* Manichaean_One */
558 UC_JOINING_GROUP_MANICHAEAN_FIVE, /* Manichaean_Five */
559 UC_JOINING_GROUP_MANICHAEAN_TEN, /* Manichaean_Ten */
560 UC_JOINING_GROUP_MANICHAEAN_TWENTY, /* Manichaean_Twenty */
561 UC_JOINING_GROUP_MANICHAEAN_HUNDRED, /* Manichaean_Hundred */
562 UC_JOINING_GROUP_AFRICAN_FEH, /* African_Feh */
563 UC_JOINING_GROUP_AFRICAN_QAF, /* African_Qaf */
564 UC_JOINING_GROUP_AFRICAN_NOON, /* African_Noon */
565 UC_JOINING_GROUP_MALAYALAM_NGA, /* Malayalam_Nga */
566 UC_JOINING_GROUP_MALAYALAM_JA, /* Malayalam_Ja */
567 UC_JOINING_GROUP_MALAYALAM_NYA, /* Malayalam_Nya */
568 UC_JOINING_GROUP_MALAYALAM_TTA, /* Malayalam_Tta */
569 UC_JOINING_GROUP_MALAYALAM_NNA, /* Malayalam_Nna */
570 UC_JOINING_GROUP_MALAYALAM_NNNA, /* Malayalam_Nnna */
571 UC_JOINING_GROUP_MALAYALAM_BHA, /* Malayalam_Bha */
572 UC_JOINING_GROUP_MALAYALAM_RA, /* Malayalam_Ra */
573 UC_JOINING_GROUP_MALAYALAM_LLA, /* Malayalam_Lla */
574 UC_JOINING_GROUP_MALAYALAM_LLLA, /* Malayalam_Llla */
575 UC_JOINING_GROUP_MALAYALAM_SSA, /* Malayalam_Ssa */
576 UC_JOINING_GROUP_HANIFI_ROHINGYA_PA, /* Hanifi_Rohingya_Pa */
577 UC_JOINING_GROUP_HANIFI_ROHINGYA_KINNA_YA, /* Hanifi_Rohingya_Kinna_Ya */
578 UC_JOINING_GROUP_THIN_YEH, /* Thin_Yeh */
579 UC_JOINING_GROUP_VERTICAL_TAIL, /* Vertical_Tail */
580 UC_JOINING_GROUP_KASHMIRI_YEH, /* Kashmiri_Yeh */
581 UC_JOINING_GROUP_THIN_NOON /* Thin_Noon */
582};
583
584/* Return the name of a joining group. */
585extern const char *
586 uc_joining_group_name (int joining_group)
587 _UC_ATTRIBUTE_CONST;
588
589/* Return the joining group given by name, e.g. "Teh_Marbuta". */
590extern int
591 uc_joining_group_byname (const char *joining_group_name)
592 _UC_ATTRIBUTE_PURE;
593
594/* Return the joining group of a Unicode character. */
595extern int
596 uc_joining_group (ucs4_t uc)
597 _UC_ATTRIBUTE_CONST;
598
599/* ========================================================================= */
600
601/* Common API for properties. */
602
603/* Data type denoting a property. This is not just a number, but rather a
604 pointer to the test functions, so that programs that use only few of the
605 properties don't have a link-time dependency towards all the tables. */
606typedef struct
607{
608 bool (*test_fn) (ucs4_t uc);
609}
610uc_property_t;
611
612/* Predefined properties. */
613/* General. */
614extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_WHITE_SPACE;
615extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_ALPHABETIC;
616extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_OTHER_ALPHABETIC;
617extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_NOT_A_CHARACTER;
618extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_DEFAULT_IGNORABLE_CODE_POINT;
619extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_OTHER_DEFAULT_IGNORABLE_CODE_POINT;
620extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_DEPRECATED;
621extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_LOGICAL_ORDER_EXCEPTION;
622extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_VARIATION_SELECTOR;
623extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_PRIVATE_USE;
624extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_UNASSIGNED_CODE_VALUE;
625/* Case. */
626extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_UPPERCASE;
627extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_OTHER_UPPERCASE;
628extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_LOWERCASE;
629extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_OTHER_LOWERCASE;
630extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_TITLECASE;
631extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_CASED;
632extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_CASE_IGNORABLE;
633extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_CHANGES_WHEN_LOWERCASED;
634extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_CHANGES_WHEN_UPPERCASED;
635extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_CHANGES_WHEN_TITLECASED;
636extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_CHANGES_WHEN_CASEFOLDED;
637extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_CHANGES_WHEN_CASEMAPPED;
638extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_SOFT_DOTTED;
639/* Identifiers. */
640extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_ID_START;
641extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_OTHER_ID_START;
642extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_ID_CONTINUE;
643extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_OTHER_ID_CONTINUE;
644extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_XID_START;
645extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_XID_CONTINUE;
646extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_ID_COMPAT_MATH_START;
647extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_ID_COMPAT_MATH_CONTINUE;
648extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_PATTERN_WHITE_SPACE;
649extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_PATTERN_SYNTAX;
650/* Shaping and rendering. */
651extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_JOIN_CONTROL;
652extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_GRAPHEME_BASE;
653extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_GRAPHEME_EXTEND;
654extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_OTHER_GRAPHEME_EXTEND;
655extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_GRAPHEME_LINK;
656extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_MODIFIER_COMBINING_MARK;
657/* Bidi. */
658extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_CONTROL;
659extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_LEFT_TO_RIGHT;
660extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_HEBREW_RIGHT_TO_LEFT;
661extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_ARABIC_RIGHT_TO_LEFT;
662extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_EUROPEAN_DIGIT;
663extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_EUR_NUM_SEPARATOR;
664extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_EUR_NUM_TERMINATOR;
665extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_ARABIC_DIGIT;
666extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_COMMON_SEPARATOR;
667extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_BLOCK_SEPARATOR;
668extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_SEGMENT_SEPARATOR;
669extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_WHITESPACE;
670extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_NON_SPACING_MARK;
671extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_BOUNDARY_NEUTRAL;
672extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_PDF;
673extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_EMBEDDING_OR_OVERRIDE;
674extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_BIDI_OTHER_NEUTRAL;
675/* Numeric. */
676extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_HEX_DIGIT;
677extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_ASCII_HEX_DIGIT;
678/* CJK. */
679extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_IDEOGRAPHIC;
680extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_UNIFIED_IDEOGRAPH;
681extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_RADICAL;
682extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_IDS_UNARY_OPERATOR;
683extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_IDS_BINARY_OPERATOR;
684extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_IDS_TRINARY_OPERATOR;
685/* Emoji. */
686extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_EMOJI;
687extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_EMOJI_PRESENTATION;
688extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_EMOJI_MODIFIER;
689extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_EMOJI_MODIFIER_BASE;
690extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_EMOJI_COMPONENT;
691extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_EXTENDED_PICTOGRAPHIC;
692/* Misc. */
693extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_ZERO_WIDTH;
694extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_SPACE;
695extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_NON_BREAK;
696extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_ISO_CONTROL;
697extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_FORMAT_CONTROL;
698extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_PREPENDED_CONCATENATION_MARK;
699extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_DASH;
700extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_HYPHEN;
701extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_PUNCTUATION;
702extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_LINE_SEPARATOR;
703extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_PARAGRAPH_SEPARATOR;
704extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_QUOTATION_MARK;
705extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_SENTENCE_TERMINAL;
706extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_TERMINAL_PUNCTUATION;
707extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_CURRENCY_SYMBOL;
708extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_MATH;
709extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_OTHER_MATH;
710extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_PAIRED_PUNCTUATION;
711extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_LEFT_OF_PAIR;
712extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_COMBINING;
713extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_COMPOSITE;
714extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_DECIMAL_DIGIT;
715extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_NUMERIC;
716extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_DIACRITIC;
717extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_EXTENDER;
718extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_IGNORABLE_CONTROL;
719extern LIBUNISTRING_DLL_VARIABLE const uc_property_t UC_PROPERTY_REGIONAL_INDICATOR;
720
721/* Return the property given by name, e.g. "White space". */
722extern uc_property_t
723 uc_property_byname (const char *property_name);
724
725/* Test whether a property is valid. */
726#define uc_property_is_valid(property) ((property).test_fn != NULL)
727
728/* Test whether a Unicode character has a given property. */
729extern bool
730 uc_is_property (ucs4_t uc, uc_property_t property);
731extern bool uc_is_property_white_space (ucs4_t uc)
732 _UC_ATTRIBUTE_CONST;
733extern bool uc_is_property_alphabetic (ucs4_t uc)
734 _UC_ATTRIBUTE_CONST;
735extern bool uc_is_property_other_alphabetic (ucs4_t uc)
736 _UC_ATTRIBUTE_CONST;
737extern bool uc_is_property_not_a_character (ucs4_t uc)
738 _UC_ATTRIBUTE_CONST;
739extern bool uc_is_property_default_ignorable_code_point (ucs4_t uc)
740 _UC_ATTRIBUTE_CONST;
741extern bool uc_is_property_other_default_ignorable_code_point (ucs4_t uc)
742 _UC_ATTRIBUTE_CONST;
743extern bool uc_is_property_deprecated (ucs4_t uc)
744 _UC_ATTRIBUTE_CONST;
745extern bool uc_is_property_logical_order_exception (ucs4_t uc)
746 _UC_ATTRIBUTE_CONST;
747extern bool uc_is_property_variation_selector (ucs4_t uc)
748 _UC_ATTRIBUTE_CONST;
749extern bool uc_is_property_private_use (ucs4_t uc)
750 _UC_ATTRIBUTE_CONST;
751extern bool uc_is_property_unassigned_code_value (ucs4_t uc)
752 _UC_ATTRIBUTE_CONST;
753extern bool uc_is_property_uppercase (ucs4_t uc)
754 _UC_ATTRIBUTE_CONST;
755extern bool uc_is_property_other_uppercase (ucs4_t uc)
756 _UC_ATTRIBUTE_CONST;
757extern bool uc_is_property_lowercase (ucs4_t uc)
758 _UC_ATTRIBUTE_CONST;
759extern bool uc_is_property_other_lowercase (ucs4_t uc)
760 _UC_ATTRIBUTE_CONST;
761extern bool uc_is_property_titlecase (ucs4_t uc)
762 _UC_ATTRIBUTE_CONST;
763extern bool uc_is_property_cased (ucs4_t uc)
764 _UC_ATTRIBUTE_CONST;
765extern bool uc_is_property_case_ignorable (ucs4_t uc)
766 _UC_ATTRIBUTE_CONST;
767extern bool uc_is_property_changes_when_lowercased (ucs4_t uc)
768 _UC_ATTRIBUTE_CONST;
769extern bool uc_is_property_changes_when_uppercased (ucs4_t uc)
770 _UC_ATTRIBUTE_CONST;
771extern bool uc_is_property_changes_when_titlecased (ucs4_t uc)
772 _UC_ATTRIBUTE_CONST;
773extern bool uc_is_property_changes_when_casefolded (ucs4_t uc)
774 _UC_ATTRIBUTE_CONST;
775extern bool uc_is_property_changes_when_casemapped (ucs4_t uc)
776 _UC_ATTRIBUTE_CONST;
777extern bool uc_is_property_soft_dotted (ucs4_t uc)
778 _UC_ATTRIBUTE_CONST;
779extern bool uc_is_property_id_start (ucs4_t uc)
780 _UC_ATTRIBUTE_CONST;
781extern bool uc_is_property_other_id_start (ucs4_t uc)
782 _UC_ATTRIBUTE_CONST;
783extern bool uc_is_property_id_continue (ucs4_t uc)
784 _UC_ATTRIBUTE_CONST;
785extern bool uc_is_property_other_id_continue (ucs4_t uc)
786 _UC_ATTRIBUTE_CONST;
787extern bool uc_is_property_xid_start (ucs4_t uc)
788 _UC_ATTRIBUTE_CONST;
789extern bool uc_is_property_xid_continue (ucs4_t uc)
790 _UC_ATTRIBUTE_CONST;
791extern bool uc_is_property_id_compat_math_start (ucs4_t uc)
792 _UC_ATTRIBUTE_CONST;
793extern bool uc_is_property_id_compat_math_continue (ucs4_t uc)
794 _UC_ATTRIBUTE_CONST;
795extern bool uc_is_property_pattern_white_space (ucs4_t uc)
796 _UC_ATTRIBUTE_CONST;
797extern bool uc_is_property_pattern_syntax (ucs4_t uc)
798 _UC_ATTRIBUTE_CONST;
799extern bool uc_is_property_join_control (ucs4_t uc)
800 _UC_ATTRIBUTE_CONST;
801extern bool uc_is_property_grapheme_base (ucs4_t uc)
802 _UC_ATTRIBUTE_CONST;
803extern bool uc_is_property_grapheme_extend (ucs4_t uc)
804 _UC_ATTRIBUTE_CONST;
805extern bool uc_is_property_other_grapheme_extend (ucs4_t uc)
806 _UC_ATTRIBUTE_CONST;
807extern bool uc_is_property_grapheme_link (ucs4_t uc)
808 _UC_ATTRIBUTE_CONST;
809extern bool uc_is_property_modifier_combining_mark (ucs4_t uc)
810 _UC_ATTRIBUTE_CONST;
811extern bool uc_is_property_bidi_control (ucs4_t uc)
812 _UC_ATTRIBUTE_CONST;
813extern bool uc_is_property_bidi_left_to_right (ucs4_t uc)
814 _UC_ATTRIBUTE_CONST;
815extern bool uc_is_property_bidi_hebrew_right_to_left (ucs4_t uc)
816 _UC_ATTRIBUTE_CONST;
817extern bool uc_is_property_bidi_arabic_right_to_left (ucs4_t uc)
818 _UC_ATTRIBUTE_CONST;
819extern bool uc_is_property_bidi_european_digit (ucs4_t uc)
820 _UC_ATTRIBUTE_CONST;
821extern bool uc_is_property_bidi_eur_num_separator (ucs4_t uc)
822 _UC_ATTRIBUTE_CONST;
823extern bool uc_is_property_bidi_eur_num_terminator (ucs4_t uc)
824 _UC_ATTRIBUTE_CONST;
825extern bool uc_is_property_bidi_arabic_digit (ucs4_t uc)
826 _UC_ATTRIBUTE_CONST;
827extern bool uc_is_property_bidi_common_separator (ucs4_t uc)
828 _UC_ATTRIBUTE_CONST;
829extern bool uc_is_property_bidi_block_separator (ucs4_t uc)
830 _UC_ATTRIBUTE_CONST;
831extern bool uc_is_property_bidi_segment_separator (ucs4_t uc)
832 _UC_ATTRIBUTE_CONST;
833extern bool uc_is_property_bidi_whitespace (ucs4_t uc)
834 _UC_ATTRIBUTE_CONST;
835extern bool uc_is_property_bidi_non_spacing_mark (ucs4_t uc)
836 _UC_ATTRIBUTE_CONST;
837extern bool uc_is_property_bidi_boundary_neutral (ucs4_t uc)
838 _UC_ATTRIBUTE_CONST;
839extern bool uc_is_property_bidi_pdf (ucs4_t uc)
840 _UC_ATTRIBUTE_CONST;
841extern bool uc_is_property_bidi_embedding_or_override (ucs4_t uc)
842 _UC_ATTRIBUTE_CONST;
843extern bool uc_is_property_bidi_other_neutral (ucs4_t uc)
844 _UC_ATTRIBUTE_CONST;
845extern bool uc_is_property_hex_digit (ucs4_t uc)
846 _UC_ATTRIBUTE_CONST;
847extern bool uc_is_property_ascii_hex_digit (ucs4_t uc)
848 _UC_ATTRIBUTE_CONST;
849extern bool uc_is_property_ideographic (ucs4_t uc)
850 _UC_ATTRIBUTE_CONST;
851extern bool uc_is_property_unified_ideograph (ucs4_t uc)
852 _UC_ATTRIBUTE_CONST;
853extern bool uc_is_property_radical (ucs4_t uc)
854 _UC_ATTRIBUTE_CONST;
855extern bool uc_is_property_ids_unary_operator (ucs4_t uc)
856 _UC_ATTRIBUTE_CONST;
857extern bool uc_is_property_ids_binary_operator (ucs4_t uc)
858 _UC_ATTRIBUTE_CONST;
859extern bool uc_is_property_ids_trinary_operator (ucs4_t uc)
860 _UC_ATTRIBUTE_CONST;
861extern bool uc_is_property_emoji (ucs4_t uc)
862 _UC_ATTRIBUTE_CONST;
863extern bool uc_is_property_emoji_presentation (ucs4_t uc)
864 _UC_ATTRIBUTE_CONST;
865extern bool uc_is_property_emoji_modifier (ucs4_t uc)
866 _UC_ATTRIBUTE_CONST;
867extern bool uc_is_property_emoji_modifier_base (ucs4_t uc)
868 _UC_ATTRIBUTE_CONST;
869extern bool uc_is_property_emoji_component (ucs4_t uc)
870 _UC_ATTRIBUTE_CONST;
871extern bool uc_is_property_extended_pictographic (ucs4_t uc)
872 _UC_ATTRIBUTE_CONST;
873extern bool uc_is_property_zero_width (ucs4_t uc)
874 _UC_ATTRIBUTE_CONST;
875extern bool uc_is_property_space (ucs4_t uc)
876 _UC_ATTRIBUTE_CONST;
877extern bool uc_is_property_non_break (ucs4_t uc)
878 _UC_ATTRIBUTE_CONST;
879extern bool uc_is_property_iso_control (ucs4_t uc)
880 _UC_ATTRIBUTE_CONST;
881extern bool uc_is_property_format_control (ucs4_t uc)
882 _UC_ATTRIBUTE_CONST;
883extern bool uc_is_property_prepended_concatenation_mark (ucs4_t uc)
884 _UC_ATTRIBUTE_CONST;
885extern bool uc_is_property_dash (ucs4_t uc)
886 _UC_ATTRIBUTE_CONST;
887extern bool uc_is_property_hyphen (ucs4_t uc)
888 _UC_ATTRIBUTE_CONST;
889extern bool uc_is_property_punctuation (ucs4_t uc)
890 _UC_ATTRIBUTE_CONST;
891extern bool uc_is_property_line_separator (ucs4_t uc)
892 _UC_ATTRIBUTE_CONST;
893extern bool uc_is_property_paragraph_separator (ucs4_t uc)
894 _UC_ATTRIBUTE_CONST;
895extern bool uc_is_property_quotation_mark (ucs4_t uc)
896 _UC_ATTRIBUTE_CONST;
897extern bool uc_is_property_sentence_terminal (ucs4_t uc)
898 _UC_ATTRIBUTE_CONST;
899extern bool uc_is_property_terminal_punctuation (ucs4_t uc)
900 _UC_ATTRIBUTE_CONST;
901extern bool uc_is_property_currency_symbol (ucs4_t uc)
902 _UC_ATTRIBUTE_CONST;
903extern bool uc_is_property_math (ucs4_t uc)
904 _UC_ATTRIBUTE_CONST;
905extern bool uc_is_property_other_math (ucs4_t uc)
906 _UC_ATTRIBUTE_CONST;
907extern bool uc_is_property_paired_punctuation (ucs4_t uc)
908 _UC_ATTRIBUTE_CONST;
909extern bool uc_is_property_left_of_pair (ucs4_t uc)
910 _UC_ATTRIBUTE_CONST;
911extern bool uc_is_property_combining (ucs4_t uc)
912 _UC_ATTRIBUTE_CONST;
913extern bool uc_is_property_composite (ucs4_t uc)
914 _UC_ATTRIBUTE_CONST;
915extern bool uc_is_property_decimal_digit (ucs4_t uc)
916 _UC_ATTRIBUTE_CONST;
917extern bool uc_is_property_numeric (ucs4_t uc)
918 _UC_ATTRIBUTE_CONST;
919extern bool uc_is_property_diacritic (ucs4_t uc)
920 _UC_ATTRIBUTE_CONST;
921extern bool uc_is_property_extender (ucs4_t uc)
922 _UC_ATTRIBUTE_CONST;
923extern bool uc_is_property_ignorable_control (ucs4_t uc)
924 _UC_ATTRIBUTE_CONST;
925extern bool uc_is_property_regional_indicator (ucs4_t uc)
926 _UC_ATTRIBUTE_CONST;
927
928/* ========================================================================= */
929
930/* Other attributes. */
931
932/* ------------------------------------------------------------------------- */
933
934/* Indic_Conjunct_Break (InCB): from the file DerivedCoreProperties.txt
935 in the Unicode Character Database. */
936
937/* Possible values of the Indic_Conjunct_Break attribute.
938 This enumeration may be extended in the future. */
939enum
940{
941 UC_INDIC_CONJUNCT_BREAK_NONE, /* None */
942 UC_INDIC_CONJUNCT_BREAK_CONSONANT, /* Consonant */
943 UC_INDIC_CONJUNCT_BREAK_LINKER, /* Linker */
944 UC_INDIC_CONJUNCT_BREAK_EXTEND /* Extend */
945};
946
947/* Return the name of an Indic_Conjunct_Break value. */
948extern const char *
949 uc_indic_conjunct_break_name (int indic_conjunct_break)
950 _UC_ATTRIBUTE_CONST;
951
952/* Return the Indic_Conjunct_Break value given by name, e.g. "Consonant". */
953extern int
954 uc_indic_conjunct_break_byname (const char *indic_conjunct_break_name)
955 _UC_ATTRIBUTE_PURE;
956
957/* Return the Indic_Conjunct_Break attribute of a Unicode character. */
958extern int
959 uc_indic_conjunct_break (ucs4_t uc)
960 _UC_ATTRIBUTE_CONST;
961
962/* ========================================================================= */
963
964/* Subdivision of the Unicode characters into scripts. */
965
966typedef struct
967{
968 unsigned int code : 21;
969 unsigned int start : 1;
970 unsigned int end : 1;
971}
972uc_interval_t;
973typedef struct
974{
975 unsigned int nintervals;
976 const uc_interval_t *intervals;
977 const char *name;
978}
979uc_script_t;
980
981/* Return the script of a Unicode character. */
982extern const uc_script_t *
983 uc_script (ucs4_t uc)
984 _UC_ATTRIBUTE_CONST;
985
986/* Return the script given by name, e.g. "HAN". */
987extern const uc_script_t *
988 uc_script_byname (const char *script_name)
989 _UC_ATTRIBUTE_PURE;
990
991/* Test whether a Unicode character belongs to a given script. */
992extern bool
993 uc_is_script (ucs4_t uc, const uc_script_t *script)
994 _UC_ATTRIBUTE_PURE;
995
996/* Get the list of all scripts. */
997extern void
998 uc_all_scripts (const uc_script_t **scripts, size_t *count);
999
1000/* ========================================================================= */
1001
1002/* Subdivision of the Unicode character range into blocks. */
1003
1004typedef struct
1005{
1006 ucs4_t start;
1007 ucs4_t end;
1008 const char *name;
1009}
1010uc_block_t;
1011
1012/* Return the block a character belongs to. */
1013extern const uc_block_t *
1014 uc_block (ucs4_t uc)
1015 _UC_ATTRIBUTE_CONST;
1016
1017/* Test whether a Unicode character belongs to a given block. */
1018extern bool
1019 uc_is_block (ucs4_t uc, const uc_block_t *block)
1020 _UC_ATTRIBUTE_PURE;
1021
1022/* Get the list of all blocks. */
1023extern void
1024 uc_all_blocks (const uc_block_t **blocks, size_t *count);
1025
1026/* ========================================================================= */
1027
1028/* Properties taken from language standards. */
1029
1030/* Test whether a Unicode character is considered whitespace in ISO C 99. */
1031extern bool
1032 uc_is_c_whitespace (ucs4_t uc)
1033 _UC_ATTRIBUTE_CONST;
1034
1035/* Test whether a Unicode character is considered whitespace in Java. */
1036extern bool
1037 uc_is_java_whitespace (ucs4_t uc)
1038 _UC_ATTRIBUTE_CONST;
1039
1040enum
1041{
1042 UC_IDENTIFIER_START, /* valid as first or subsequent character */
1043 UC_IDENTIFIER_VALID, /* valid as subsequent character only */
1044 UC_IDENTIFIER_INVALID, /* not valid */
1045 UC_IDENTIFIER_IGNORABLE /* ignorable (Java only) */
1046};
1047
1048/* Return the categorization of a Unicode character w.r.t. the ISO C 99
1049 identifier syntax. */
1050extern int
1051 uc_c_ident_category (ucs4_t uc)
1052 _UC_ATTRIBUTE_CONST;
1053
1054/* Return the categorization of a Unicode character w.r.t. the Java
1055 identifier syntax. */
1056extern int
1057 uc_java_ident_category (ucs4_t uc)
1058 _UC_ATTRIBUTE_CONST;
1059
1060/* ========================================================================= */
1061
1062/* Like ISO C <ctype.h> and <wctype.h>. These functions are deprecated,
1063 because this set of functions was designed with ASCII in mind and cannot
1064 reflect the more diverse reality of the Unicode character set. But they
1065 can be a quick-and-dirty porting aid when migrating from wchar_t APIs
1066 to Unicode strings. */
1067
1068/* Test for any character for which 'uc_is_alpha' or 'uc_is_digit' is true. */
1069extern bool
1070 uc_is_alnum (ucs4_t uc)
1071 _UC_ATTRIBUTE_CONST;
1072
1073/* Test for any character for which 'uc_is_upper' or 'uc_is_lower' is true,
1074 or any character that is one of a locale-specific set of characters for
1075 which none of 'uc_is_cntrl', 'uc_is_digit', 'uc_is_punct', or 'uc_is_space'
1076 is true. */
1077extern bool
1078 uc_is_alpha (ucs4_t uc)
1079 _UC_ATTRIBUTE_CONST;
1080
1081/* Test for any control character. */
1082extern bool
1083 uc_is_cntrl (ucs4_t uc)
1084 _UC_ATTRIBUTE_CONST;
1085
1086/* Test for any character that corresponds to a decimal-digit character. */
1087extern bool
1088 uc_is_digit (ucs4_t uc)
1089 _UC_ATTRIBUTE_CONST;
1090
1091/* Test for any character for which 'uc_is_print' is true and 'uc_is_space'
1092 is false. */
1093extern bool
1094 uc_is_graph (ucs4_t uc)
1095 _UC_ATTRIBUTE_CONST;
1096
1097/* Test for any character that corresponds to a lowercase letter or is one
1098 of a locale-specific set of characters for which none of 'uc_is_cntrl',
1099 'uc_is_digit', 'uc_is_punct', or 'uc_is_space' is true. */
1100extern bool
1101 uc_is_lower (ucs4_t uc)
1102 _UC_ATTRIBUTE_CONST;
1103
1104/* Test for any printing character. */
1105extern bool
1106 uc_is_print (ucs4_t uc)
1107 _UC_ATTRIBUTE_CONST;
1108
1109/* Test for any printing character that is one of a locale-specific set of
1110 characters for which neither 'uc_is_space' nor 'uc_is_alnum' is true. */
1111extern bool
1112 uc_is_punct (ucs4_t uc)
1113 _UC_ATTRIBUTE_CONST;
1114
1115/* Test for any character that corresponds to a locale-specific set of
1116 characters for which none of 'uc_is_alnum', 'uc_is_graph', or 'uc_is_punct'
1117 is true. */
1118extern bool
1119 uc_is_space (ucs4_t uc)
1120 _UC_ATTRIBUTE_CONST;
1121
1122/* Test for any character that corresponds to an uppercase letter or is one
1123 of a locale-specific set of character for which none of 'uc_is_cntrl',
1124 'uc_is_digit', 'uc_is_punct', or 'uc_is_space' is true. */
1125extern bool
1126 uc_is_upper (ucs4_t uc)
1127 _UC_ATTRIBUTE_CONST;
1128
1129/* Test for any character that corresponds to a hexadecimal-digit
1130 character. */
1131extern bool
1132 uc_is_xdigit (ucs4_t uc)
1133 _UC_ATTRIBUTE_CONST;
1134
1135/* GNU extension. */
1136/* Test for any character that corresponds to a standard blank character or
1137 a locale-specific set of characters for which 'uc_is_alnum' is false. */
1138extern bool
1139 uc_is_blank (ucs4_t uc)
1140 _UC_ATTRIBUTE_CONST;
1141
1142/* ========================================================================= */
1143
1144#ifdef __cplusplus
1145}
1146#endif
1147
1148#endif /* _UNICTYPE_H */
diff --git a/gl/unictype.in.h b/gl/unictype.in.h
new file mode 100644
index 00000000..3818da91
--- /dev/null
+++ b/gl/unictype.in.h
@@ -0,0 +1,1146 @@
1/* Unicode character classification and properties.
2 Copyright (C) 2002, 2005-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#ifndef _UNICTYPE_H
18#define _UNICTYPE_H
19
20#include "unitypes.h"
21
22/* Get bool. */
23#include <stdbool.h>
24
25/* Get size_t. */
26#include <stddef.h>
27
28#if @HAVE_UNISTRING_WOE32DLL_H@
29# include <unistring/woe32dll.h>
30#else
31# define LIBUNISTRING_DLL_VARIABLE
32#endif
33
34#ifdef __cplusplus
35extern "C" {
36#endif
37
38/* ========================================================================= */
39
40/* Field 1 of Unicode Character Database: Character name.
41 See "uniname.h". */
42
43/* ========================================================================= */
44
45/* Field 2 of Unicode Character Database: General category. */
46
47/* Data type denoting a General category value. This is not just a bitmask,
48 but rather a bitmask and a pointer to the lookup table, so that programs
49 that use only the predefined bitmasks (i.e. don't combine bitmasks with &
50 and |) don't have a link-time dependency towards the big general table. */
51typedef struct
52{
53 uint32_t bitmask : 31;
54 /*bool*/ unsigned int generic : 1;
55 union
56 {
57 const void *table; /* when generic is 0 */
58 bool (*lookup_fn) (ucs4_t uc, uint32_t bitmask); /* when generic is 1 */
59 } lookup;
60}
61uc_general_category_t;
62
63/* Bits and bit masks denoting General category values. UnicodeData-3.2.0.html
64 says a 32-bit integer will always suffice to represent them.
65 These bit masks can only be used with the uc_is_general_category_withtable
66 function. */
67enum
68{
69 UC_CATEGORY_MASK_L = 0x0000001f,
70 UC_CATEGORY_MASK_LC = 0x00000007,
71 UC_CATEGORY_MASK_Lu = 0x00000001,
72 UC_CATEGORY_MASK_Ll = 0x00000002,
73 UC_CATEGORY_MASK_Lt = 0x00000004,
74 UC_CATEGORY_MASK_Lm = 0x00000008,
75 UC_CATEGORY_MASK_Lo = 0x00000010,
76 UC_CATEGORY_MASK_M = 0x000000e0,
77 UC_CATEGORY_MASK_Mn = 0x00000020,
78 UC_CATEGORY_MASK_Mc = 0x00000040,
79 UC_CATEGORY_MASK_Me = 0x00000080,
80 UC_CATEGORY_MASK_N = 0x00000700,
81 UC_CATEGORY_MASK_Nd = 0x00000100,
82 UC_CATEGORY_MASK_Nl = 0x00000200,
83 UC_CATEGORY_MASK_No = 0x00000400,
84 UC_CATEGORY_MASK_P = 0x0003f800,
85 UC_CATEGORY_MASK_Pc = 0x00000800,
86 UC_CATEGORY_MASK_Pd = 0x00001000,
87 UC_CATEGORY_MASK_Ps = 0x00002000,
88 UC_CATEGORY_MASK_Pe = 0x00004000,
89 UC_CATEGORY_MASK_Pi = 0x00008000,
90 UC_CATEGORY_MASK_Pf = 0x00010000,
91 UC_CATEGORY_MASK_Po = 0x00020000,
92 UC_CATEGORY_MASK_S = 0x003c0000,
93 UC_CATEGORY_MASK_Sm = 0x00040000,
94 UC_CATEGORY_MASK_Sc = 0x00080000,
95 UC_CATEGORY_MASK_Sk = 0x00100000,
96 UC_CATEGORY_MASK_So = 0x00200000,
97 UC_CATEGORY_MASK_Z = 0x01c00000,
98 UC_CATEGORY_MASK_Zs = 0x00400000,
99 UC_CATEGORY_MASK_Zl = 0x00800000,
100 UC_CATEGORY_MASK_Zp = 0x01000000,
101 UC_CATEGORY_MASK_C = 0x3e000000,
102 UC_CATEGORY_MASK_Cc = 0x02000000,
103 UC_CATEGORY_MASK_Cf = 0x04000000,
104 UC_CATEGORY_MASK_Cs = 0x08000000,
105 UC_CATEGORY_MASK_Co = 0x10000000,
106 UC_CATEGORY_MASK_Cn = 0x20000000
107};
108
109/* Predefined General category values. */
110extern @GNULIB_UNICTYPE_CATEGORY_L_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_L;
111extern @GNULIB_UNICTYPE_CATEGORY_LC_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_LC;
112extern @GNULIB_UNICTYPE_CATEGORY_LU_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Lu;
113extern @GNULIB_UNICTYPE_CATEGORY_LL_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Ll;
114extern @GNULIB_UNICTYPE_CATEGORY_LT_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Lt;
115extern @GNULIB_UNICTYPE_CATEGORY_LM_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Lm;
116extern @GNULIB_UNICTYPE_CATEGORY_LO_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Lo;
117extern @GNULIB_UNICTYPE_CATEGORY_M_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_M;
118extern @GNULIB_UNICTYPE_CATEGORY_MN_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Mn;
119extern @GNULIB_UNICTYPE_CATEGORY_MC_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Mc;
120extern @GNULIB_UNICTYPE_CATEGORY_ME_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Me;
121extern @GNULIB_UNICTYPE_CATEGORY_N_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_N;
122extern @GNULIB_UNICTYPE_CATEGORY_ND_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Nd;
123extern @GNULIB_UNICTYPE_CATEGORY_NL_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Nl;
124extern @GNULIB_UNICTYPE_CATEGORY_NO_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_No;
125extern @GNULIB_UNICTYPE_CATEGORY_P_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_P;
126extern @GNULIB_UNICTYPE_CATEGORY_PC_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Pc;
127extern @GNULIB_UNICTYPE_CATEGORY_PD_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Pd;
128extern @GNULIB_UNICTYPE_CATEGORY_PS_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Ps;
129extern @GNULIB_UNICTYPE_CATEGORY_PE_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Pe;
130extern @GNULIB_UNICTYPE_CATEGORY_PI_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Pi;
131extern @GNULIB_UNICTYPE_CATEGORY_PF_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Pf;
132extern @GNULIB_UNICTYPE_CATEGORY_PO_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Po;
133extern @GNULIB_UNICTYPE_CATEGORY_S_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_S;
134extern @GNULIB_UNICTYPE_CATEGORY_SM_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Sm;
135extern @GNULIB_UNICTYPE_CATEGORY_SC_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Sc;
136extern @GNULIB_UNICTYPE_CATEGORY_SK_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Sk;
137extern @GNULIB_UNICTYPE_CATEGORY_SO_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_So;
138extern @GNULIB_UNICTYPE_CATEGORY_Z_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Z;
139extern @GNULIB_UNICTYPE_CATEGORY_ZS_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Zs;
140extern @GNULIB_UNICTYPE_CATEGORY_ZL_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Zl;
141extern @GNULIB_UNICTYPE_CATEGORY_ZP_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Zp;
142extern @GNULIB_UNICTYPE_CATEGORY_C_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_C;
143extern @GNULIB_UNICTYPE_CATEGORY_CC_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Cc;
144extern @GNULIB_UNICTYPE_CATEGORY_CF_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Cf;
145extern @GNULIB_UNICTYPE_CATEGORY_CS_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Cs;
146extern @GNULIB_UNICTYPE_CATEGORY_CO_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Co;
147extern @GNULIB_UNICTYPE_CATEGORY_CN_DLL_VARIABLE@ const uc_general_category_t UC_CATEGORY_Cn;
148/* Non-public. */
149extern const uc_general_category_t _UC_CATEGORY_NONE;
150
151/* Alias names for predefined General category values. */
152#define UC_LETTER UC_CATEGORY_L
153#define UC_CASED_LETTER UC_CATEGORY_LC
154#define UC_UPPERCASE_LETTER UC_CATEGORY_Lu
155#define UC_LOWERCASE_LETTER UC_CATEGORY_Ll
156#define UC_TITLECASE_LETTER UC_CATEGORY_Lt
157#define UC_MODIFIER_LETTER UC_CATEGORY_Lm
158#define UC_OTHER_LETTER UC_CATEGORY_Lo
159#define UC_MARK UC_CATEGORY_M
160#define UC_NON_SPACING_MARK UC_CATEGORY_Mn
161#define UC_COMBINING_SPACING_MARK UC_CATEGORY_Mc
162#define UC_ENCLOSING_MARK UC_CATEGORY_Me
163#define UC_NUMBER UC_CATEGORY_N
164#define UC_DECIMAL_DIGIT_NUMBER UC_CATEGORY_Nd
165#define UC_LETTER_NUMBER UC_CATEGORY_Nl
166#define UC_OTHER_NUMBER UC_CATEGORY_No
167#define UC_PUNCTUATION UC_CATEGORY_P
168#define UC_CONNECTOR_PUNCTUATION UC_CATEGORY_Pc
169#define UC_DASH_PUNCTUATION UC_CATEGORY_Pd
170#define UC_OPEN_PUNCTUATION UC_CATEGORY_Ps /* a.k.a. UC_START_PUNCTUATION */
171#define UC_CLOSE_PUNCTUATION UC_CATEGORY_Pe /* a.k.a. UC_END_PUNCTUATION */
172#define UC_INITIAL_QUOTE_PUNCTUATION UC_CATEGORY_Pi
173#define UC_FINAL_QUOTE_PUNCTUATION UC_CATEGORY_Pf
174#define UC_OTHER_PUNCTUATION UC_CATEGORY_Po
175#define UC_SYMBOL UC_CATEGORY_S
176#define UC_MATH_SYMBOL UC_CATEGORY_Sm
177#define UC_CURRENCY_SYMBOL UC_CATEGORY_Sc
178#define UC_MODIFIER_SYMBOL UC_CATEGORY_Sk
179#define UC_OTHER_SYMBOL UC_CATEGORY_So
180#define UC_SEPARATOR UC_CATEGORY_Z
181#define UC_SPACE_SEPARATOR UC_CATEGORY_Zs
182#define UC_LINE_SEPARATOR UC_CATEGORY_Zl
183#define UC_PARAGRAPH_SEPARATOR UC_CATEGORY_Zp
184#define UC_OTHER UC_CATEGORY_C
185#define UC_CONTROL UC_CATEGORY_Cc
186#define UC_FORMAT UC_CATEGORY_Cf
187#define UC_SURROGATE UC_CATEGORY_Cs /* all of them are invalid characters */
188#define UC_PRIVATE_USE UC_CATEGORY_Co
189#define UC_UNASSIGNED UC_CATEGORY_Cn /* some of them are invalid characters */
190
191/* Return the union of two general categories.
192 This corresponds to the unions of the two sets of characters. */
193extern uc_general_category_t
194 uc_general_category_or (uc_general_category_t category1,
195 uc_general_category_t category2);
196
197/* Return the intersection of two general categories as bit masks.
198 This *does*not* correspond to the intersection of the two sets of
199 characters. */
200extern uc_general_category_t
201 uc_general_category_and (uc_general_category_t category1,
202 uc_general_category_t category2);
203
204/* Return the intersection of a general category with the complement of a
205 second general category, as bit masks.
206 This *does*not* correspond to the intersection with complement, when
207 viewing the categories as sets of characters. */
208extern uc_general_category_t
209 uc_general_category_and_not (uc_general_category_t category1,
210 uc_general_category_t category2);
211
212/* Return the name of a general category. */
213extern const char *
214 uc_general_category_name (uc_general_category_t category)
215 _UC_ATTRIBUTE_PURE;
216
217/* Return the long name of a general category. */
218extern const char *
219 uc_general_category_long_name (uc_general_category_t category)
220 _UC_ATTRIBUTE_PURE;
221
222/* Return the general category given by name, e.g. "Lu", or by long name,
223 e.g. "Uppercase Letter". */
224extern uc_general_category_t
225 uc_general_category_byname (const char *category_name)
226 _UC_ATTRIBUTE_PURE;
227
228/* Return the general category of a Unicode character. */
229extern uc_general_category_t
230 uc_general_category (ucs4_t uc)
231 _UC_ATTRIBUTE_PURE;
232
233/* Test whether a Unicode character belongs to a given category.
234 The CATEGORY argument can be the combination of several predefined
235 general categories. */
236extern bool
237 uc_is_general_category (ucs4_t uc, uc_general_category_t category)
238 _UC_ATTRIBUTE_PURE;
239/* Likewise. This function uses a big table comprising all categories. */
240extern bool
241 uc_is_general_category_withtable (ucs4_t uc, uint32_t bitmask)
242 _UC_ATTRIBUTE_CONST;
243
244/* ========================================================================= */
245
246/* Field 3 of Unicode Character Database: Canonical combining class. */
247
248/* The possible results of uc_combining_class (0..255) are described in
249 UCD.html. The list here is not definitive; more values can be added
250 in future versions. */
251enum
252{
253 UC_CCC_NR = 0, /* Not Reordered */
254 UC_CCC_OV = 1, /* Overlay */
255 UC_CCC_NK = 7, /* Nukta */
256 UC_CCC_KV = 8, /* Kana Voicing */
257 UC_CCC_VR = 9, /* Virama */
258 UC_CCC_ATBL = 200, /* Attached Below Left */
259 UC_CCC_ATB = 202, /* Attached Below */
260 UC_CCC_ATA = 214, /* Attached Above */
261 UC_CCC_ATAR = 216, /* Attached Above Right */
262 UC_CCC_BL = 218, /* Below Left */
263 UC_CCC_B = 220, /* Below */
264 UC_CCC_BR = 222, /* Below Right */
265 UC_CCC_L = 224, /* Left */
266 UC_CCC_R = 226, /* Right */
267 UC_CCC_AL = 228, /* Above Left */
268 UC_CCC_A = 230, /* Above */
269 UC_CCC_AR = 232, /* Above Right */
270 UC_CCC_DB = 233, /* Double Below */
271 UC_CCC_DA = 234, /* Double Above */
272 UC_CCC_IS = 240 /* Iota Subscript */
273};
274
275/* Return the canonical combining class of a Unicode character. */
276extern int
277 uc_combining_class (ucs4_t uc)
278 _UC_ATTRIBUTE_CONST;
279
280/* Return the name of a canonical combining class. */
281extern const char *
282 uc_combining_class_name (int ccc)
283 _UC_ATTRIBUTE_CONST;
284
285/* Return the long name of a canonical combining class. */
286extern const char *
287 uc_combining_class_long_name (int ccc)
288 _UC_ATTRIBUTE_CONST;
289
290/* Return the canonical combining class given by name, e.g. "BL", or by long
291 name, e.g. "Below Left". */
292extern int
293 uc_combining_class_byname (const char *ccc_name)
294 _UC_ATTRIBUTE_PURE;
295
296/* ========================================================================= */
297
298/* Field 4 of Unicode Character Database: Bidi class.
299 Before Unicode 4.0, this field was called "Bidirectional category". */
300
301enum
302{
303 UC_BIDI_L, /* Left-to-Right */
304 UC_BIDI_LRE, /* Left-to-Right Embedding */
305 UC_BIDI_LRO, /* Left-to-Right Override */
306 UC_BIDI_R, /* Right-to-Left */
307 UC_BIDI_AL, /* Right-to-Left Arabic */
308 UC_BIDI_RLE, /* Right-to-Left Embedding */
309 UC_BIDI_RLO, /* Right-to-Left Override */
310 UC_BIDI_PDF, /* Pop Directional Format */
311 UC_BIDI_EN, /* European Number */
312 UC_BIDI_ES, /* European Number Separator */
313 UC_BIDI_ET, /* European Number Terminator */
314 UC_BIDI_AN, /* Arabic Number */
315 UC_BIDI_CS, /* Common Number Separator */
316 UC_BIDI_NSM, /* Non-Spacing Mark */
317 UC_BIDI_BN, /* Boundary Neutral */
318 UC_BIDI_B, /* Paragraph Separator */
319 UC_BIDI_S, /* Segment Separator */
320 UC_BIDI_WS, /* Whitespace */
321 UC_BIDI_ON, /* Other Neutral */
322 UC_BIDI_LRI, /* Left-to-Right Isolate */
323 UC_BIDI_RLI, /* Right-to-Left Isolate */
324 UC_BIDI_FSI, /* First Strong Isolate */
325 UC_BIDI_PDI /* Pop Directional Isolate */
326};
327
328/* Return the name of a bidi class. */
329extern const char *
330 uc_bidi_class_name (int bidi_class)
331 _UC_ATTRIBUTE_CONST;
332/* Same; obsolete function name. */
333extern const char *
334 uc_bidi_category_name (int category)
335 _UC_ATTRIBUTE_CONST;
336
337/* Return the long name of a bidi class. */
338extern const char *
339 uc_bidi_class_long_name (int bidi_class)
340 _UC_ATTRIBUTE_CONST;
341
342/* Return the bidi class given by name, e.g. "LRE", or by long name, e.g.
343 "Left-to-Right Embedding". */
344extern int
345 uc_bidi_class_byname (const char *bidi_class_name)
346 _UC_ATTRIBUTE_PURE;
347/* Same; obsolete function name. */
348extern int
349 uc_bidi_category_byname (const char *category_name)
350 _UC_ATTRIBUTE_PURE;
351
352/* Return the bidi class of a Unicode character. */
353extern int
354 uc_bidi_class (ucs4_t uc)
355 _UC_ATTRIBUTE_CONST;
356/* Same; obsolete function name. */
357extern int
358 uc_bidi_category (ucs4_t uc)
359 _UC_ATTRIBUTE_CONST;
360
361/* Test whether a Unicode character belongs to a given bidi class. */
362extern bool
363 uc_is_bidi_class (ucs4_t uc, int bidi_class)
364 _UC_ATTRIBUTE_CONST;
365/* Same; obsolete function name. */
366extern bool
367 uc_is_bidi_category (ucs4_t uc, int category)
368 _UC_ATTRIBUTE_CONST;
369
370/* ========================================================================= */
371
372/* Field 5 of Unicode Character Database: Character decomposition mapping.
373 See "uninorm.h". */
374
375/* ========================================================================= */
376
377/* Field 6 of Unicode Character Database: Decimal digit value. */
378
379/* Return the decimal digit value of a Unicode character. */
380extern int
381 uc_decimal_value (ucs4_t uc)
382 _UC_ATTRIBUTE_CONST;
383
384/* ========================================================================= */
385
386/* Field 7 of Unicode Character Database: Digit value. */
387
388/* Return the digit value of a Unicode character. */
389extern int
390 uc_digit_value (ucs4_t uc)
391 _UC_ATTRIBUTE_CONST;
392
393/* ========================================================================= */
394
395/* Field 8 of Unicode Character Database: Numeric value. */
396
397/* Return the numeric value of a Unicode character. */
398typedef struct
399{
400 int numerator;
401 int denominator;
402}
403uc_fraction_t;
404extern uc_fraction_t
405 uc_numeric_value (ucs4_t uc)
406 _UC_ATTRIBUTE_CONST;
407
408/* ========================================================================= */
409
410/* Field 9 of Unicode Character Database: Mirrored. */
411
412/* Return the mirrored character of a Unicode character UC in *PUC. */
413extern bool
414 uc_mirror_char (ucs4_t uc, ucs4_t *puc);
415
416/* ========================================================================= */
417
418/* Field 10 of Unicode Character Database: Unicode 1.0 Name.
419 Not available in this library. */
420
421/* ========================================================================= */
422
423/* Field 11 of Unicode Character Database: ISO 10646 comment.
424 Not available in this library. */
425
426/* ========================================================================= */
427
428/* Field 12, 13, 14 of Unicode Character Database: Uppercase mapping,
429 lowercase mapping, titlecase mapping. See "unicase.h". */
430
431/* ========================================================================= */
432
433/* Field 2 of the file ArabicShaping.txt in the Unicode Character Database. */
434
435/* Possible joining types. */
436enum
437{
438 UC_JOINING_TYPE_U, /* Non_Joining */
439 UC_JOINING_TYPE_T, /* Transparent */
440 UC_JOINING_TYPE_C, /* Join_Causing */
441 UC_JOINING_TYPE_L, /* Left_Joining */
442 UC_JOINING_TYPE_R, /* Right_Joining */
443 UC_JOINING_TYPE_D /* Dual_Joining */
444};
445
446/* Return the name of a joining type. */
447extern const char *
448 uc_joining_type_name (int joining_type)
449 _UC_ATTRIBUTE_CONST;
450
451/* Return the long name of a joining type. */
452extern const char *
453 uc_joining_type_long_name (int joining_type)
454 _UC_ATTRIBUTE_CONST;
455
456/* Return the joining type given by name, e.g. "D", or by long name, e.g.
457 "Dual Joining". */
458extern int
459 uc_joining_type_byname (const char *joining_type_name)
460 _UC_ATTRIBUTE_PURE;
461
462/* Return the joining type of a Unicode character. */
463extern int
464 uc_joining_type (ucs4_t uc)
465 _UC_ATTRIBUTE_CONST;
466
467/* ========================================================================= */
468
469/* Field 3 of the file ArabicShaping.txt in the Unicode Character Database. */
470
471/* Possible joining groups.
472 This enumeration may be extended in the future. */
473enum
474{
475 UC_JOINING_GROUP_NONE, /* No_Joining_Group */
476 UC_JOINING_GROUP_AIN, /* Ain */
477 UC_JOINING_GROUP_ALAPH, /* Alaph */
478 UC_JOINING_GROUP_ALEF, /* Alef */
479 UC_JOINING_GROUP_BEH, /* Beh */
480 UC_JOINING_GROUP_BETH, /* Beth */
481 UC_JOINING_GROUP_BURUSHASKI_YEH_BARREE, /* Burushaski_Yeh_Barree */
482 UC_JOINING_GROUP_DAL, /* Dal */
483 UC_JOINING_GROUP_DALATH_RISH, /* Dalath_Rish */
484 UC_JOINING_GROUP_E, /* E */
485 UC_JOINING_GROUP_FARSI_YEH, /* Farsi_Yeh */
486 UC_JOINING_GROUP_FE, /* Fe */
487 UC_JOINING_GROUP_FEH, /* Feh */
488 UC_JOINING_GROUP_FINAL_SEMKATH, /* Final_Semkath */
489 UC_JOINING_GROUP_GAF, /* Gaf */
490 UC_JOINING_GROUP_GAMAL, /* Gamal */
491 UC_JOINING_GROUP_HAH, /* Hah */
492 UC_JOINING_GROUP_HE, /* He */
493 UC_JOINING_GROUP_HEH, /* Heh */
494 UC_JOINING_GROUP_HEH_GOAL, /* Heh_Goal */
495 UC_JOINING_GROUP_HETH, /* Heth */
496 UC_JOINING_GROUP_KAF, /* Kaf */
497 UC_JOINING_GROUP_KAPH, /* Kaph */
498 UC_JOINING_GROUP_KHAPH, /* Khaph */
499 UC_JOINING_GROUP_KNOTTED_HEH, /* Knotted_Heh */
500 UC_JOINING_GROUP_LAM, /* Lam */
501 UC_JOINING_GROUP_LAMADH, /* Lamadh */
502 UC_JOINING_GROUP_MEEM, /* Meem */
503 UC_JOINING_GROUP_MIM, /* Mim */
504 UC_JOINING_GROUP_NOON, /* Noon */
505 UC_JOINING_GROUP_NUN, /* Nun */
506 UC_JOINING_GROUP_NYA, /* Nya */
507 UC_JOINING_GROUP_PE, /* Pe */
508 UC_JOINING_GROUP_QAF, /* Qaf */
509 UC_JOINING_GROUP_QAPH, /* Qaph */
510 UC_JOINING_GROUP_REH, /* Reh */
511 UC_JOINING_GROUP_REVERSED_PE, /* Reversed_Pe */
512 UC_JOINING_GROUP_SAD, /* Sad */
513 UC_JOINING_GROUP_SADHE, /* Sadhe */
514 UC_JOINING_GROUP_SEEN, /* Seen */
515 UC_JOINING_GROUP_SEMKATH, /* Semkath */
516 UC_JOINING_GROUP_SHIN, /* Shin */
517 UC_JOINING_GROUP_SWASH_KAF, /* Swash_Kaf */
518 UC_JOINING_GROUP_SYRIAC_WAW, /* Syriac_Waw */
519 UC_JOINING_GROUP_TAH, /* Tah */
520 UC_JOINING_GROUP_TAW, /* Taw */
521 UC_JOINING_GROUP_TEH_MARBUTA, /* Teh_Marbuta */
522 UC_JOINING_GROUP_TEH_MARBUTA_GOAL, /* Teh_Marbuta_Goal */
523 UC_JOINING_GROUP_TETH, /* Teth */
524 UC_JOINING_GROUP_WAW, /* Waw */
525 UC_JOINING_GROUP_YEH, /* Yeh */
526 UC_JOINING_GROUP_YEH_BARREE, /* Yeh_Barree */
527 UC_JOINING_GROUP_YEH_WITH_TAIL, /* Yeh_With_Tail */
528 UC_JOINING_GROUP_YUDH, /* Yudh */
529 UC_JOINING_GROUP_YUDH_HE, /* Yudh_He */
530 UC_JOINING_GROUP_ZAIN, /* Zain */
531 UC_JOINING_GROUP_ZHAIN, /* Zhain */
532 UC_JOINING_GROUP_ROHINGYA_YEH, /* Rohingya_Yeh */
533 UC_JOINING_GROUP_STRAIGHT_WAW, /* Straight_Waw */
534 UC_JOINING_GROUP_MANICHAEAN_ALEPH, /* Manichaean_Aleph */
535 UC_JOINING_GROUP_MANICHAEAN_BETH, /* Manichaean_Beth */
536 UC_JOINING_GROUP_MANICHAEAN_GIMEL, /* Manichaean_Gimel */
537 UC_JOINING_GROUP_MANICHAEAN_DALETH, /* Manichaean_Daleth */
538 UC_JOINING_GROUP_MANICHAEAN_WAW, /* Manichaean_Waw */
539 UC_JOINING_GROUP_MANICHAEAN_ZAYIN, /* Manichaean_Zayin */
540 UC_JOINING_GROUP_MANICHAEAN_HETH, /* Manichaean_Heth */
541 UC_JOINING_GROUP_MANICHAEAN_TETH, /* Manichaean_Teth */
542 UC_JOINING_GROUP_MANICHAEAN_YODH, /* Manichaean_Yodh */
543 UC_JOINING_GROUP_MANICHAEAN_KAPH, /* Manichaean_Kaph */
544 UC_JOINING_GROUP_MANICHAEAN_LAMEDH, /* Manichaean_Lamedh */
545 UC_JOINING_GROUP_MANICHAEAN_DHAMEDH, /* Manichaean_Dhamedh */
546 UC_JOINING_GROUP_MANICHAEAN_THAMEDH, /* Manichaean_Thamedh */
547 UC_JOINING_GROUP_MANICHAEAN_MEM, /* Manichaean_Mem */
548 UC_JOINING_GROUP_MANICHAEAN_NUN, /* Manichaean_Nun */
549 UC_JOINING_GROUP_MANICHAEAN_SAMEKH, /* Manichaean_Aleph */
550 UC_JOINING_GROUP_MANICHAEAN_AYIN, /* Manichaean_Ayin */
551 UC_JOINING_GROUP_MANICHAEAN_PE, /* Manichaean_Pe */
552 UC_JOINING_GROUP_MANICHAEAN_SADHE, /* Manichaean_Sadhe */
553 UC_JOINING_GROUP_MANICHAEAN_QOPH, /* Manichaean_Qoph */
554 UC_JOINING_GROUP_MANICHAEAN_RESH, /* Manichaean_Resh */
555 UC_JOINING_GROUP_MANICHAEAN_TAW, /* Manichaean_Taw */
556 UC_JOINING_GROUP_MANICHAEAN_ONE, /* Manichaean_One */
557 UC_JOINING_GROUP_MANICHAEAN_FIVE, /* Manichaean_Five */
558 UC_JOINING_GROUP_MANICHAEAN_TEN, /* Manichaean_Ten */
559 UC_JOINING_GROUP_MANICHAEAN_TWENTY, /* Manichaean_Twenty */
560 UC_JOINING_GROUP_MANICHAEAN_HUNDRED, /* Manichaean_Hundred */
561 UC_JOINING_GROUP_AFRICAN_FEH, /* African_Feh */
562 UC_JOINING_GROUP_AFRICAN_QAF, /* African_Qaf */
563 UC_JOINING_GROUP_AFRICAN_NOON, /* African_Noon */
564 UC_JOINING_GROUP_MALAYALAM_NGA, /* Malayalam_Nga */
565 UC_JOINING_GROUP_MALAYALAM_JA, /* Malayalam_Ja */
566 UC_JOINING_GROUP_MALAYALAM_NYA, /* Malayalam_Nya */
567 UC_JOINING_GROUP_MALAYALAM_TTA, /* Malayalam_Tta */
568 UC_JOINING_GROUP_MALAYALAM_NNA, /* Malayalam_Nna */
569 UC_JOINING_GROUP_MALAYALAM_NNNA, /* Malayalam_Nnna */
570 UC_JOINING_GROUP_MALAYALAM_BHA, /* Malayalam_Bha */
571 UC_JOINING_GROUP_MALAYALAM_RA, /* Malayalam_Ra */
572 UC_JOINING_GROUP_MALAYALAM_LLA, /* Malayalam_Lla */
573 UC_JOINING_GROUP_MALAYALAM_LLLA, /* Malayalam_Llla */
574 UC_JOINING_GROUP_MALAYALAM_SSA, /* Malayalam_Ssa */
575 UC_JOINING_GROUP_HANIFI_ROHINGYA_PA, /* Hanifi_Rohingya_Pa */
576 UC_JOINING_GROUP_HANIFI_ROHINGYA_KINNA_YA, /* Hanifi_Rohingya_Kinna_Ya */
577 UC_JOINING_GROUP_THIN_YEH, /* Thin_Yeh */
578 UC_JOINING_GROUP_VERTICAL_TAIL, /* Vertical_Tail */
579 UC_JOINING_GROUP_KASHMIRI_YEH /* Kashmiri_Yeh */
580};
581
582/* Return the name of a joining group. */
583extern const char *
584 uc_joining_group_name (int joining_group)
585 _UC_ATTRIBUTE_CONST;
586
587/* Return the joining group given by name, e.g. "Teh_Marbuta". */
588extern int
589 uc_joining_group_byname (const char *joining_group_name)
590 _UC_ATTRIBUTE_PURE;
591
592/* Return the joining group of a Unicode character. */
593extern int
594 uc_joining_group (ucs4_t uc)
595 _UC_ATTRIBUTE_CONST;
596
597/* ========================================================================= */
598
599/* Common API for properties. */
600
601/* Data type denoting a property. This is not just a number, but rather a
602 pointer to the test functions, so that programs that use only few of the
603 properties don't have a link-time dependency towards all the tables. */
604typedef struct
605{
606 bool (*test_fn) (ucs4_t uc);
607}
608uc_property_t;
609
610/* Predefined properties. */
611/* General. */
612extern @GNULIB_UNICTYPE_PROPERTY_WHITE_SPACE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_WHITE_SPACE;
613extern @GNULIB_UNICTYPE_PROPERTY_ALPHABETIC_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_ALPHABETIC;
614extern @GNULIB_UNICTYPE_PROPERTY_OTHER_ALPHABETIC_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_OTHER_ALPHABETIC;
615extern @GNULIB_UNICTYPE_PROPERTY_NOT_A_CHARACTER_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_NOT_A_CHARACTER;
616extern @GNULIB_UNICTYPE_PROPERTY_DEFAULT_IGNORABLE_CODE_POINT_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_DEFAULT_IGNORABLE_CODE_POINT;
617extern @GNULIB_UNICTYPE_PROPERTY_OTHER_DEFAULT_IGNORABLE_CODE_POINT_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_OTHER_DEFAULT_IGNORABLE_CODE_POINT;
618extern @GNULIB_UNICTYPE_PROPERTY_DEPRECATED_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_DEPRECATED;
619extern @GNULIB_UNICTYPE_PROPERTY_LOGICAL_ORDER_EXCEPTION_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_LOGICAL_ORDER_EXCEPTION;
620extern @GNULIB_UNICTYPE_PROPERTY_VARIATION_SELECTOR_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_VARIATION_SELECTOR;
621extern @GNULIB_UNICTYPE_PROPERTY_PRIVATE_USE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_PRIVATE_USE;
622extern @GNULIB_UNICTYPE_PROPERTY_UNASSIGNED_CODE_VALUE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_UNASSIGNED_CODE_VALUE;
623/* Case. */
624extern @GNULIB_UNICTYPE_PROPERTY_UPPERCASE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_UPPERCASE;
625extern @GNULIB_UNICTYPE_PROPERTY_OTHER_UPPERCASE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_OTHER_UPPERCASE;
626extern @GNULIB_UNICTYPE_PROPERTY_LOWERCASE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_LOWERCASE;
627extern @GNULIB_UNICTYPE_PROPERTY_OTHER_LOWERCASE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_OTHER_LOWERCASE;
628extern @GNULIB_UNICTYPE_PROPERTY_TITLECASE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_TITLECASE;
629extern @GNULIB_UNICTYPE_PROPERTY_CASED_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_CASED;
630extern @GNULIB_UNICTYPE_PROPERTY_CASE_IGNORABLE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_CASE_IGNORABLE;
631extern @GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_LOWERCASED_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_CHANGES_WHEN_LOWERCASED;
632extern @GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_UPPERCASED_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_CHANGES_WHEN_UPPERCASED;
633extern @GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_TITLECASED_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_CHANGES_WHEN_TITLECASED;
634extern @GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_CASEFOLDED_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_CHANGES_WHEN_CASEFOLDED;
635extern @GNULIB_UNICTYPE_PROPERTY_CHANGES_WHEN_CASEMAPPED_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_CHANGES_WHEN_CASEMAPPED;
636extern @GNULIB_UNICTYPE_PROPERTY_SOFT_DOTTED_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_SOFT_DOTTED;
637/* Identifiers. */
638extern @GNULIB_UNICTYPE_PROPERTY_ID_START_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_ID_START;
639extern @GNULIB_UNICTYPE_PROPERTY_OTHER_ID_START_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_OTHER_ID_START;
640extern @GNULIB_UNICTYPE_PROPERTY_ID_CONTINUE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_ID_CONTINUE;
641extern @GNULIB_UNICTYPE_PROPERTY_OTHER_ID_CONTINUE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_OTHER_ID_CONTINUE;
642extern @GNULIB_UNICTYPE_PROPERTY_XID_START_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_XID_START;
643extern @GNULIB_UNICTYPE_PROPERTY_XID_CONTINUE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_XID_CONTINUE;
644extern @GNULIB_UNICTYPE_PROPERTY_ID_COMPAT_MATH_START_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_ID_COMPAT_MATH_START;
645extern @GNULIB_UNICTYPE_PROPERTY_ID_COMPAT_MATH_CONTINUE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_ID_COMPAT_MATH_CONTINUE;
646extern @GNULIB_UNICTYPE_PROPERTY_PATTERN_WHITE_SPACE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_PATTERN_WHITE_SPACE;
647extern @GNULIB_UNICTYPE_PROPERTY_PATTERN_SYNTAX_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_PATTERN_SYNTAX;
648/* Shaping and rendering. */
649extern @GNULIB_UNICTYPE_PROPERTY_JOIN_CONTROL_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_JOIN_CONTROL;
650extern @GNULIB_UNICTYPE_PROPERTY_GRAPHEME_BASE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_GRAPHEME_BASE;
651extern @GNULIB_UNICTYPE_PROPERTY_GRAPHEME_EXTEND_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_GRAPHEME_EXTEND;
652extern @GNULIB_UNICTYPE_PROPERTY_OTHER_GRAPHEME_EXTEND_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_OTHER_GRAPHEME_EXTEND;
653extern @GNULIB_UNICTYPE_PROPERTY_GRAPHEME_LINK_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_GRAPHEME_LINK;
654extern @GNULIB_UNICTYPE_PROPERTY_MODIFIER_COMBINING_MARK_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_MODIFIER_COMBINING_MARK;
655/* Bidi. */
656extern @GNULIB_UNICTYPE_PROPERTY_BIDI_CONTROL_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_CONTROL;
657extern @GNULIB_UNICTYPE_PROPERTY_BIDI_LEFT_TO_RIGHT_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_LEFT_TO_RIGHT;
658extern @GNULIB_UNICTYPE_PROPERTY_BIDI_HEBREW_RIGHT_TO_LEFT_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_HEBREW_RIGHT_TO_LEFT;
659extern @GNULIB_UNICTYPE_PROPERTY_BIDI_ARABIC_RIGHT_TO_LEFT_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_ARABIC_RIGHT_TO_LEFT;
660extern @GNULIB_UNICTYPE_PROPERTY_BIDI_EUROPEAN_DIGIT_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_EUROPEAN_DIGIT;
661extern @GNULIB_UNICTYPE_PROPERTY_BIDI_EUR_NUM_SEPARATOR_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_EUR_NUM_SEPARATOR;
662extern @GNULIB_UNICTYPE_PROPERTY_BIDI_EUR_NUM_TERMINATOR_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_EUR_NUM_TERMINATOR;
663extern @GNULIB_UNICTYPE_PROPERTY_BIDI_ARABIC_DIGIT_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_ARABIC_DIGIT;
664extern @GNULIB_UNICTYPE_PROPERTY_BIDI_COMMON_SEPARATOR_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_COMMON_SEPARATOR;
665extern @GNULIB_UNICTYPE_PROPERTY_BIDI_BLOCK_SEPARATOR_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_BLOCK_SEPARATOR;
666extern @GNULIB_UNICTYPE_PROPERTY_BIDI_SEGMENT_SEPARATOR_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_SEGMENT_SEPARATOR;
667extern @GNULIB_UNICTYPE_PROPERTY_BIDI_WHITESPACE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_WHITESPACE;
668extern @GNULIB_UNICTYPE_PROPERTY_BIDI_NON_SPACING_MARK_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_NON_SPACING_MARK;
669extern @GNULIB_UNICTYPE_PROPERTY_BIDI_BOUNDARY_NEUTRAL_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_BOUNDARY_NEUTRAL;
670extern @GNULIB_UNICTYPE_PROPERTY_BIDI_PDF_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_PDF;
671extern @GNULIB_UNICTYPE_PROPERTY_BIDI_EMBEDDING_OR_OVERRIDE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_EMBEDDING_OR_OVERRIDE;
672extern @GNULIB_UNICTYPE_PROPERTY_BIDI_OTHER_NEUTRAL_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_BIDI_OTHER_NEUTRAL;
673/* Numeric. */
674extern @GNULIB_UNICTYPE_PROPERTY_HEX_DIGIT_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_HEX_DIGIT;
675extern @GNULIB_UNICTYPE_PROPERTY_ASCII_HEX_DIGIT_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_ASCII_HEX_DIGIT;
676/* CJK. */
677extern @GNULIB_UNICTYPE_PROPERTY_IDEOGRAPHIC_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_IDEOGRAPHIC;
678extern @GNULIB_UNICTYPE_PROPERTY_UNIFIED_IDEOGRAPH_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_UNIFIED_IDEOGRAPH;
679extern @GNULIB_UNICTYPE_PROPERTY_RADICAL_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_RADICAL;
680extern @GNULIB_UNICTYPE_PROPERTY_IDS_UNARY_OPERATOR_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_IDS_UNARY_OPERATOR;
681extern @GNULIB_UNICTYPE_PROPERTY_IDS_BINARY_OPERATOR_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_IDS_BINARY_OPERATOR;
682extern @GNULIB_UNICTYPE_PROPERTY_IDS_TRINARY_OPERATOR_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_IDS_TRINARY_OPERATOR;
683/* Emoji. */
684extern @GNULIB_UNICTYPE_PROPERTY_EMOJI_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_EMOJI;
685extern @GNULIB_UNICTYPE_PROPERTY_EMOJI_PRESENTATION_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_EMOJI_PRESENTATION;
686extern @GNULIB_UNICTYPE_PROPERTY_EMOJI_MODIFIER_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_EMOJI_MODIFIER;
687extern @GNULIB_UNICTYPE_PROPERTY_EMOJI_MODIFIER_BASE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_EMOJI_MODIFIER_BASE;
688extern @GNULIB_UNICTYPE_PROPERTY_EMOJI_COMPONENT_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_EMOJI_COMPONENT;
689extern @GNULIB_UNICTYPE_PROPERTY_EXTENDED_PICTOGRAPHIC_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_EXTENDED_PICTOGRAPHIC;
690/* Misc. */
691extern @GNULIB_UNICTYPE_PROPERTY_ZERO_WIDTH_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_ZERO_WIDTH;
692extern @GNULIB_UNICTYPE_PROPERTY_SPACE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_SPACE;
693extern @GNULIB_UNICTYPE_PROPERTY_NON_BREAK_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_NON_BREAK;
694extern @GNULIB_UNICTYPE_PROPERTY_ISO_CONTROL_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_ISO_CONTROL;
695extern @GNULIB_UNICTYPE_PROPERTY_FORMAT_CONTROL_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_FORMAT_CONTROL;
696extern @GNULIB_UNICTYPE_PROPERTY_PREPENDED_CONCATENATION_MARK_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_PREPENDED_CONCATENATION_MARK;
697extern @GNULIB_UNICTYPE_PROPERTY_DASH_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_DASH;
698extern @GNULIB_UNICTYPE_PROPERTY_HYPHEN_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_HYPHEN;
699extern @GNULIB_UNICTYPE_PROPERTY_PUNCTUATION_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_PUNCTUATION;
700extern @GNULIB_UNICTYPE_PROPERTY_LINE_SEPARATOR_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_LINE_SEPARATOR;
701extern @GNULIB_UNICTYPE_PROPERTY_PARAGRAPH_SEPARATOR_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_PARAGRAPH_SEPARATOR;
702extern @GNULIB_UNICTYPE_PROPERTY_QUOTATION_MARK_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_QUOTATION_MARK;
703extern @GNULIB_UNICTYPE_PROPERTY_SENTENCE_TERMINAL_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_SENTENCE_TERMINAL;
704extern @GNULIB_UNICTYPE_PROPERTY_TERMINAL_PUNCTUATION_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_TERMINAL_PUNCTUATION;
705extern @GNULIB_UNICTYPE_PROPERTY_CURRENCY_SYMBOL_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_CURRENCY_SYMBOL;
706extern @GNULIB_UNICTYPE_PROPERTY_MATH_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_MATH;
707extern @GNULIB_UNICTYPE_PROPERTY_OTHER_MATH_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_OTHER_MATH;
708extern @GNULIB_UNICTYPE_PROPERTY_PAIRED_PUNCTUATION_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_PAIRED_PUNCTUATION;
709extern @GNULIB_UNICTYPE_PROPERTY_LEFT_OF_PAIR_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_LEFT_OF_PAIR;
710extern @GNULIB_UNICTYPE_PROPERTY_COMBINING_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_COMBINING;
711extern @GNULIB_UNICTYPE_PROPERTY_COMPOSITE_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_COMPOSITE;
712extern @GNULIB_UNICTYPE_PROPERTY_DECIMAL_DIGIT_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_DECIMAL_DIGIT;
713extern @GNULIB_UNICTYPE_PROPERTY_NUMERIC_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_NUMERIC;
714extern @GNULIB_UNICTYPE_PROPERTY_DIACRITIC_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_DIACRITIC;
715extern @GNULIB_UNICTYPE_PROPERTY_EXTENDER_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_EXTENDER;
716extern @GNULIB_UNICTYPE_PROPERTY_IGNORABLE_CONTROL_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_IGNORABLE_CONTROL;
717extern @GNULIB_UNICTYPE_PROPERTY_REGIONAL_INDICATOR_DLL_VARIABLE@ const uc_property_t UC_PROPERTY_REGIONAL_INDICATOR;
718
719/* Return the property given by name, e.g. "White space". */
720extern uc_property_t
721 uc_property_byname (const char *property_name);
722
723/* Test whether a property is valid. */
724#define uc_property_is_valid(property) ((property).test_fn != NULL)
725
726/* Test whether a Unicode character has a given property. */
727extern bool
728 uc_is_property (ucs4_t uc, uc_property_t property);
729extern bool uc_is_property_white_space (ucs4_t uc)
730 _UC_ATTRIBUTE_CONST;
731extern bool uc_is_property_alphabetic (ucs4_t uc)
732 _UC_ATTRIBUTE_CONST;
733extern bool uc_is_property_other_alphabetic (ucs4_t uc)
734 _UC_ATTRIBUTE_CONST;
735extern bool uc_is_property_not_a_character (ucs4_t uc)
736 _UC_ATTRIBUTE_CONST;
737extern bool uc_is_property_default_ignorable_code_point (ucs4_t uc)
738 _UC_ATTRIBUTE_CONST;
739extern bool uc_is_property_other_default_ignorable_code_point (ucs4_t uc)
740 _UC_ATTRIBUTE_CONST;
741extern bool uc_is_property_deprecated (ucs4_t uc)
742 _UC_ATTRIBUTE_CONST;
743extern bool uc_is_property_logical_order_exception (ucs4_t uc)
744 _UC_ATTRIBUTE_CONST;
745extern bool uc_is_property_variation_selector (ucs4_t uc)
746 _UC_ATTRIBUTE_CONST;
747extern bool uc_is_property_private_use (ucs4_t uc)
748 _UC_ATTRIBUTE_CONST;
749extern bool uc_is_property_unassigned_code_value (ucs4_t uc)
750 _UC_ATTRIBUTE_CONST;
751extern bool uc_is_property_uppercase (ucs4_t uc)
752 _UC_ATTRIBUTE_CONST;
753extern bool uc_is_property_other_uppercase (ucs4_t uc)
754 _UC_ATTRIBUTE_CONST;
755extern bool uc_is_property_lowercase (ucs4_t uc)
756 _UC_ATTRIBUTE_CONST;
757extern bool uc_is_property_other_lowercase (ucs4_t uc)
758 _UC_ATTRIBUTE_CONST;
759extern bool uc_is_property_titlecase (ucs4_t uc)
760 _UC_ATTRIBUTE_CONST;
761extern bool uc_is_property_cased (ucs4_t uc)
762 _UC_ATTRIBUTE_CONST;
763extern bool uc_is_property_case_ignorable (ucs4_t uc)
764 _UC_ATTRIBUTE_CONST;
765extern bool uc_is_property_changes_when_lowercased (ucs4_t uc)
766 _UC_ATTRIBUTE_CONST;
767extern bool uc_is_property_changes_when_uppercased (ucs4_t uc)
768 _UC_ATTRIBUTE_CONST;
769extern bool uc_is_property_changes_when_titlecased (ucs4_t uc)
770 _UC_ATTRIBUTE_CONST;
771extern bool uc_is_property_changes_when_casefolded (ucs4_t uc)
772 _UC_ATTRIBUTE_CONST;
773extern bool uc_is_property_changes_when_casemapped (ucs4_t uc)
774 _UC_ATTRIBUTE_CONST;
775extern bool uc_is_property_soft_dotted (ucs4_t uc)
776 _UC_ATTRIBUTE_CONST;
777extern bool uc_is_property_id_start (ucs4_t uc)
778 _UC_ATTRIBUTE_CONST;
779extern bool uc_is_property_other_id_start (ucs4_t uc)
780 _UC_ATTRIBUTE_CONST;
781extern bool uc_is_property_id_continue (ucs4_t uc)
782 _UC_ATTRIBUTE_CONST;
783extern bool uc_is_property_other_id_continue (ucs4_t uc)
784 _UC_ATTRIBUTE_CONST;
785extern bool uc_is_property_xid_start (ucs4_t uc)
786 _UC_ATTRIBUTE_CONST;
787extern bool uc_is_property_xid_continue (ucs4_t uc)
788 _UC_ATTRIBUTE_CONST;
789extern bool uc_is_property_id_compat_math_start (ucs4_t uc)
790 _UC_ATTRIBUTE_CONST;
791extern bool uc_is_property_id_compat_math_continue (ucs4_t uc)
792 _UC_ATTRIBUTE_CONST;
793extern bool uc_is_property_pattern_white_space (ucs4_t uc)
794 _UC_ATTRIBUTE_CONST;
795extern bool uc_is_property_pattern_syntax (ucs4_t uc)
796 _UC_ATTRIBUTE_CONST;
797extern bool uc_is_property_join_control (ucs4_t uc)
798 _UC_ATTRIBUTE_CONST;
799extern bool uc_is_property_grapheme_base (ucs4_t uc)
800 _UC_ATTRIBUTE_CONST;
801extern bool uc_is_property_grapheme_extend (ucs4_t uc)
802 _UC_ATTRIBUTE_CONST;
803extern bool uc_is_property_other_grapheme_extend (ucs4_t uc)
804 _UC_ATTRIBUTE_CONST;
805extern bool uc_is_property_grapheme_link (ucs4_t uc)
806 _UC_ATTRIBUTE_CONST;
807extern bool uc_is_property_modifier_combining_mark (ucs4_t uc)
808 _UC_ATTRIBUTE_CONST;
809extern bool uc_is_property_bidi_control (ucs4_t uc)
810 _UC_ATTRIBUTE_CONST;
811extern bool uc_is_property_bidi_left_to_right (ucs4_t uc)
812 _UC_ATTRIBUTE_CONST;
813extern bool uc_is_property_bidi_hebrew_right_to_left (ucs4_t uc)
814 _UC_ATTRIBUTE_CONST;
815extern bool uc_is_property_bidi_arabic_right_to_left (ucs4_t uc)
816 _UC_ATTRIBUTE_CONST;
817extern bool uc_is_property_bidi_european_digit (ucs4_t uc)
818 _UC_ATTRIBUTE_CONST;
819extern bool uc_is_property_bidi_eur_num_separator (ucs4_t uc)
820 _UC_ATTRIBUTE_CONST;
821extern bool uc_is_property_bidi_eur_num_terminator (ucs4_t uc)
822 _UC_ATTRIBUTE_CONST;
823extern bool uc_is_property_bidi_arabic_digit (ucs4_t uc)
824 _UC_ATTRIBUTE_CONST;
825extern bool uc_is_property_bidi_common_separator (ucs4_t uc)
826 _UC_ATTRIBUTE_CONST;
827extern bool uc_is_property_bidi_block_separator (ucs4_t uc)
828 _UC_ATTRIBUTE_CONST;
829extern bool uc_is_property_bidi_segment_separator (ucs4_t uc)
830 _UC_ATTRIBUTE_CONST;
831extern bool uc_is_property_bidi_whitespace (ucs4_t uc)
832 _UC_ATTRIBUTE_CONST;
833extern bool uc_is_property_bidi_non_spacing_mark (ucs4_t uc)
834 _UC_ATTRIBUTE_CONST;
835extern bool uc_is_property_bidi_boundary_neutral (ucs4_t uc)
836 _UC_ATTRIBUTE_CONST;
837extern bool uc_is_property_bidi_pdf (ucs4_t uc)
838 _UC_ATTRIBUTE_CONST;
839extern bool uc_is_property_bidi_embedding_or_override (ucs4_t uc)
840 _UC_ATTRIBUTE_CONST;
841extern bool uc_is_property_bidi_other_neutral (ucs4_t uc)
842 _UC_ATTRIBUTE_CONST;
843extern bool uc_is_property_hex_digit (ucs4_t uc)
844 _UC_ATTRIBUTE_CONST;
845extern bool uc_is_property_ascii_hex_digit (ucs4_t uc)
846 _UC_ATTRIBUTE_CONST;
847extern bool uc_is_property_ideographic (ucs4_t uc)
848 _UC_ATTRIBUTE_CONST;
849extern bool uc_is_property_unified_ideograph (ucs4_t uc)
850 _UC_ATTRIBUTE_CONST;
851extern bool uc_is_property_radical (ucs4_t uc)
852 _UC_ATTRIBUTE_CONST;
853extern bool uc_is_property_ids_unary_operator (ucs4_t uc)
854 _UC_ATTRIBUTE_CONST;
855extern bool uc_is_property_ids_binary_operator (ucs4_t uc)
856 _UC_ATTRIBUTE_CONST;
857extern bool uc_is_property_ids_trinary_operator (ucs4_t uc)
858 _UC_ATTRIBUTE_CONST;
859extern bool uc_is_property_emoji (ucs4_t uc)
860 _UC_ATTRIBUTE_CONST;
861extern bool uc_is_property_emoji_presentation (ucs4_t uc)
862 _UC_ATTRIBUTE_CONST;
863extern bool uc_is_property_emoji_modifier (ucs4_t uc)
864 _UC_ATTRIBUTE_CONST;
865extern bool uc_is_property_emoji_modifier_base (ucs4_t uc)
866 _UC_ATTRIBUTE_CONST;
867extern bool uc_is_property_emoji_component (ucs4_t uc)
868 _UC_ATTRIBUTE_CONST;
869extern bool uc_is_property_extended_pictographic (ucs4_t uc)
870 _UC_ATTRIBUTE_CONST;
871extern bool uc_is_property_zero_width (ucs4_t uc)
872 _UC_ATTRIBUTE_CONST;
873extern bool uc_is_property_space (ucs4_t uc)
874 _UC_ATTRIBUTE_CONST;
875extern bool uc_is_property_non_break (ucs4_t uc)
876 _UC_ATTRIBUTE_CONST;
877extern bool uc_is_property_iso_control (ucs4_t uc)
878 _UC_ATTRIBUTE_CONST;
879extern bool uc_is_property_format_control (ucs4_t uc)
880 _UC_ATTRIBUTE_CONST;
881extern bool uc_is_property_prepended_concatenation_mark (ucs4_t uc)
882 _UC_ATTRIBUTE_CONST;
883extern bool uc_is_property_dash (ucs4_t uc)
884 _UC_ATTRIBUTE_CONST;
885extern bool uc_is_property_hyphen (ucs4_t uc)
886 _UC_ATTRIBUTE_CONST;
887extern bool uc_is_property_punctuation (ucs4_t uc)
888 _UC_ATTRIBUTE_CONST;
889extern bool uc_is_property_line_separator (ucs4_t uc)
890 _UC_ATTRIBUTE_CONST;
891extern bool uc_is_property_paragraph_separator (ucs4_t uc)
892 _UC_ATTRIBUTE_CONST;
893extern bool uc_is_property_quotation_mark (ucs4_t uc)
894 _UC_ATTRIBUTE_CONST;
895extern bool uc_is_property_sentence_terminal (ucs4_t uc)
896 _UC_ATTRIBUTE_CONST;
897extern bool uc_is_property_terminal_punctuation (ucs4_t uc)
898 _UC_ATTRIBUTE_CONST;
899extern bool uc_is_property_currency_symbol (ucs4_t uc)
900 _UC_ATTRIBUTE_CONST;
901extern bool uc_is_property_math (ucs4_t uc)
902 _UC_ATTRIBUTE_CONST;
903extern bool uc_is_property_other_math (ucs4_t uc)
904 _UC_ATTRIBUTE_CONST;
905extern bool uc_is_property_paired_punctuation (ucs4_t uc)
906 _UC_ATTRIBUTE_CONST;
907extern bool uc_is_property_left_of_pair (ucs4_t uc)
908 _UC_ATTRIBUTE_CONST;
909extern bool uc_is_property_combining (ucs4_t uc)
910 _UC_ATTRIBUTE_CONST;
911extern bool uc_is_property_composite (ucs4_t uc)
912 _UC_ATTRIBUTE_CONST;
913extern bool uc_is_property_decimal_digit (ucs4_t uc)
914 _UC_ATTRIBUTE_CONST;
915extern bool uc_is_property_numeric (ucs4_t uc)
916 _UC_ATTRIBUTE_CONST;
917extern bool uc_is_property_diacritic (ucs4_t uc)
918 _UC_ATTRIBUTE_CONST;
919extern bool uc_is_property_extender (ucs4_t uc)
920 _UC_ATTRIBUTE_CONST;
921extern bool uc_is_property_ignorable_control (ucs4_t uc)
922 _UC_ATTRIBUTE_CONST;
923extern bool uc_is_property_regional_indicator (ucs4_t uc)
924 _UC_ATTRIBUTE_CONST;
925
926/* ========================================================================= */
927
928/* Other attributes. */
929
930/* ------------------------------------------------------------------------- */
931
932/* Indic_Conjunct_Break (InCB): from the file DerivedCoreProperties.txt
933 in the Unicode Character Database. */
934
935/* Possible values of the Indic_Conjunct_Break attribute.
936 This enumeration may be extended in the future. */
937enum
938{
939 UC_INDIC_CONJUNCT_BREAK_NONE, /* None */
940 UC_INDIC_CONJUNCT_BREAK_CONSONANT, /* Consonant */
941 UC_INDIC_CONJUNCT_BREAK_LINKER, /* Linker */
942 UC_INDIC_CONJUNCT_BREAK_EXTEND /* Extend */
943};
944
945/* Return the name of an Indic_Conjunct_Break value. */
946extern const char *
947 uc_indic_conjunct_break_name (int indic_conjunct_break)
948 _UC_ATTRIBUTE_CONST;
949
950/* Return the Indic_Conjunct_Break value given by name, e.g. "Consonant". */
951extern int
952 uc_indic_conjunct_break_byname (const char *indic_conjunct_break_name)
953 _UC_ATTRIBUTE_PURE;
954
955/* Return the Indic_Conjunct_Break attribute of a Unicode character. */
956extern int
957 uc_indic_conjunct_break (ucs4_t uc)
958 _UC_ATTRIBUTE_CONST;
959
960/* ========================================================================= */
961
962/* Subdivision of the Unicode characters into scripts. */
963
964typedef struct
965{
966 unsigned int code : 21;
967 unsigned int start : 1;
968 unsigned int end : 1;
969}
970uc_interval_t;
971typedef struct
972{
973 unsigned int nintervals;
974 const uc_interval_t *intervals;
975 const char *name;
976}
977uc_script_t;
978
979/* Return the script of a Unicode character. */
980extern const uc_script_t *
981 uc_script (ucs4_t uc)
982 _UC_ATTRIBUTE_CONST;
983
984/* Return the script given by name, e.g. "HAN". */
985extern const uc_script_t *
986 uc_script_byname (const char *script_name)
987 _UC_ATTRIBUTE_PURE;
988
989/* Test whether a Unicode character belongs to a given script. */
990extern bool
991 uc_is_script (ucs4_t uc, const uc_script_t *script)
992 _UC_ATTRIBUTE_PURE;
993
994/* Get the list of all scripts. */
995extern void
996 uc_all_scripts (const uc_script_t **scripts, size_t *count);
997
998/* ========================================================================= */
999
1000/* Subdivision of the Unicode character range into blocks. */
1001
1002typedef struct
1003{
1004 ucs4_t start;
1005 ucs4_t end;
1006 const char *name;
1007}
1008uc_block_t;
1009
1010/* Return the block a character belongs to. */
1011extern const uc_block_t *
1012 uc_block (ucs4_t uc)
1013 _UC_ATTRIBUTE_CONST;
1014
1015/* Test whether a Unicode character belongs to a given block. */
1016extern bool
1017 uc_is_block (ucs4_t uc, const uc_block_t *block)
1018 _UC_ATTRIBUTE_PURE;
1019
1020/* Get the list of all blocks. */
1021extern void
1022 uc_all_blocks (const uc_block_t **blocks, size_t *count);
1023
1024/* ========================================================================= */
1025
1026/* Properties taken from language standards. */
1027
1028/* Test whether a Unicode character is considered whitespace in ISO C 99. */
1029extern bool
1030 uc_is_c_whitespace (ucs4_t uc)
1031 _UC_ATTRIBUTE_CONST;
1032
1033/* Test whether a Unicode character is considered whitespace in Java. */
1034extern bool
1035 uc_is_java_whitespace (ucs4_t uc)
1036 _UC_ATTRIBUTE_CONST;
1037
1038enum
1039{
1040 UC_IDENTIFIER_START, /* valid as first or subsequent character */
1041 UC_IDENTIFIER_VALID, /* valid as subsequent character only */
1042 UC_IDENTIFIER_INVALID, /* not valid */
1043 UC_IDENTIFIER_IGNORABLE /* ignorable (Java only) */
1044};
1045
1046/* Return the categorization of a Unicode character w.r.t. the ISO C 99
1047 identifier syntax. */
1048extern int
1049 uc_c_ident_category (ucs4_t uc)
1050 _UC_ATTRIBUTE_CONST;
1051
1052/* Return the categorization of a Unicode character w.r.t. the Java
1053 identifier syntax. */
1054extern int
1055 uc_java_ident_category (ucs4_t uc)
1056 _UC_ATTRIBUTE_CONST;
1057
1058/* ========================================================================= */
1059
1060/* Like ISO C <ctype.h> and <wctype.h>. These functions are deprecated,
1061 because this set of functions was designed with ASCII in mind and cannot
1062 reflect the more diverse reality of the Unicode character set. But they
1063 can be a quick-and-dirty porting aid when migrating from wchar_t APIs
1064 to Unicode strings. */
1065
1066/* Test for any character for which 'uc_is_alpha' or 'uc_is_digit' is true. */
1067extern bool
1068 uc_is_alnum (ucs4_t uc)
1069 _UC_ATTRIBUTE_CONST;
1070
1071/* Test for any character for which 'uc_is_upper' or 'uc_is_lower' is true,
1072 or any character that is one of a locale-specific set of characters for
1073 which none of 'uc_is_cntrl', 'uc_is_digit', 'uc_is_punct', or 'uc_is_space'
1074 is true. */
1075extern bool
1076 uc_is_alpha (ucs4_t uc)
1077 _UC_ATTRIBUTE_CONST;
1078
1079/* Test for any control character. */
1080extern bool
1081 uc_is_cntrl (ucs4_t uc)
1082 _UC_ATTRIBUTE_CONST;
1083
1084/* Test for any character that corresponds to a decimal-digit character. */
1085extern bool
1086 uc_is_digit (ucs4_t uc)
1087 _UC_ATTRIBUTE_CONST;
1088
1089/* Test for any character for which 'uc_is_print' is true and 'uc_is_space'
1090 is false. */
1091extern bool
1092 uc_is_graph (ucs4_t uc)
1093 _UC_ATTRIBUTE_CONST;
1094
1095/* Test for any character that corresponds to a lowercase letter or is one
1096 of a locale-specific set of characters for which none of 'uc_is_cntrl',
1097 'uc_is_digit', 'uc_is_punct', or 'uc_is_space' is true. */
1098extern bool
1099 uc_is_lower (ucs4_t uc)
1100 _UC_ATTRIBUTE_CONST;
1101
1102/* Test for any printing character. */
1103extern bool
1104 uc_is_print (ucs4_t uc)
1105 _UC_ATTRIBUTE_CONST;
1106
1107/* Test for any printing character that is one of a locale-specific set of
1108 characters for which neither 'uc_is_space' nor 'uc_is_alnum' is true. */
1109extern bool
1110 uc_is_punct (ucs4_t uc)
1111 _UC_ATTRIBUTE_CONST;
1112
1113/* Test for any character that corresponds to a locale-specific set of
1114 characters for which none of 'uc_is_alnum', 'uc_is_graph', or 'uc_is_punct'
1115 is true. */
1116extern bool
1117 uc_is_space (ucs4_t uc)
1118 _UC_ATTRIBUTE_CONST;
1119
1120/* Test for any character that corresponds to an uppercase letter or is one
1121 of a locale-specific set of character for which none of 'uc_is_cntrl',
1122 'uc_is_digit', 'uc_is_punct', or 'uc_is_space' is true. */
1123extern bool
1124 uc_is_upper (ucs4_t uc)
1125 _UC_ATTRIBUTE_CONST;
1126
1127/* Test for any character that corresponds to a hexadecimal-digit
1128 character. */
1129extern bool
1130 uc_is_xdigit (ucs4_t uc)
1131 _UC_ATTRIBUTE_CONST;
1132
1133/* GNU extension. */
1134/* Test for any character that corresponds to a standard blank character or
1135 a locale-specific set of characters for which 'uc_is_alnum' is false. */
1136extern bool
1137 uc_is_blank (ucs4_t uc)
1138 _UC_ATTRIBUTE_CONST;
1139
1140/* ========================================================================= */
1141
1142#ifdef __cplusplus
1143}
1144#endif
1145
1146#endif /* _UNICTYPE_H */
diff --git a/gl/unictype/.deps/.dirstamp b/gl/unictype/.deps/.dirstamp
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gl/unictype/.deps/.dirstamp
diff --git a/gl/unictype/.deps/libgnu_a-ctype_alnum.Po b/gl/unictype/.deps/libgnu_a-ctype_alnum.Po
new file mode 100644
index 00000000..429d1968
--- /dev/null
+++ b/gl/unictype/.deps/libgnu_a-ctype_alnum.Po
@@ -0,0 +1,48 @@
1unictype/libgnu_a-ctype_alnum.o: unictype/ctype_alnum.c \
2 /usr/include/stdc-predef.h ../config.h unictype.h unitypes.h \
3 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h /usr/include/stdint.h \
4 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
5 /usr/include/features.h /usr/include/features-time64.h \
6 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
7 /usr/include/x86_64-linux-gnu/bits/timesize.h \
8 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
9 /usr/include/x86_64-linux-gnu/bits/long-double.h \
10 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
11 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
12 /usr/include/x86_64-linux-gnu/bits/types.h \
13 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
14 /usr/include/x86_64-linux-gnu/bits/time64.h \
15 /usr/include/x86_64-linux-gnu/bits/wchar.h \
16 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
17 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
18 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
19 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h stddef.h \
20 /usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h unictype/bitmap.h \
21 unictype/ctype_alnum.h
22/usr/include/stdc-predef.h:
23../config.h:
24unictype.h:
25unitypes.h:
26/usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h:
27/usr/include/stdint.h:
28/usr/include/x86_64-linux-gnu/bits/libc-header-start.h:
29/usr/include/features.h:
30/usr/include/features-time64.h:
31/usr/include/x86_64-linux-gnu/bits/wordsize.h:
32/usr/include/x86_64-linux-gnu/bits/timesize.h:
33/usr/include/x86_64-linux-gnu/sys/cdefs.h:
34/usr/include/x86_64-linux-gnu/bits/long-double.h:
35/usr/include/x86_64-linux-gnu/gnu/stubs.h:
36/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
37/usr/include/x86_64-linux-gnu/bits/types.h:
38/usr/include/x86_64-linux-gnu/bits/typesizes.h:
39/usr/include/x86_64-linux-gnu/bits/time64.h:
40/usr/include/x86_64-linux-gnu/bits/wchar.h:
41/usr/include/x86_64-linux-gnu/bits/stdint-intn.h:
42/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h:
43/usr/include/x86_64-linux-gnu/bits/stdint-least.h:
44/usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h:
45stddef.h:
46/usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h:
47unictype/bitmap.h:
48unictype/ctype_alnum.h:
diff --git a/gl/unictype/.deps/libgnu_a-ctype_alpha.Po b/gl/unictype/.deps/libgnu_a-ctype_alpha.Po
new file mode 100644
index 00000000..f2d01713
--- /dev/null
+++ b/gl/unictype/.deps/libgnu_a-ctype_alpha.Po
@@ -0,0 +1,48 @@
1unictype/libgnu_a-ctype_alpha.o: unictype/ctype_alpha.c \
2 /usr/include/stdc-predef.h ../config.h unictype.h unitypes.h \
3 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h /usr/include/stdint.h \
4 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
5 /usr/include/features.h /usr/include/features-time64.h \
6 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
7 /usr/include/x86_64-linux-gnu/bits/timesize.h \
8 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
9 /usr/include/x86_64-linux-gnu/bits/long-double.h \
10 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
11 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
12 /usr/include/x86_64-linux-gnu/bits/types.h \
13 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
14 /usr/include/x86_64-linux-gnu/bits/time64.h \
15 /usr/include/x86_64-linux-gnu/bits/wchar.h \
16 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
17 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
18 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
19 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h stddef.h \
20 /usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h unictype/bitmap.h \
21 unictype/ctype_alpha.h
22/usr/include/stdc-predef.h:
23../config.h:
24unictype.h:
25unitypes.h:
26/usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h:
27/usr/include/stdint.h:
28/usr/include/x86_64-linux-gnu/bits/libc-header-start.h:
29/usr/include/features.h:
30/usr/include/features-time64.h:
31/usr/include/x86_64-linux-gnu/bits/wordsize.h:
32/usr/include/x86_64-linux-gnu/bits/timesize.h:
33/usr/include/x86_64-linux-gnu/sys/cdefs.h:
34/usr/include/x86_64-linux-gnu/bits/long-double.h:
35/usr/include/x86_64-linux-gnu/gnu/stubs.h:
36/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
37/usr/include/x86_64-linux-gnu/bits/types.h:
38/usr/include/x86_64-linux-gnu/bits/typesizes.h:
39/usr/include/x86_64-linux-gnu/bits/time64.h:
40/usr/include/x86_64-linux-gnu/bits/wchar.h:
41/usr/include/x86_64-linux-gnu/bits/stdint-intn.h:
42/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h:
43/usr/include/x86_64-linux-gnu/bits/stdint-least.h:
44/usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h:
45stddef.h:
46/usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h:
47unictype/bitmap.h:
48unictype/ctype_alpha.h:
diff --git a/gl/unictype/.deps/libgnu_a-ctype_blank.Po b/gl/unictype/.deps/libgnu_a-ctype_blank.Po
new file mode 100644
index 00000000..82be4126
--- /dev/null
+++ b/gl/unictype/.deps/libgnu_a-ctype_blank.Po
@@ -0,0 +1,48 @@
1unictype/libgnu_a-ctype_blank.o: unictype/ctype_blank.c \
2 /usr/include/stdc-predef.h ../config.h unictype.h unitypes.h \
3 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h /usr/include/stdint.h \
4 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
5 /usr/include/features.h /usr/include/features-time64.h \
6 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
7 /usr/include/x86_64-linux-gnu/bits/timesize.h \
8 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
9 /usr/include/x86_64-linux-gnu/bits/long-double.h \
10 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
11 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
12 /usr/include/x86_64-linux-gnu/bits/types.h \
13 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
14 /usr/include/x86_64-linux-gnu/bits/time64.h \
15 /usr/include/x86_64-linux-gnu/bits/wchar.h \
16 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
17 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
18 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
19 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h stddef.h \
20 /usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h unictype/bitmap.h \
21 unictype/ctype_blank.h
22/usr/include/stdc-predef.h:
23../config.h:
24unictype.h:
25unitypes.h:
26/usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h:
27/usr/include/stdint.h:
28/usr/include/x86_64-linux-gnu/bits/libc-header-start.h:
29/usr/include/features.h:
30/usr/include/features-time64.h:
31/usr/include/x86_64-linux-gnu/bits/wordsize.h:
32/usr/include/x86_64-linux-gnu/bits/timesize.h:
33/usr/include/x86_64-linux-gnu/sys/cdefs.h:
34/usr/include/x86_64-linux-gnu/bits/long-double.h:
35/usr/include/x86_64-linux-gnu/gnu/stubs.h:
36/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
37/usr/include/x86_64-linux-gnu/bits/types.h:
38/usr/include/x86_64-linux-gnu/bits/typesizes.h:
39/usr/include/x86_64-linux-gnu/bits/time64.h:
40/usr/include/x86_64-linux-gnu/bits/wchar.h:
41/usr/include/x86_64-linux-gnu/bits/stdint-intn.h:
42/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h:
43/usr/include/x86_64-linux-gnu/bits/stdint-least.h:
44/usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h:
45stddef.h:
46/usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h:
47unictype/bitmap.h:
48unictype/ctype_blank.h:
diff --git a/gl/unictype/.deps/libgnu_a-ctype_cntrl.Po b/gl/unictype/.deps/libgnu_a-ctype_cntrl.Po
new file mode 100644
index 00000000..dfb2233d
--- /dev/null
+++ b/gl/unictype/.deps/libgnu_a-ctype_cntrl.Po
@@ -0,0 +1,48 @@
1unictype/libgnu_a-ctype_cntrl.o: unictype/ctype_cntrl.c \
2 /usr/include/stdc-predef.h ../config.h unictype.h unitypes.h \
3 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h /usr/include/stdint.h \
4 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
5 /usr/include/features.h /usr/include/features-time64.h \
6 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
7 /usr/include/x86_64-linux-gnu/bits/timesize.h \
8 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
9 /usr/include/x86_64-linux-gnu/bits/long-double.h \
10 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
11 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
12 /usr/include/x86_64-linux-gnu/bits/types.h \
13 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
14 /usr/include/x86_64-linux-gnu/bits/time64.h \
15 /usr/include/x86_64-linux-gnu/bits/wchar.h \
16 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
17 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
18 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
19 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h stddef.h \
20 /usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h unictype/bitmap.h \
21 unictype/ctype_cntrl.h
22/usr/include/stdc-predef.h:
23../config.h:
24unictype.h:
25unitypes.h:
26/usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h:
27/usr/include/stdint.h:
28/usr/include/x86_64-linux-gnu/bits/libc-header-start.h:
29/usr/include/features.h:
30/usr/include/features-time64.h:
31/usr/include/x86_64-linux-gnu/bits/wordsize.h:
32/usr/include/x86_64-linux-gnu/bits/timesize.h:
33/usr/include/x86_64-linux-gnu/sys/cdefs.h:
34/usr/include/x86_64-linux-gnu/bits/long-double.h:
35/usr/include/x86_64-linux-gnu/gnu/stubs.h:
36/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
37/usr/include/x86_64-linux-gnu/bits/types.h:
38/usr/include/x86_64-linux-gnu/bits/typesizes.h:
39/usr/include/x86_64-linux-gnu/bits/time64.h:
40/usr/include/x86_64-linux-gnu/bits/wchar.h:
41/usr/include/x86_64-linux-gnu/bits/stdint-intn.h:
42/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h:
43/usr/include/x86_64-linux-gnu/bits/stdint-least.h:
44/usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h:
45stddef.h:
46/usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h:
47unictype/bitmap.h:
48unictype/ctype_cntrl.h:
diff --git a/gl/unictype/.deps/libgnu_a-ctype_digit.Po b/gl/unictype/.deps/libgnu_a-ctype_digit.Po
new file mode 100644
index 00000000..d243fcc1
--- /dev/null
+++ b/gl/unictype/.deps/libgnu_a-ctype_digit.Po
@@ -0,0 +1,48 @@
1unictype/libgnu_a-ctype_digit.o: unictype/ctype_digit.c \
2 /usr/include/stdc-predef.h ../config.h unictype.h unitypes.h \
3 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h /usr/include/stdint.h \
4 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
5 /usr/include/features.h /usr/include/features-time64.h \
6 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
7 /usr/include/x86_64-linux-gnu/bits/timesize.h \
8 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
9 /usr/include/x86_64-linux-gnu/bits/long-double.h \
10 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
11 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
12 /usr/include/x86_64-linux-gnu/bits/types.h \
13 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
14 /usr/include/x86_64-linux-gnu/bits/time64.h \
15 /usr/include/x86_64-linux-gnu/bits/wchar.h \
16 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
17 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
18 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
19 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h stddef.h \
20 /usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h unictype/bitmap.h \
21 unictype/ctype_digit.h
22/usr/include/stdc-predef.h:
23../config.h:
24unictype.h:
25unitypes.h:
26/usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h:
27/usr/include/stdint.h:
28/usr/include/x86_64-linux-gnu/bits/libc-header-start.h:
29/usr/include/features.h:
30/usr/include/features-time64.h:
31/usr/include/x86_64-linux-gnu/bits/wordsize.h:
32/usr/include/x86_64-linux-gnu/bits/timesize.h:
33/usr/include/x86_64-linux-gnu/sys/cdefs.h:
34/usr/include/x86_64-linux-gnu/bits/long-double.h:
35/usr/include/x86_64-linux-gnu/gnu/stubs.h:
36/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
37/usr/include/x86_64-linux-gnu/bits/types.h:
38/usr/include/x86_64-linux-gnu/bits/typesizes.h:
39/usr/include/x86_64-linux-gnu/bits/time64.h:
40/usr/include/x86_64-linux-gnu/bits/wchar.h:
41/usr/include/x86_64-linux-gnu/bits/stdint-intn.h:
42/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h:
43/usr/include/x86_64-linux-gnu/bits/stdint-least.h:
44/usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h:
45stddef.h:
46/usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h:
47unictype/bitmap.h:
48unictype/ctype_digit.h:
diff --git a/gl/unictype/.deps/libgnu_a-ctype_graph.Po b/gl/unictype/.deps/libgnu_a-ctype_graph.Po
new file mode 100644
index 00000000..9850fe6f
--- /dev/null
+++ b/gl/unictype/.deps/libgnu_a-ctype_graph.Po
@@ -0,0 +1,48 @@
1unictype/libgnu_a-ctype_graph.o: unictype/ctype_graph.c \
2 /usr/include/stdc-predef.h ../config.h unictype.h unitypes.h \
3 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h /usr/include/stdint.h \
4 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
5 /usr/include/features.h /usr/include/features-time64.h \
6 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
7 /usr/include/x86_64-linux-gnu/bits/timesize.h \
8 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
9 /usr/include/x86_64-linux-gnu/bits/long-double.h \
10 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
11 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
12 /usr/include/x86_64-linux-gnu/bits/types.h \
13 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
14 /usr/include/x86_64-linux-gnu/bits/time64.h \
15 /usr/include/x86_64-linux-gnu/bits/wchar.h \
16 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
17 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
18 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
19 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h stddef.h \
20 /usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h unictype/bitmap.h \
21 unictype/ctype_graph.h
22/usr/include/stdc-predef.h:
23../config.h:
24unictype.h:
25unitypes.h:
26/usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h:
27/usr/include/stdint.h:
28/usr/include/x86_64-linux-gnu/bits/libc-header-start.h:
29/usr/include/features.h:
30/usr/include/features-time64.h:
31/usr/include/x86_64-linux-gnu/bits/wordsize.h:
32/usr/include/x86_64-linux-gnu/bits/timesize.h:
33/usr/include/x86_64-linux-gnu/sys/cdefs.h:
34/usr/include/x86_64-linux-gnu/bits/long-double.h:
35/usr/include/x86_64-linux-gnu/gnu/stubs.h:
36/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
37/usr/include/x86_64-linux-gnu/bits/types.h:
38/usr/include/x86_64-linux-gnu/bits/typesizes.h:
39/usr/include/x86_64-linux-gnu/bits/time64.h:
40/usr/include/x86_64-linux-gnu/bits/wchar.h:
41/usr/include/x86_64-linux-gnu/bits/stdint-intn.h:
42/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h:
43/usr/include/x86_64-linux-gnu/bits/stdint-least.h:
44/usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h:
45stddef.h:
46/usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h:
47unictype/bitmap.h:
48unictype/ctype_graph.h:
diff --git a/gl/unictype/.deps/libgnu_a-ctype_lower.Po b/gl/unictype/.deps/libgnu_a-ctype_lower.Po
new file mode 100644
index 00000000..6447d3e4
--- /dev/null
+++ b/gl/unictype/.deps/libgnu_a-ctype_lower.Po
@@ -0,0 +1,48 @@
1unictype/libgnu_a-ctype_lower.o: unictype/ctype_lower.c \
2 /usr/include/stdc-predef.h ../config.h unictype.h unitypes.h \
3 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h /usr/include/stdint.h \
4 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
5 /usr/include/features.h /usr/include/features-time64.h \
6 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
7 /usr/include/x86_64-linux-gnu/bits/timesize.h \
8 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
9 /usr/include/x86_64-linux-gnu/bits/long-double.h \
10 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
11 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
12 /usr/include/x86_64-linux-gnu/bits/types.h \
13 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
14 /usr/include/x86_64-linux-gnu/bits/time64.h \
15 /usr/include/x86_64-linux-gnu/bits/wchar.h \
16 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
17 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
18 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
19 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h stddef.h \
20 /usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h unictype/bitmap.h \
21 unictype/ctype_lower.h
22/usr/include/stdc-predef.h:
23../config.h:
24unictype.h:
25unitypes.h:
26/usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h:
27/usr/include/stdint.h:
28/usr/include/x86_64-linux-gnu/bits/libc-header-start.h:
29/usr/include/features.h:
30/usr/include/features-time64.h:
31/usr/include/x86_64-linux-gnu/bits/wordsize.h:
32/usr/include/x86_64-linux-gnu/bits/timesize.h:
33/usr/include/x86_64-linux-gnu/sys/cdefs.h:
34/usr/include/x86_64-linux-gnu/bits/long-double.h:
35/usr/include/x86_64-linux-gnu/gnu/stubs.h:
36/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
37/usr/include/x86_64-linux-gnu/bits/types.h:
38/usr/include/x86_64-linux-gnu/bits/typesizes.h:
39/usr/include/x86_64-linux-gnu/bits/time64.h:
40/usr/include/x86_64-linux-gnu/bits/wchar.h:
41/usr/include/x86_64-linux-gnu/bits/stdint-intn.h:
42/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h:
43/usr/include/x86_64-linux-gnu/bits/stdint-least.h:
44/usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h:
45stddef.h:
46/usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h:
47unictype/bitmap.h:
48unictype/ctype_lower.h:
diff --git a/gl/unictype/.deps/libgnu_a-ctype_print.Po b/gl/unictype/.deps/libgnu_a-ctype_print.Po
new file mode 100644
index 00000000..f592e16c
--- /dev/null
+++ b/gl/unictype/.deps/libgnu_a-ctype_print.Po
@@ -0,0 +1,48 @@
1unictype/libgnu_a-ctype_print.o: unictype/ctype_print.c \
2 /usr/include/stdc-predef.h ../config.h unictype.h unitypes.h \
3 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h /usr/include/stdint.h \
4 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
5 /usr/include/features.h /usr/include/features-time64.h \
6 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
7 /usr/include/x86_64-linux-gnu/bits/timesize.h \
8 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
9 /usr/include/x86_64-linux-gnu/bits/long-double.h \
10 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
11 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
12 /usr/include/x86_64-linux-gnu/bits/types.h \
13 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
14 /usr/include/x86_64-linux-gnu/bits/time64.h \
15 /usr/include/x86_64-linux-gnu/bits/wchar.h \
16 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
17 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
18 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
19 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h stddef.h \
20 /usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h unictype/bitmap.h \
21 unictype/ctype_print.h
22/usr/include/stdc-predef.h:
23../config.h:
24unictype.h:
25unitypes.h:
26/usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h:
27/usr/include/stdint.h:
28/usr/include/x86_64-linux-gnu/bits/libc-header-start.h:
29/usr/include/features.h:
30/usr/include/features-time64.h:
31/usr/include/x86_64-linux-gnu/bits/wordsize.h:
32/usr/include/x86_64-linux-gnu/bits/timesize.h:
33/usr/include/x86_64-linux-gnu/sys/cdefs.h:
34/usr/include/x86_64-linux-gnu/bits/long-double.h:
35/usr/include/x86_64-linux-gnu/gnu/stubs.h:
36/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
37/usr/include/x86_64-linux-gnu/bits/types.h:
38/usr/include/x86_64-linux-gnu/bits/typesizes.h:
39/usr/include/x86_64-linux-gnu/bits/time64.h:
40/usr/include/x86_64-linux-gnu/bits/wchar.h:
41/usr/include/x86_64-linux-gnu/bits/stdint-intn.h:
42/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h:
43/usr/include/x86_64-linux-gnu/bits/stdint-least.h:
44/usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h:
45stddef.h:
46/usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h:
47unictype/bitmap.h:
48unictype/ctype_print.h:
diff --git a/gl/unictype/.deps/libgnu_a-ctype_punct.Po b/gl/unictype/.deps/libgnu_a-ctype_punct.Po
new file mode 100644
index 00000000..245e5396
--- /dev/null
+++ b/gl/unictype/.deps/libgnu_a-ctype_punct.Po
@@ -0,0 +1,48 @@
1unictype/libgnu_a-ctype_punct.o: unictype/ctype_punct.c \
2 /usr/include/stdc-predef.h ../config.h unictype.h unitypes.h \
3 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h /usr/include/stdint.h \
4 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
5 /usr/include/features.h /usr/include/features-time64.h \
6 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
7 /usr/include/x86_64-linux-gnu/bits/timesize.h \
8 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
9 /usr/include/x86_64-linux-gnu/bits/long-double.h \
10 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
11 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
12 /usr/include/x86_64-linux-gnu/bits/types.h \
13 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
14 /usr/include/x86_64-linux-gnu/bits/time64.h \
15 /usr/include/x86_64-linux-gnu/bits/wchar.h \
16 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
17 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
18 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
19 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h stddef.h \
20 /usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h unictype/bitmap.h \
21 unictype/ctype_punct.h
22/usr/include/stdc-predef.h:
23../config.h:
24unictype.h:
25unitypes.h:
26/usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h:
27/usr/include/stdint.h:
28/usr/include/x86_64-linux-gnu/bits/libc-header-start.h:
29/usr/include/features.h:
30/usr/include/features-time64.h:
31/usr/include/x86_64-linux-gnu/bits/wordsize.h:
32/usr/include/x86_64-linux-gnu/bits/timesize.h:
33/usr/include/x86_64-linux-gnu/sys/cdefs.h:
34/usr/include/x86_64-linux-gnu/bits/long-double.h:
35/usr/include/x86_64-linux-gnu/gnu/stubs.h:
36/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
37/usr/include/x86_64-linux-gnu/bits/types.h:
38/usr/include/x86_64-linux-gnu/bits/typesizes.h:
39/usr/include/x86_64-linux-gnu/bits/time64.h:
40/usr/include/x86_64-linux-gnu/bits/wchar.h:
41/usr/include/x86_64-linux-gnu/bits/stdint-intn.h:
42/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h:
43/usr/include/x86_64-linux-gnu/bits/stdint-least.h:
44/usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h:
45stddef.h:
46/usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h:
47unictype/bitmap.h:
48unictype/ctype_punct.h:
diff --git a/gl/unictype/.deps/libgnu_a-ctype_space.Po b/gl/unictype/.deps/libgnu_a-ctype_space.Po
new file mode 100644
index 00000000..2b51c518
--- /dev/null
+++ b/gl/unictype/.deps/libgnu_a-ctype_space.Po
@@ -0,0 +1,48 @@
1unictype/libgnu_a-ctype_space.o: unictype/ctype_space.c \
2 /usr/include/stdc-predef.h ../config.h unictype.h unitypes.h \
3 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h /usr/include/stdint.h \
4 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
5 /usr/include/features.h /usr/include/features-time64.h \
6 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
7 /usr/include/x86_64-linux-gnu/bits/timesize.h \
8 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
9 /usr/include/x86_64-linux-gnu/bits/long-double.h \
10 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
11 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
12 /usr/include/x86_64-linux-gnu/bits/types.h \
13 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
14 /usr/include/x86_64-linux-gnu/bits/time64.h \
15 /usr/include/x86_64-linux-gnu/bits/wchar.h \
16 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
17 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
18 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
19 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h stddef.h \
20 /usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h unictype/bitmap.h \
21 unictype/ctype_space.h
22/usr/include/stdc-predef.h:
23../config.h:
24unictype.h:
25unitypes.h:
26/usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h:
27/usr/include/stdint.h:
28/usr/include/x86_64-linux-gnu/bits/libc-header-start.h:
29/usr/include/features.h:
30/usr/include/features-time64.h:
31/usr/include/x86_64-linux-gnu/bits/wordsize.h:
32/usr/include/x86_64-linux-gnu/bits/timesize.h:
33/usr/include/x86_64-linux-gnu/sys/cdefs.h:
34/usr/include/x86_64-linux-gnu/bits/long-double.h:
35/usr/include/x86_64-linux-gnu/gnu/stubs.h:
36/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
37/usr/include/x86_64-linux-gnu/bits/types.h:
38/usr/include/x86_64-linux-gnu/bits/typesizes.h:
39/usr/include/x86_64-linux-gnu/bits/time64.h:
40/usr/include/x86_64-linux-gnu/bits/wchar.h:
41/usr/include/x86_64-linux-gnu/bits/stdint-intn.h:
42/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h:
43/usr/include/x86_64-linux-gnu/bits/stdint-least.h:
44/usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h:
45stddef.h:
46/usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h:
47unictype/bitmap.h:
48unictype/ctype_space.h:
diff --git a/gl/unictype/.deps/libgnu_a-ctype_upper.Po b/gl/unictype/.deps/libgnu_a-ctype_upper.Po
new file mode 100644
index 00000000..3395834f
--- /dev/null
+++ b/gl/unictype/.deps/libgnu_a-ctype_upper.Po
@@ -0,0 +1,48 @@
1unictype/libgnu_a-ctype_upper.o: unictype/ctype_upper.c \
2 /usr/include/stdc-predef.h ../config.h unictype.h unitypes.h \
3 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h /usr/include/stdint.h \
4 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
5 /usr/include/features.h /usr/include/features-time64.h \
6 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
7 /usr/include/x86_64-linux-gnu/bits/timesize.h \
8 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
9 /usr/include/x86_64-linux-gnu/bits/long-double.h \
10 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
11 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
12 /usr/include/x86_64-linux-gnu/bits/types.h \
13 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
14 /usr/include/x86_64-linux-gnu/bits/time64.h \
15 /usr/include/x86_64-linux-gnu/bits/wchar.h \
16 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
17 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
18 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
19 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h stddef.h \
20 /usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h unictype/bitmap.h \
21 unictype/ctype_upper.h
22/usr/include/stdc-predef.h:
23../config.h:
24unictype.h:
25unitypes.h:
26/usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h:
27/usr/include/stdint.h:
28/usr/include/x86_64-linux-gnu/bits/libc-header-start.h:
29/usr/include/features.h:
30/usr/include/features-time64.h:
31/usr/include/x86_64-linux-gnu/bits/wordsize.h:
32/usr/include/x86_64-linux-gnu/bits/timesize.h:
33/usr/include/x86_64-linux-gnu/sys/cdefs.h:
34/usr/include/x86_64-linux-gnu/bits/long-double.h:
35/usr/include/x86_64-linux-gnu/gnu/stubs.h:
36/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
37/usr/include/x86_64-linux-gnu/bits/types.h:
38/usr/include/x86_64-linux-gnu/bits/typesizes.h:
39/usr/include/x86_64-linux-gnu/bits/time64.h:
40/usr/include/x86_64-linux-gnu/bits/wchar.h:
41/usr/include/x86_64-linux-gnu/bits/stdint-intn.h:
42/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h:
43/usr/include/x86_64-linux-gnu/bits/stdint-least.h:
44/usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h:
45stddef.h:
46/usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h:
47unictype/bitmap.h:
48unictype/ctype_upper.h:
diff --git a/gl/unictype/.deps/libgnu_a-ctype_xdigit.Po b/gl/unictype/.deps/libgnu_a-ctype_xdigit.Po
new file mode 100644
index 00000000..3c05b331
--- /dev/null
+++ b/gl/unictype/.deps/libgnu_a-ctype_xdigit.Po
@@ -0,0 +1,48 @@
1unictype/libgnu_a-ctype_xdigit.o: unictype/ctype_xdigit.c \
2 /usr/include/stdc-predef.h ../config.h unictype.h unitypes.h \
3 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h /usr/include/stdint.h \
4 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
5 /usr/include/features.h /usr/include/features-time64.h \
6 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
7 /usr/include/x86_64-linux-gnu/bits/timesize.h \
8 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
9 /usr/include/x86_64-linux-gnu/bits/long-double.h \
10 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
11 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
12 /usr/include/x86_64-linux-gnu/bits/types.h \
13 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
14 /usr/include/x86_64-linux-gnu/bits/time64.h \
15 /usr/include/x86_64-linux-gnu/bits/wchar.h \
16 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
17 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
18 /usr/include/x86_64-linux-gnu/bits/stdint-least.h \
19 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h stddef.h \
20 /usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h unictype/bitmap.h \
21 unictype/ctype_xdigit.h
22/usr/include/stdc-predef.h:
23../config.h:
24unictype.h:
25unitypes.h:
26/usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h:
27/usr/include/stdint.h:
28/usr/include/x86_64-linux-gnu/bits/libc-header-start.h:
29/usr/include/features.h:
30/usr/include/features-time64.h:
31/usr/include/x86_64-linux-gnu/bits/wordsize.h:
32/usr/include/x86_64-linux-gnu/bits/timesize.h:
33/usr/include/x86_64-linux-gnu/sys/cdefs.h:
34/usr/include/x86_64-linux-gnu/bits/long-double.h:
35/usr/include/x86_64-linux-gnu/gnu/stubs.h:
36/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
37/usr/include/x86_64-linux-gnu/bits/types.h:
38/usr/include/x86_64-linux-gnu/bits/typesizes.h:
39/usr/include/x86_64-linux-gnu/bits/time64.h:
40/usr/include/x86_64-linux-gnu/bits/wchar.h:
41/usr/include/x86_64-linux-gnu/bits/stdint-intn.h:
42/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h:
43/usr/include/x86_64-linux-gnu/bits/stdint-least.h:
44/usr/lib/gcc/x86_64-linux-gnu/15/include/stdbool.h:
45stddef.h:
46/usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h:
47unictype/bitmap.h:
48unictype/ctype_xdigit.h:
diff --git a/gl/unictype/.dirstamp b/gl/unictype/.dirstamp
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gl/unictype/.dirstamp
diff --git a/gl/unictype/bitmap.h b/gl/unictype/bitmap.h
new file mode 100644
index 00000000..869ac066
--- /dev/null
+++ b/gl/unictype/bitmap.h
@@ -0,0 +1,48 @@
1/* Three-level bitmap lookup.
2 Copyright (C) 2000-2002, 2005-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2000-2002.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18static inline int bitmap_lookup (const void *table, ucs4_t uc);
19
20/* These values are currently hardcoded into gen-uni-tables.c, function
21 output_predicate(). */
22#define header_0 16
23#define header_2 9
24#define header_3 127
25#define header_4 15
26
27static inline int
28bitmap_lookup (const void *table, ucs4_t uc)
29{
30 unsigned int index1 = uc >> header_0;
31 if (index1 < ((const int *) table)[0])
32 {
33 int lookup1 = ((const int *) table)[1 + index1];
34 if (lookup1 >= 0)
35 {
36 unsigned int index2 = (uc >> header_2) & header_3;
37 int lookup2 = ((const short *) table)[lookup1 + index2];
38 if (lookup2 >= 0)
39 {
40 unsigned int index3 = (uc >> 5) & header_4;
41 unsigned int lookup3 = ((const unsigned int *) table)[lookup2 + index3];
42
43 return (lookup3 >> (uc & 0x1f)) & 1;
44 }
45 }
46 }
47 return 0;
48}
diff --git a/gl/unictype/ctype_alnum.c b/gl/unictype/ctype_alnum.c
new file mode 100644
index 00000000..f58f4310
--- /dev/null
+++ b/gl/unictype/ctype_alnum.c
@@ -0,0 +1,32 @@
1/* ISO C <ctype.h> like properties of Unicode characters.
2 Copyright (C) 2002, 2006-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2002.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include "unictype.h"
22
23#include "bitmap.h"
24
25/* Define u_is_alnum table. */
26#include "ctype_alnum.h"
27
28bool
29uc_is_alnum (ucs4_t uc)
30{
31 return bitmap_lookup (&u_is_alnum, uc);
32}
diff --git a/gl/unictype/ctype_alnum.h b/gl/unictype/ctype_alnum.h
new file mode 100644
index 00000000..3ee771ab
--- /dev/null
+++ b/gl/unictype/ctype_alnum.h
@@ -0,0 +1,897 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* ISO C <ctype.h> like properties of Unicode characters. */
3/* Generated automatically by gen-uni-tables.c for Unicode 16.0.0. */
4
5/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
6
7 This file is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 This file is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19
20#define header_0 16
21#define header_2 9
22#define header_3 127
23#define header_4 15
24static const
25struct
26 {
27 int header[1];
28 int level1[4];
29 short level2[4 << 7];
30 unsigned int level3[85 << 4];
31 }
32u_is_alnum =
33{
34 { 4 },
35 {
36 5 * sizeof (int) / sizeof (short) + 0,
37 5 * sizeof (int) / sizeof (short) + 128,
38 5 * sizeof (int) / sizeof (short) + 256,
39 5 * sizeof (int) / sizeof (short) + 384
40 },
41 {
42 5 + 512 * sizeof (short) / sizeof (int) + 0,
43 5 + 512 * sizeof (short) / sizeof (int) + 16,
44 5 + 512 * sizeof (short) / sizeof (int) + 32,
45 5 + 512 * sizeof (short) / sizeof (int) + 48,
46 5 + 512 * sizeof (short) / sizeof (int) + 64,
47 5 + 512 * sizeof (short) / sizeof (int) + 80,
48 5 + 512 * sizeof (short) / sizeof (int) + 96,
49 5 + 512 * sizeof (short) / sizeof (int) + 112,
50 5 + 512 * sizeof (short) / sizeof (int) + 128,
51 5 + 512 * sizeof (short) / sizeof (int) + 144,
52 5 + 512 * sizeof (short) / sizeof (int) + 160,
53 5 + 512 * sizeof (short) / sizeof (int) + 176,
54 5 + 512 * sizeof (short) / sizeof (int) + 192,
55 5 + 512 * sizeof (short) / sizeof (int) + 208,
56 5 + 512 * sizeof (short) / sizeof (int) + 224,
57 5 + 512 * sizeof (short) / sizeof (int) + 240,
58 5 + 512 * sizeof (short) / sizeof (int) + 256,
59 -1,
60 5 + 512 * sizeof (short) / sizeof (int) + 272,
61 -1,
62 -1,
63 -1,
64 5 + 512 * sizeof (short) / sizeof (int) + 288,
65 5 + 512 * sizeof (short) / sizeof (int) + 304,
66 5 + 512 * sizeof (short) / sizeof (int) + 320,
67 -1,
68 5 + 512 * sizeof (short) / sizeof (int) + 336,
69 5 + 512 * sizeof (short) / sizeof (int) + 336,
70 5 + 512 * sizeof (short) / sizeof (int) + 336,
71 5 + 512 * sizeof (short) / sizeof (int) + 336,
72 5 + 512 * sizeof (short) / sizeof (int) + 336,
73 5 + 512 * sizeof (short) / sizeof (int) + 336,
74 5 + 512 * sizeof (short) / sizeof (int) + 336,
75 5 + 512 * sizeof (short) / sizeof (int) + 336,
76 5 + 512 * sizeof (short) / sizeof (int) + 336,
77 5 + 512 * sizeof (short) / sizeof (int) + 336,
78 5 + 512 * sizeof (short) / sizeof (int) + 336,
79 5 + 512 * sizeof (short) / sizeof (int) + 336,
80 5 + 512 * sizeof (short) / sizeof (int) + 352,
81 5 + 512 * sizeof (short) / sizeof (int) + 336,
82 5 + 512 * sizeof (short) / sizeof (int) + 336,
83 5 + 512 * sizeof (short) / sizeof (int) + 336,
84 5 + 512 * sizeof (short) / sizeof (int) + 336,
85 5 + 512 * sizeof (short) / sizeof (int) + 336,
86 5 + 512 * sizeof (short) / sizeof (int) + 336,
87 5 + 512 * sizeof (short) / sizeof (int) + 336,
88 5 + 512 * sizeof (short) / sizeof (int) + 336,
89 5 + 512 * sizeof (short) / sizeof (int) + 336,
90 5 + 512 * sizeof (short) / sizeof (int) + 336,
91 5 + 512 * sizeof (short) / sizeof (int) + 336,
92 5 + 512 * sizeof (short) / sizeof (int) + 336,
93 5 + 512 * sizeof (short) / sizeof (int) + 336,
94 5 + 512 * sizeof (short) / sizeof (int) + 336,
95 5 + 512 * sizeof (short) / sizeof (int) + 336,
96 5 + 512 * sizeof (short) / sizeof (int) + 336,
97 5 + 512 * sizeof (short) / sizeof (int) + 336,
98 5 + 512 * sizeof (short) / sizeof (int) + 336,
99 5 + 512 * sizeof (short) / sizeof (int) + 336,
100 5 + 512 * sizeof (short) / sizeof (int) + 336,
101 5 + 512 * sizeof (short) / sizeof (int) + 336,
102 5 + 512 * sizeof (short) / sizeof (int) + 336,
103 5 + 512 * sizeof (short) / sizeof (int) + 336,
104 5 + 512 * sizeof (short) / sizeof (int) + 336,
105 5 + 512 * sizeof (short) / sizeof (int) + 336,
106 5 + 512 * sizeof (short) / sizeof (int) + 336,
107 5 + 512 * sizeof (short) / sizeof (int) + 336,
108 5 + 512 * sizeof (short) / sizeof (int) + 336,
109 5 + 512 * sizeof (short) / sizeof (int) + 336,
110 5 + 512 * sizeof (short) / sizeof (int) + 336,
111 5 + 512 * sizeof (short) / sizeof (int) + 336,
112 5 + 512 * sizeof (short) / sizeof (int) + 336,
113 5 + 512 * sizeof (short) / sizeof (int) + 336,
114 5 + 512 * sizeof (short) / sizeof (int) + 336,
115 5 + 512 * sizeof (short) / sizeof (int) + 336,
116 5 + 512 * sizeof (short) / sizeof (int) + 336,
117 5 + 512 * sizeof (short) / sizeof (int) + 336,
118 5 + 512 * sizeof (short) / sizeof (int) + 336,
119 5 + 512 * sizeof (short) / sizeof (int) + 336,
120 5 + 512 * sizeof (short) / sizeof (int) + 336,
121 5 + 512 * sizeof (short) / sizeof (int) + 336,
122 5 + 512 * sizeof (short) / sizeof (int) + 336,
123 5 + 512 * sizeof (short) / sizeof (int) + 336,
124 5 + 512 * sizeof (short) / sizeof (int) + 368,
125 5 + 512 * sizeof (short) / sizeof (int) + 384,
126 5 + 512 * sizeof (short) / sizeof (int) + 400,
127 5 + 512 * sizeof (short) / sizeof (int) + 416,
128 5 + 512 * sizeof (short) / sizeof (int) + 336,
129 5 + 512 * sizeof (short) / sizeof (int) + 336,
130 5 + 512 * sizeof (short) / sizeof (int) + 336,
131 5 + 512 * sizeof (short) / sizeof (int) + 336,
132 5 + 512 * sizeof (short) / sizeof (int) + 336,
133 5 + 512 * sizeof (short) / sizeof (int) + 336,
134 5 + 512 * sizeof (short) / sizeof (int) + 336,
135 5 + 512 * sizeof (short) / sizeof (int) + 336,
136 5 + 512 * sizeof (short) / sizeof (int) + 336,
137 5 + 512 * sizeof (short) / sizeof (int) + 336,
138 5 + 512 * sizeof (short) / sizeof (int) + 336,
139 5 + 512 * sizeof (short) / sizeof (int) + 336,
140 5 + 512 * sizeof (short) / sizeof (int) + 336,
141 5 + 512 * sizeof (short) / sizeof (int) + 336,
142 5 + 512 * sizeof (short) / sizeof (int) + 336,
143 5 + 512 * sizeof (short) / sizeof (int) + 336,
144 5 + 512 * sizeof (short) / sizeof (int) + 336,
145 5 + 512 * sizeof (short) / sizeof (int) + 336,
146 5 + 512 * sizeof (short) / sizeof (int) + 336,
147 5 + 512 * sizeof (short) / sizeof (int) + 336,
148 5 + 512 * sizeof (short) / sizeof (int) + 336,
149 5 + 512 * sizeof (short) / sizeof (int) + 432,
150 -1,
151 -1,
152 -1,
153 -1,
154 -1,
155 -1,
156 -1,
157 -1,
158 -1,
159 -1,
160 -1,
161 -1,
162 -1,
163 -1,
164 -1,
165 -1,
166 5 + 512 * sizeof (short) / sizeof (int) + 448,
167 5 + 512 * sizeof (short) / sizeof (int) + 464,
168 5 + 512 * sizeof (short) / sizeof (int) + 480,
169 5 + 512 * sizeof (short) / sizeof (int) + 496,
170 5 + 512 * sizeof (short) / sizeof (int) + 512,
171 5 + 512 * sizeof (short) / sizeof (int) + 528,
172 5 + 512 * sizeof (short) / sizeof (int) + 544,
173 5 + 512 * sizeof (short) / sizeof (int) + 560,
174 5 + 512 * sizeof (short) / sizeof (int) + 576,
175 5 + 512 * sizeof (short) / sizeof (int) + 592,
176 5 + 512 * sizeof (short) / sizeof (int) + 608,
177 5 + 512 * sizeof (short) / sizeof (int) + 624,
178 5 + 512 * sizeof (short) / sizeof (int) + 640,
179 5 + 512 * sizeof (short) / sizeof (int) + 656,
180 5 + 512 * sizeof (short) / sizeof (int) + 672,
181 5 + 512 * sizeof (short) / sizeof (int) + 688,
182 5 + 512 * sizeof (short) / sizeof (int) + 704,
183 5 + 512 * sizeof (short) / sizeof (int) + 720,
184 5 + 512 * sizeof (short) / sizeof (int) + 736,
185 5 + 512 * sizeof (short) / sizeof (int) + 752,
186 5 + 512 * sizeof (short) / sizeof (int) + 336,
187 5 + 512 * sizeof (short) / sizeof (int) + 768,
188 5 + 512 * sizeof (short) / sizeof (int) + 784,
189 -1,
190 -1,
191 -1,
192 -1,
193 5 + 512 * sizeof (short) / sizeof (int) + 800,
194 5 + 512 * sizeof (short) / sizeof (int) + 336,
195 5 + 512 * sizeof (short) / sizeof (int) + 336,
196 5 + 512 * sizeof (short) / sizeof (int) + 816,
197 5 + 512 * sizeof (short) / sizeof (int) + 336,
198 5 + 512 * sizeof (short) / sizeof (int) + 336,
199 5 + 512 * sizeof (short) / sizeof (int) + 336,
200 5 + 512 * sizeof (short) / sizeof (int) + 336,
201 5 + 512 * sizeof (short) / sizeof (int) + 336,
202 5 + 512 * sizeof (short) / sizeof (int) + 336,
203 5 + 512 * sizeof (short) / sizeof (int) + 832,
204 5 + 512 * sizeof (short) / sizeof (int) + 336,
205 5 + 512 * sizeof (short) / sizeof (int) + 848,
206 -1,
207 -1,
208 -1,
209 -1,
210 -1,
211 -1,
212 -1,
213 -1,
214 -1,
215 -1,
216 -1,
217 -1,
218 5 + 512 * sizeof (short) / sizeof (int) + 864,
219 -1,
220 -1,
221 -1,
222 5 + 512 * sizeof (short) / sizeof (int) + 336,
223 5 + 512 * sizeof (short) / sizeof (int) + 880,
224 5 + 512 * sizeof (short) / sizeof (int) + 896,
225 5 + 512 * sizeof (short) / sizeof (int) + 912,
226 5 + 512 * sizeof (short) / sizeof (int) + 336,
227 5 + 512 * sizeof (short) / sizeof (int) + 336,
228 5 + 512 * sizeof (short) / sizeof (int) + 336,
229 5 + 512 * sizeof (short) / sizeof (int) + 336,
230 5 + 512 * sizeof (short) / sizeof (int) + 336,
231 5 + 512 * sizeof (short) / sizeof (int) + 336,
232 5 + 512 * sizeof (short) / sizeof (int) + 336,
233 5 + 512 * sizeof (short) / sizeof (int) + 336,
234 5 + 512 * sizeof (short) / sizeof (int) + 336,
235 5 + 512 * sizeof (short) / sizeof (int) + 336,
236 5 + 512 * sizeof (short) / sizeof (int) + 336,
237 5 + 512 * sizeof (short) / sizeof (int) + 928,
238 5 + 512 * sizeof (short) / sizeof (int) + 336,
239 5 + 512 * sizeof (short) / sizeof (int) + 336,
240 5 + 512 * sizeof (short) / sizeof (int) + 944,
241 -1,
242 -1,
243 -1,
244 -1,
245 -1,
246 -1,
247 -1,
248 -1,
249 -1,
250 -1,
251 -1,
252 -1,
253 -1,
254 -1,
255 -1,
256 -1,
257 5 + 512 * sizeof (short) / sizeof (int) + 960,
258 5 + 512 * sizeof (short) / sizeof (int) + 976,
259 5 + 512 * sizeof (short) / sizeof (int) + 992,
260 -1,
261 -1,
262 -1,
263 -1,
264 5 + 512 * sizeof (short) / sizeof (int) + 1008,
265 -1,
266 -1,
267 -1,
268 -1,
269 -1,
270 -1,
271 -1,
272 5 + 512 * sizeof (short) / sizeof (int) + 1024,
273 -1,
274 -1,
275 -1,
276 5 + 512 * sizeof (short) / sizeof (int) + 1040,
277 5 + 512 * sizeof (short) / sizeof (int) + 1056,
278 -1,
279 -1,
280 -1,
281 5 + 512 * sizeof (short) / sizeof (int) + 1072,
282 5 + 512 * sizeof (short) / sizeof (int) + 1088,
283 5 + 512 * sizeof (short) / sizeof (int) + 1104,
284 5 + 512 * sizeof (short) / sizeof (int) + 1120,
285 5 + 512 * sizeof (short) / sizeof (int) + 1136,
286 5 + 512 * sizeof (short) / sizeof (int) + 1152,
287 -1,
288 -1,
289 5 + 512 * sizeof (short) / sizeof (int) + 1168,
290 5 + 512 * sizeof (short) / sizeof (int) + 1184,
291 -1,
292 -1,
293 -1,
294 -1,
295 5 + 512 * sizeof (short) / sizeof (int) + 1200,
296 -1,
297 -1,
298 5 + 512 * sizeof (short) / sizeof (int) + 336,
299 5 + 512 * sizeof (short) / sizeof (int) + 336,
300 5 + 512 * sizeof (short) / sizeof (int) + 336,
301 5 + 512 * sizeof (short) / sizeof (int) + 336,
302 5 + 512 * sizeof (short) / sizeof (int) + 336,
303 5 + 512 * sizeof (short) / sizeof (int) + 336,
304 5 + 512 * sizeof (short) / sizeof (int) + 336,
305 5 + 512 * sizeof (short) / sizeof (int) + 336,
306 5 + 512 * sizeof (short) / sizeof (int) + 336,
307 5 + 512 * sizeof (short) / sizeof (int) + 336,
308 5 + 512 * sizeof (short) / sizeof (int) + 336,
309 5 + 512 * sizeof (short) / sizeof (int) + 336,
310 5 + 512 * sizeof (short) / sizeof (int) + 336,
311 5 + 512 * sizeof (short) / sizeof (int) + 336,
312 5 + 512 * sizeof (short) / sizeof (int) + 336,
313 5 + 512 * sizeof (short) / sizeof (int) + 336,
314 5 + 512 * sizeof (short) / sizeof (int) + 336,
315 5 + 512 * sizeof (short) / sizeof (int) + 336,
316 5 + 512 * sizeof (short) / sizeof (int) + 336,
317 5 + 512 * sizeof (short) / sizeof (int) + 336,
318 5 + 512 * sizeof (short) / sizeof (int) + 336,
319 5 + 512 * sizeof (short) / sizeof (int) + 336,
320 5 + 512 * sizeof (short) / sizeof (int) + 336,
321 5 + 512 * sizeof (short) / sizeof (int) + 336,
322 5 + 512 * sizeof (short) / sizeof (int) + 336,
323 5 + 512 * sizeof (short) / sizeof (int) + 336,
324 5 + 512 * sizeof (short) / sizeof (int) + 336,
325 5 + 512 * sizeof (short) / sizeof (int) + 336,
326 5 + 512 * sizeof (short) / sizeof (int) + 336,
327 5 + 512 * sizeof (short) / sizeof (int) + 336,
328 5 + 512 * sizeof (short) / sizeof (int) + 336,
329 5 + 512 * sizeof (short) / sizeof (int) + 336,
330 5 + 512 * sizeof (short) / sizeof (int) + 336,
331 5 + 512 * sizeof (short) / sizeof (int) + 336,
332 5 + 512 * sizeof (short) / sizeof (int) + 336,
333 5 + 512 * sizeof (short) / sizeof (int) + 336,
334 5 + 512 * sizeof (short) / sizeof (int) + 336,
335 5 + 512 * sizeof (short) / sizeof (int) + 336,
336 5 + 512 * sizeof (short) / sizeof (int) + 336,
337 5 + 512 * sizeof (short) / sizeof (int) + 336,
338 5 + 512 * sizeof (short) / sizeof (int) + 336,
339 5 + 512 * sizeof (short) / sizeof (int) + 336,
340 5 + 512 * sizeof (short) / sizeof (int) + 336,
341 5 + 512 * sizeof (short) / sizeof (int) + 336,
342 5 + 512 * sizeof (short) / sizeof (int) + 336,
343 5 + 512 * sizeof (short) / sizeof (int) + 336,
344 5 + 512 * sizeof (short) / sizeof (int) + 336,
345 5 + 512 * sizeof (short) / sizeof (int) + 336,
346 5 + 512 * sizeof (short) / sizeof (int) + 336,
347 5 + 512 * sizeof (short) / sizeof (int) + 336,
348 5 + 512 * sizeof (short) / sizeof (int) + 336,
349 5 + 512 * sizeof (short) / sizeof (int) + 336,
350 5 + 512 * sizeof (short) / sizeof (int) + 336,
351 5 + 512 * sizeof (short) / sizeof (int) + 336,
352 5 + 512 * sizeof (short) / sizeof (int) + 336,
353 5 + 512 * sizeof (short) / sizeof (int) + 336,
354 5 + 512 * sizeof (short) / sizeof (int) + 336,
355 5 + 512 * sizeof (short) / sizeof (int) + 336,
356 5 + 512 * sizeof (short) / sizeof (int) + 336,
357 5 + 512 * sizeof (short) / sizeof (int) + 336,
358 5 + 512 * sizeof (short) / sizeof (int) + 336,
359 5 + 512 * sizeof (short) / sizeof (int) + 336,
360 5 + 512 * sizeof (short) / sizeof (int) + 336,
361 5 + 512 * sizeof (short) / sizeof (int) + 336,
362 5 + 512 * sizeof (short) / sizeof (int) + 336,
363 5 + 512 * sizeof (short) / sizeof (int) + 336,
364 5 + 512 * sizeof (short) / sizeof (int) + 336,
365 5 + 512 * sizeof (short) / sizeof (int) + 336,
366 5 + 512 * sizeof (short) / sizeof (int) + 336,
367 5 + 512 * sizeof (short) / sizeof (int) + 336,
368 5 + 512 * sizeof (short) / sizeof (int) + 336,
369 5 + 512 * sizeof (short) / sizeof (int) + 336,
370 5 + 512 * sizeof (short) / sizeof (int) + 336,
371 5 + 512 * sizeof (short) / sizeof (int) + 336,
372 5 + 512 * sizeof (short) / sizeof (int) + 336,
373 5 + 512 * sizeof (short) / sizeof (int) + 336,
374 5 + 512 * sizeof (short) / sizeof (int) + 336,
375 5 + 512 * sizeof (short) / sizeof (int) + 336,
376 5 + 512 * sizeof (short) / sizeof (int) + 336,
377 5 + 512 * sizeof (short) / sizeof (int) + 336,
378 5 + 512 * sizeof (short) / sizeof (int) + 336,
379 5 + 512 * sizeof (short) / sizeof (int) + 336,
380 5 + 512 * sizeof (short) / sizeof (int) + 336,
381 5 + 512 * sizeof (short) / sizeof (int) + 1216,
382 5 + 512 * sizeof (short) / sizeof (int) + 336,
383 5 + 512 * sizeof (short) / sizeof (int) + 336,
384 5 + 512 * sizeof (short) / sizeof (int) + 336,
385 5 + 512 * sizeof (short) / sizeof (int) + 336,
386 5 + 512 * sizeof (short) / sizeof (int) + 336,
387 5 + 512 * sizeof (short) / sizeof (int) + 336,
388 5 + 512 * sizeof (short) / sizeof (int) + 336,
389 5 + 512 * sizeof (short) / sizeof (int) + 1232,
390 5 + 512 * sizeof (short) / sizeof (int) + 1248,
391 5 + 512 * sizeof (short) / sizeof (int) + 336,
392 5 + 512 * sizeof (short) / sizeof (int) + 336,
393 5 + 512 * sizeof (short) / sizeof (int) + 336,
394 5 + 512 * sizeof (short) / sizeof (int) + 336,
395 5 + 512 * sizeof (short) / sizeof (int) + 336,
396 5 + 512 * sizeof (short) / sizeof (int) + 336,
397 5 + 512 * sizeof (short) / sizeof (int) + 336,
398 5 + 512 * sizeof (short) / sizeof (int) + 336,
399 5 + 512 * sizeof (short) / sizeof (int) + 336,
400 5 + 512 * sizeof (short) / sizeof (int) + 336,
401 5 + 512 * sizeof (short) / sizeof (int) + 1264,
402 5 + 512 * sizeof (short) / sizeof (int) + 336,
403 5 + 512 * sizeof (short) / sizeof (int) + 336,
404 5 + 512 * sizeof (short) / sizeof (int) + 336,
405 5 + 512 * sizeof (short) / sizeof (int) + 336,
406 5 + 512 * sizeof (short) / sizeof (int) + 336,
407 5 + 512 * sizeof (short) / sizeof (int) + 336,
408 5 + 512 * sizeof (short) / sizeof (int) + 336,
409 5 + 512 * sizeof (short) / sizeof (int) + 336,
410 5 + 512 * sizeof (short) / sizeof (int) + 336,
411 5 + 512 * sizeof (short) / sizeof (int) + 336,
412 5 + 512 * sizeof (short) / sizeof (int) + 336,
413 5 + 512 * sizeof (short) / sizeof (int) + 336,
414 5 + 512 * sizeof (short) / sizeof (int) + 336,
415 5 + 512 * sizeof (short) / sizeof (int) + 1280,
416 5 + 512 * sizeof (short) / sizeof (int) + 336,
417 5 + 512 * sizeof (short) / sizeof (int) + 1296,
418 -1,
419 -1,
420 -1,
421 -1,
422 5 + 512 * sizeof (short) / sizeof (int) + 336,
423 5 + 512 * sizeof (short) / sizeof (int) + 1312,
424 -1,
425 -1,
426 5 + 512 * sizeof (short) / sizeof (int) + 336,
427 5 + 512 * sizeof (short) / sizeof (int) + 336,
428 5 + 512 * sizeof (short) / sizeof (int) + 336,
429 5 + 512 * sizeof (short) / sizeof (int) + 336,
430 5 + 512 * sizeof (short) / sizeof (int) + 336,
431 5 + 512 * sizeof (short) / sizeof (int) + 336,
432 5 + 512 * sizeof (short) / sizeof (int) + 336,
433 5 + 512 * sizeof (short) / sizeof (int) + 336,
434 5 + 512 * sizeof (short) / sizeof (int) + 336,
435 5 + 512 * sizeof (short) / sizeof (int) + 1328,
436 5 + 512 * sizeof (short) / sizeof (int) + 336,
437 5 + 512 * sizeof (short) / sizeof (int) + 336,
438 5 + 512 * sizeof (short) / sizeof (int) + 336,
439 5 + 512 * sizeof (short) / sizeof (int) + 336,
440 5 + 512 * sizeof (short) / sizeof (int) + 336,
441 5 + 512 * sizeof (short) / sizeof (int) + 336,
442 5 + 512 * sizeof (short) / sizeof (int) + 336,
443 5 + 512 * sizeof (short) / sizeof (int) + 1344,
444 -1,
445 -1,
446 -1,
447 -1,
448 -1,
449 -1,
450 -1,
451 -1,
452 -1,
453 -1,
454 -1,
455 -1,
456 -1,
457 -1,
458 -1,
459 -1,
460 -1,
461 -1,
462 -1,
463 -1,
464 -1,
465 -1,
466 -1,
467 -1,
468 -1,
469 -1,
470 -1,
471 -1,
472 -1,
473 -1,
474 -1,
475 -1,
476 -1,
477 -1,
478 -1,
479 -1,
480 -1,
481 -1,
482 -1,
483 -1,
484 -1,
485 -1,
486 -1,
487 -1,
488 -1,
489 -1,
490 -1,
491 -1,
492 -1,
493 -1,
494 -1,
495 -1,
496 -1,
497 -1,
498 -1,
499 -1,
500 -1,
501 -1,
502 -1,
503 -1,
504 -1,
505 -1,
506 -1,
507 -1,
508 -1,
509 -1,
510 -1,
511 -1,
512 -1,
513 -1,
514 -1,
515 -1,
516 -1,
517 -1,
518 -1,
519 -1,
520 -1,
521 -1,
522 -1,
523 -1,
524 -1,
525 -1,
526 -1,
527 -1,
528 -1,
529 -1,
530 -1,
531 -1,
532 -1,
533 -1,
534 -1,
535 -1,
536 -1,
537 -1,
538 -1,
539 -1,
540 -1,
541 -1,
542 -1,
543 -1,
544 -1,
545 -1,
546 -1,
547 -1,
548 -1,
549 -1,
550 -1,
551 -1,
552 -1,
553 -1
554 },
555 {
556 0x00000000U, 0x03FF0000U, 0x07FFFFFEU, 0x07FFFFFEU,
557 0x00000000U, 0x04200400U, 0xFF7FFFFFU, 0xFF7FFFFFU,
558 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
559 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
560 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
561 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0003FFC3U, 0x0000501FU,
562 0x00000000U, 0x00000000U, 0x00000020U, 0xBCDF0000U,
563 0xFFFFD740U, 0xFFFFFFFBU, 0xFFFFFFFFU, 0xFFBFFFFFU,
564 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
565 0xFFFFFC03U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
566 0xFFFFFFFFU, 0xFFFEFFFFU, 0x027FFFFFU, 0xFFFFFFFFU,
567 0x000001FFU, 0x00000000U, 0xFFFF0000U, 0x000787FFU,
568 0x00000000U, 0xFFFFFFFFU, 0x000007FFU, 0xFFFEC3FFU,
569 0xFFFFFFFFU, 0xFFFFFFFFU, 0x002FFFFFU, 0x9FFFC060U,
570 0xFFFD0000U, 0x0000FFFFU, 0xFFFFE000U, 0xFFFFFFFFU,
571 0xFFFFFFFFU, 0x0002003FU, 0xFFFFFFFFU, 0x043007FFU,
572 0x043FFFFFU, 0x00000110U, 0x01FFFFFFU, 0xFFFF07FFU,
573 0x00007EFFU, 0xFFFFFFFFU, 0x000003FFU, 0x00000000U,
574 0xFFFFFFF0U, 0x23FFFFFFU, 0xFF010000U, 0xFFFEFFC3U,
575 0xFFF99FE1U, 0x23C5FDFFU, 0xB0004000U, 0x1003FFC3U,
576 0xFFF987E0U, 0x036DFDFFU, 0x5E000000U, 0x001CFFC0U,
577 0xFFFBBFE0U, 0x23EDFDFFU, 0x00010000U, 0x0200FFC3U,
578 0xFFF99FE0U, 0x23EDFDFFU, 0xB0000000U, 0x0002FFC3U,
579 0xD63DC7E8U, 0x03FFC718U, 0x00010000U, 0x0000FFC0U,
580 0xFFFDDFE0U, 0x23FFFDFFU, 0x27000000U, 0x0000FFC3U,
581 0xFFFDDFE1U, 0x23EFFDFFU, 0x60000000U, 0x0006FFC3U,
582 0xFFFDDFF0U, 0x27FFFFFFU, 0x80704000U, 0xFC00FFC3U,
583 0xFC7FFFE0U, 0x2FFBFFFFU, 0x0000007FU, 0x0000FFC0U,
584 0xFFFFFFFEU, 0x07FF7FFFU, 0x03FF7FBFU, 0x00000000U,
585 0xFFFFF7D6U, 0x200DFFAFU, 0xF3FF005FU, 0x00000000U,
586 0x00000001U, 0x000003FFU, 0xFFFFFEFFU, 0x00001FFFU,
587 0x00001F00U, 0x00000000U, 0x00000000U, 0x00000000U,
588 0xFFFFFFFFU, 0x800007FFU, 0x3C3F03FFU, 0xFFE1C062U,
589 0x03FF4003U, 0xFFFFFFFFU, 0xFFFF20BFU, 0xF7FFFFFFU,
590 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
591 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
592 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3D7F3DFFU, 0xFFFFFFFFU,
593 0xFFFF3DFFU, 0x7F3DFFFFU, 0xFF7FFF3DU, 0xFFFFFFFFU,
594 0xFF3DFFFFU, 0xFFFFFFFFU, 0x07FFFFFFU, 0x00000000U,
595 0x0000FFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3F3FFFFFU,
596 0xFFFFFFFEU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
597 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
598 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
599 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
600 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF9FFFU,
601 0x07FFFFFEU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x01FFC7FFU,
602 0x8003FFFFU, 0x0003FFFFU, 0x0003FFFFU, 0x0001DFFFU,
603 0xFFFFFFFFU, 0x000FFFFFU, 0x10800000U, 0x000003FFU,
604 0x03FF0000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x01FFFFFFU,
605 0xFFFFFF9FU, 0xFFFF05FFU, 0xFFFFFFFFU, 0x003FFFFFU,
606 0x7FFFFFFFU, 0x00000000U, 0xFFFFFFC0U, 0x001F3FFFU,
607 0xFFFFFFFFU, 0xFFFF0FFFU, 0x03FF03FFU, 0x00000000U,
608 0x007FFFFFU, 0xFFFFFFFFU, 0x001FFFFFU, 0x00000000U,
609 0x03FF03FFU, 0x00000080U, 0x00000000U, 0x00000000U,
610 0xFFFFFFE0U, 0x000FFFFFU, 0x03FF1FE0U, 0x00000000U,
611 0xFFFFFFF8U, 0xFFFFC001U, 0xFFFFFFFFU, 0x0000003FU,
612 0xFFFFFFFFU, 0x0000000FU, 0xFFFFE3FFU, 0x3FFFFFFFU,
613 0xFFFF07FFU, 0xE7FFFFFFU, 0x00000000U, 0x046FDE00U,
614 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
615 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000000U, 0x00000000U,
616 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
617 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
618 0x3F3FFFFFU, 0xFFFFFFFFU, 0xAAFF3F3FU, 0x3FFFFFFFU,
619 0xFFFFFFFFU, 0x5FDFFFFFU, 0x0FCF1FDCU, 0x1FDC1FFFU,
620 0x00000000U, 0x00000000U, 0x00000000U, 0x80020000U,
621 0x1FFF0000U, 0x00000000U, 0x00000000U, 0x00000000U,
622 0x3E2FFC84U, 0xF3FFBF50U, 0x000043E0U, 0xFFFFFFFFU,
623 0x000001FFU, 0x00000000U, 0x00000000U, 0x00000000U,
624 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
625 0xF0000000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000003FFU,
626 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
627 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
628 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
629 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000C781FU,
630 0xFFFFFFFFU, 0xFFFF20BFU, 0xFFFFFFFFU, 0x000080FFU,
631 0x007FFFFFU, 0x7F7F7F7FU, 0x7F7F7F7FU, 0x00000000U,
632 0x00000000U, 0x00008000U, 0x00000000U, 0x00000000U,
633 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
634 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
635 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
636 0x000000E0U, 0x1F3E03FEU, 0xFFFFFFFEU, 0xFFFFFFFFU,
637 0xE07FFFFFU, 0xFFFFFFFEU, 0xFFFFFFFFU, 0xF7FFFFFFU,
638 0xFFFFFFE0U, 0xFFFEFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
639 0x00007FFFU, 0xFFFFFFFFU, 0x00000000U, 0xFFFF0000U,
640 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
641 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
642 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
643 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
644 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
645 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
646 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
647 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000000U, 0x00000000U,
648 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
649 0x00001FFFU, 0x00000000U, 0xFFFF0000U, 0x3FFFFFFFU,
650 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
651 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
652 0xFFFF1FFFU, 0x00000FFFU, 0xFFFFFFFFU, 0x80007FFFU,
653 0x3FFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000FFFFU,
654 0xFF800000U, 0xFFFFFFFCU, 0xFFFFFFFFU, 0xFFFFFFFFU,
655 0xFFFFF9FFU, 0xFFFFFFFFU, 0x1FEB3FFFU, 0xFFFC0000U,
656 0xFFFFF7BBU, 0x00000007U, 0xFFFFFFFFU, 0x000FFFFFU,
657 0xFFFFFFFCU, 0x000FFFFFU, 0x03FF0000U, 0x68FC0000U,
658 0xFFFFFFFFU, 0xFFFF003FU, 0x0000007FU, 0x1FFFFFFFU,
659 0xFFFFFFF0U, 0x0007FFFFU, 0x03FF8000U, 0x7FFFFFDFU,
660 0xFFFFFFFFU, 0x000001FFU, 0x03FF0FF7U, 0xC47FFFFFU,
661 0xFFFFFFFFU, 0x3E62FFFFU, 0x38000005U, 0x001C07FFU,
662 0x007E7E7EU, 0xFFFF7F7FU, 0xF7FFFFFFU, 0xFFFF03FFU,
663 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FF0007U,
664 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
665 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
666 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
667 0xFFFFFFFFU, 0xFFFF000FU, 0xFFFFF87FU, 0x0FFFFFFFU,
668 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
669 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
670 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
671 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
672 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF3FFFU,
673 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FFFFFFU, 0x00000000U,
674 0xA0F8007FU, 0x5F7FFDFFU, 0xFFFFFFDBU, 0xFFFFFFFFU,
675 0xFFFFFFFFU, 0x0003FFFFU, 0xFFF80000U, 0xFFFFFFFFU,
676 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
677 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
678 0xFFFFFFFFU, 0x3FFFFFFFU, 0xFFFF0000U, 0xFFFFFFFFU,
679 0xFFFCFFFFU, 0xFFFFFFFFU, 0x000000FFU, 0x0FFF0000U,
680 0x00000000U, 0x00000000U, 0x00000000U, 0xFFDF0000U,
681 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x1FFFFFFFU,
682 0x03FF0000U, 0x07FFFFFEU, 0x07FFFFFEU, 0xFFFFFFC0U,
683 0xFFFFFFFFU, 0x7FFFFFFFU, 0x1CFCFCFCU, 0x00000000U,
684 0xFFFFEFFFU, 0xB7FFFF7FU, 0x3FFF3FFFU, 0x00000000U,
685 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x07FFFFFFU,
686 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0x001FFFFFU,
687 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
688 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
689 0x1FFFFFFFU, 0xFFFFFFFFU, 0x0001FFFFU, 0x00000000U,
690 0xFFFFFFFFU, 0xFFFFE000U, 0xFFFF07FFU, 0x003FFFFFU,
691 0x3FFFFFFFU, 0xFFFFFFFFU, 0x003EFF0FU, 0x00000000U,
692 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
693 0x3FFFFFFFU, 0xFFFF03FFU, 0xFF0FFFFFU, 0x0FFFFFFFU,
694 0xFFFFFFFFU, 0xFFFF00FFU, 0xFFFFFFFFU, 0xF7FF000FU,
695 0xFFB7F7FFU, 0x1BFBFFFBU, 0xFFFFFFFFU, 0x000FFFFFU,
696 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
697 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
698 0xFFFFFFFFU, 0x007FFFFFU, 0x003FFFFFU, 0x000000FFU,
699 0xFFFFFFBFU, 0x07FDFFFFU, 0x00000000U, 0x00000000U,
700 0xFFFFFD3FU, 0x91BFFFFFU, 0x003FFFFFU, 0x007FFFFFU,
701 0x7FFFFFFFU, 0x00000000U, 0x00000000U, 0x0037FFFFU,
702 0x003FFFFFU, 0x03FFFFFFU, 0x00000000U, 0x00000000U,
703 0xFFFFFFFFU, 0xC0FFFFFFU, 0x00000000U, 0x00000000U,
704 0xFEEF0001U, 0x003FFFFFU, 0x00000000U, 0x1FFFFFFFU,
705 0x1FFFFFFFU, 0x00000000U, 0xFFFFFEFFU, 0x0000001FU,
706 0xFFFFFFFFU, 0x003FFFFFU, 0x003FFFFFU, 0x0007FFFFU,
707 0x0003FFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
708 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000001FFU, 0x00000000U,
709 0xFFFFFFFFU, 0x0007FFFFU, 0xFFFFFFFFU, 0x0007FFFFU,
710 0xFFFFFFFFU, 0x03FF000FU, 0xFFFFFFFFU, 0xFFFF803FU,
711 0x0000003FU, 0x00000000U, 0x00000000U, 0x00000000U,
712 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
713 0xFFFFFFFFU, 0x000303FFU, 0x0000001CU, 0x00000000U,
714 0x1FFFFFFFU, 0xFFFF0080U, 0x0000003FU, 0xFFFF0000U,
715 0x00000003U, 0xFFFF0000U, 0x0000001FU, 0x007FFFFFU,
716 0xFFFFFFF8U, 0x00FFFFFFU, 0x00000000U, 0x0026FFC0U,
717 0xFFFFFFF8U, 0x0000FFFFU, 0xFFFF0000U, 0x03FF01FFU,
718 0xFFFFFFF8U, 0xFFC0007FU, 0xFFFF0090U, 0x0047FFFFU,
719 0xFFFFFFF8U, 0x0007FFFFU, 0x17FF001EU, 0x00000000U,
720 0xFFFBFFFFU, 0x80000FFFU, 0x00000001U, 0x00000000U,
721 0xBFFFBD7FU, 0xFFFF01FFU, 0x7FFFFFFFU, 0x03FF0000U,
722 0xFFF99FE0U, 0x23EDFDFFU, 0xE0010000U, 0x00000003U,
723 0xFFFF4BFFU, 0x00BFFFFFU, 0x000A0000U, 0x00000000U,
724 0xFFFFFFFFU, 0x001FFFFFU, 0x83FF0780U, 0x00000003U,
725 0xFFFFFFFFU, 0x0000FFFFU, 0x03FF00B0U, 0x00000000U,
726 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
727 0xFFFFFFFFU, 0x00007FFFU, 0x0F000000U, 0x00000000U,
728 0xFFFFFFFFU, 0x0000FFFFU, 0x03FF0010U, 0x00000000U,
729 0xFFFFFFFFU, 0x010007FFU, 0xFFFF03FFU, 0x0000000FU,
730 0x07FFFFFFU, 0x03FF0000U, 0x0000007FU, 0x00000000U,
731 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
732 0xFFFFFFFFU, 0x00000FFFU, 0x00000000U, 0x00000000U,
733 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x800003FFU,
734 0xFF6FF27FU, 0x8000FFFFU, 0x03FF0002U, 0x00000000U,
735 0x00000000U, 0xFFFFFCFFU, 0x0001FFFFU, 0x0000000AU,
736 0xFFFFF801U, 0x0407FFFFU, 0xF0010000U, 0xFFFFFFFFU,
737 0x200003FFU, 0xFFFF0000U, 0xFFFFFFFFU, 0x01FFFFFFU,
738 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
739 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0x03FF0001U,
740 0xFFFFFDFFU, 0x00007FFFU, 0x03FF0001U, 0xFFFC0000U,
741 0x0000FFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
742 0xFFFFFB7FU, 0x0001FFFFU, 0x03FF0040U, 0xFFFFFDBFU,
743 0x010003FFU, 0x000003FFU, 0x00000000U, 0x00000000U,
744 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
745 0x00000000U, 0x00000000U, 0x00000000U, 0x0007FFFFU,
746 0xFFFDFFF4U, 0x000FFFFFU, 0x03FF0000U, 0x00000000U,
747 0x00000000U, 0x00010000U, 0x00000000U, 0x00000000U,
748 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
749 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
750 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
751 0x03FFFFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
752 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00007FFFU,
753 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
754 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000000FU, 0x00000000U,
755 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
756 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
757 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
758 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
759 0xFFFF0000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0001FFFFU,
760 0xFFFFFFFFU, 0x0000FFFFU, 0x0000007EU, 0xFFFFFFFFU,
761 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
762 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
763 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
764 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
765 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
766 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
767 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x07FFFFFFU,
768 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000007FU, 0x00000000U,
769 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
770 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
771 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
772 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
773 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
774 0x3FFFFFFFU, 0x03FF0000U, 0x00000000U, 0x00000000U,
775 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
776 0xFFFFFFFFU, 0x01FFFFFFU, 0x7FFFFFFFU, 0xFFFF03FFU,
777 0xFFFFFFFFU, 0x7FFFFFFFU, 0xFFFF03FFU, 0x00003FFFU,
778 0xFFFFFFFFU, 0x0000FFFFU, 0x03FF000FU, 0xE0FFFFF8U,
779 0x0000FFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
780 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
781 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
782 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0x03FF1FFFU,
783 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
784 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU,
785 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
786 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000107FFU, 0x00000000U,
787 0xFFF80000U, 0x00000000U, 0x00000000U, 0x0000000BU,
788 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
789 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
790 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
791 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00FFFFFFU,
792 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
793 0xFFFFFFFFU, 0xFFFFFFFFU, 0x003FFFFFU, 0x80000000U,
794 0x000001FFU, 0x00000000U, 0x00000000U, 0x00000000U,
795 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
796 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
797 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
798 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
799 0x00000000U, 0x00000000U, 0x00000000U, 0x6FEF0000U,
800 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
801 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
802 0xFFFFFFFFU, 0x00040007U, 0x00270000U, 0xFFFF00F0U,
803 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
804 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
805 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0FFFFFFFU,
806 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
807 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
808 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x1FFF07FFU,
809 0x03FF01FFU, 0x00000000U, 0x00000000U, 0x00000000U,
810 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
811 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
812 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
813 0x00000000U, 0x00000000U, 0xFFC00000U, 0x03FFFFFFU,
814 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
815 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
816 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFDFFFFFU, 0xFFFFFFFFU,
817 0xDFFFFFFFU, 0xEBFFDE64U, 0xFFFFFFEFU, 0xFFFFFFFFU,
818 0xDFDFE7BFU, 0x7BFFFFFFU, 0xFFFDFC5FU, 0xFFFFFFFFU,
819 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
820 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
821 0xFFFFFFFFU, 0xFFFFFF3FU, 0xF7FFFFFDU, 0xF7FFFFFFU,
822 0xFFDFFFFFU, 0xFFDFFFFFU, 0xFFFF7FFFU, 0xFFFF7FFFU,
823 0xFFFFFDFFU, 0xFFFFFDFFU, 0xFFFFCFF7U, 0xFFFFFFFFU,
824 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
825 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
826 0x7FFFFFFFU, 0x000007E0U, 0x00000000U, 0x00000000U,
827 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
828 0x00000000U, 0xFFFF0000U, 0xFFFFFFFFU, 0x00003FFFU,
829 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
830 0xFFFFFFFFU, 0x3F801FFFU, 0x000043FFU, 0x00000000U,
831 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
832 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
833 0xFFFF0000U, 0x00003FFFU, 0xFFFFFFFFU, 0x03FF0FFFU,
834 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
835 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
836 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
837 0x00000000U, 0x00000000U, 0xFFFF0000U, 0x03FF0FFFU,
838 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
839 0x00000000U, 0x00000000U, 0xFFFF0000U, 0x07FF3FFFU,
840 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
841 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
842 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
843 0x00000000U, 0x00000000U, 0x00000000U, 0x7FFF6F7FU,
844 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
845 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000001FU, 0x00000000U,
846 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FF080FU, 0x00000000U,
847 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
848 0xFFFFFFEFU, 0x0AF7FE96U, 0xAA96EA84U, 0x5EF7F796U,
849 0x0FFFFBFFU, 0x0FFFFBEEU, 0x00000000U, 0x00000000U,
850 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
851 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
852 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
853 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
854 0xFFFF0000U, 0xFFFF1FFFU, 0xFFFF03FFU, 0xFFFF03FFU,
855 0x000007FFU, 0x00000020U, 0x00000000U, 0xFFFFFFC0U,
856 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
857 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
858 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
859 0x00000000U, 0x00000000U, 0x00000000U, 0x03FF0000U,
860 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
861 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000000U,
862 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
863 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
864 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
865 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
866 0xFFFFFFFFU, 0x03FFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
867 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
868 0x3FFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
869 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
870 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
871 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
872 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
873 0xFFFFFFFFU, 0xFFFF0003U, 0xFFFFFFFFU, 0xFFFFFFFFU,
874 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
875 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
876 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
877 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
878 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
879 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF0001U,
880 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3FFFFFFFU, 0x00000000U,
881 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
882 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
883 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
884 0x3FFFFFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
885 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
886 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
887 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
888 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
889 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
890 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF07FFU, 0xFFFFFFFFU,
891 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
892 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
893 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
894 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
895 0xFFFFFFFFU, 0x0000FFFFU, 0x00000000U, 0x00000000U
896 }
897};
diff --git a/gl/unictype/ctype_alpha.c b/gl/unictype/ctype_alpha.c
new file mode 100644
index 00000000..c422fec6
--- /dev/null
+++ b/gl/unictype/ctype_alpha.c
@@ -0,0 +1,32 @@
1/* ISO C <ctype.h> like properties of Unicode characters.
2 Copyright (C) 2002, 2006-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2002.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include "unictype.h"
22
23#include "bitmap.h"
24
25/* Define u_is_alpha table. */
26#include "ctype_alpha.h"
27
28bool
29uc_is_alpha (ucs4_t uc)
30{
31 return bitmap_lookup (&u_is_alpha, uc);
32}
diff --git a/gl/unictype/ctype_alpha.h b/gl/unictype/ctype_alpha.h
new file mode 100644
index 00000000..cd129cb9
--- /dev/null
+++ b/gl/unictype/ctype_alpha.h
@@ -0,0 +1,897 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* ISO C <ctype.h> like properties of Unicode characters. */
3/* Generated automatically by gen-uni-tables.c for Unicode 16.0.0. */
4
5/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
6
7 This file is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 This file is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19
20#define header_0 16
21#define header_2 9
22#define header_3 127
23#define header_4 15
24static const
25struct
26 {
27 int header[1];
28 int level1[4];
29 short level2[4 << 7];
30 unsigned int level3[85 << 4];
31 }
32u_is_alpha =
33{
34 { 4 },
35 {
36 5 * sizeof (int) / sizeof (short) + 0,
37 5 * sizeof (int) / sizeof (short) + 128,
38 5 * sizeof (int) / sizeof (short) + 256,
39 5 * sizeof (int) / sizeof (short) + 384
40 },
41 {
42 5 + 512 * sizeof (short) / sizeof (int) + 0,
43 5 + 512 * sizeof (short) / sizeof (int) + 16,
44 5 + 512 * sizeof (short) / sizeof (int) + 32,
45 5 + 512 * sizeof (short) / sizeof (int) + 48,
46 5 + 512 * sizeof (short) / sizeof (int) + 64,
47 5 + 512 * sizeof (short) / sizeof (int) + 80,
48 5 + 512 * sizeof (short) / sizeof (int) + 96,
49 5 + 512 * sizeof (short) / sizeof (int) + 112,
50 5 + 512 * sizeof (short) / sizeof (int) + 128,
51 5 + 512 * sizeof (short) / sizeof (int) + 144,
52 5 + 512 * sizeof (short) / sizeof (int) + 160,
53 5 + 512 * sizeof (short) / sizeof (int) + 176,
54 5 + 512 * sizeof (short) / sizeof (int) + 192,
55 5 + 512 * sizeof (short) / sizeof (int) + 208,
56 5 + 512 * sizeof (short) / sizeof (int) + 224,
57 5 + 512 * sizeof (short) / sizeof (int) + 240,
58 5 + 512 * sizeof (short) / sizeof (int) + 256,
59 -1,
60 5 + 512 * sizeof (short) / sizeof (int) + 272,
61 -1,
62 -1,
63 -1,
64 5 + 512 * sizeof (short) / sizeof (int) + 288,
65 5 + 512 * sizeof (short) / sizeof (int) + 304,
66 5 + 512 * sizeof (short) / sizeof (int) + 320,
67 -1,
68 5 + 512 * sizeof (short) / sizeof (int) + 336,
69 5 + 512 * sizeof (short) / sizeof (int) + 336,
70 5 + 512 * sizeof (short) / sizeof (int) + 336,
71 5 + 512 * sizeof (short) / sizeof (int) + 336,
72 5 + 512 * sizeof (short) / sizeof (int) + 336,
73 5 + 512 * sizeof (short) / sizeof (int) + 336,
74 5 + 512 * sizeof (short) / sizeof (int) + 336,
75 5 + 512 * sizeof (short) / sizeof (int) + 336,
76 5 + 512 * sizeof (short) / sizeof (int) + 336,
77 5 + 512 * sizeof (short) / sizeof (int) + 336,
78 5 + 512 * sizeof (short) / sizeof (int) + 336,
79 5 + 512 * sizeof (short) / sizeof (int) + 336,
80 5 + 512 * sizeof (short) / sizeof (int) + 352,
81 5 + 512 * sizeof (short) / sizeof (int) + 336,
82 5 + 512 * sizeof (short) / sizeof (int) + 336,
83 5 + 512 * sizeof (short) / sizeof (int) + 336,
84 5 + 512 * sizeof (short) / sizeof (int) + 336,
85 5 + 512 * sizeof (short) / sizeof (int) + 336,
86 5 + 512 * sizeof (short) / sizeof (int) + 336,
87 5 + 512 * sizeof (short) / sizeof (int) + 336,
88 5 + 512 * sizeof (short) / sizeof (int) + 336,
89 5 + 512 * sizeof (short) / sizeof (int) + 336,
90 5 + 512 * sizeof (short) / sizeof (int) + 336,
91 5 + 512 * sizeof (short) / sizeof (int) + 336,
92 5 + 512 * sizeof (short) / sizeof (int) + 336,
93 5 + 512 * sizeof (short) / sizeof (int) + 336,
94 5 + 512 * sizeof (short) / sizeof (int) + 336,
95 5 + 512 * sizeof (short) / sizeof (int) + 336,
96 5 + 512 * sizeof (short) / sizeof (int) + 336,
97 5 + 512 * sizeof (short) / sizeof (int) + 336,
98 5 + 512 * sizeof (short) / sizeof (int) + 336,
99 5 + 512 * sizeof (short) / sizeof (int) + 336,
100 5 + 512 * sizeof (short) / sizeof (int) + 336,
101 5 + 512 * sizeof (short) / sizeof (int) + 336,
102 5 + 512 * sizeof (short) / sizeof (int) + 336,
103 5 + 512 * sizeof (short) / sizeof (int) + 336,
104 5 + 512 * sizeof (short) / sizeof (int) + 336,
105 5 + 512 * sizeof (short) / sizeof (int) + 336,
106 5 + 512 * sizeof (short) / sizeof (int) + 336,
107 5 + 512 * sizeof (short) / sizeof (int) + 336,
108 5 + 512 * sizeof (short) / sizeof (int) + 336,
109 5 + 512 * sizeof (short) / sizeof (int) + 336,
110 5 + 512 * sizeof (short) / sizeof (int) + 336,
111 5 + 512 * sizeof (short) / sizeof (int) + 336,
112 5 + 512 * sizeof (short) / sizeof (int) + 336,
113 5 + 512 * sizeof (short) / sizeof (int) + 336,
114 5 + 512 * sizeof (short) / sizeof (int) + 336,
115 5 + 512 * sizeof (short) / sizeof (int) + 336,
116 5 + 512 * sizeof (short) / sizeof (int) + 336,
117 5 + 512 * sizeof (short) / sizeof (int) + 336,
118 5 + 512 * sizeof (short) / sizeof (int) + 336,
119 5 + 512 * sizeof (short) / sizeof (int) + 336,
120 5 + 512 * sizeof (short) / sizeof (int) + 336,
121 5 + 512 * sizeof (short) / sizeof (int) + 336,
122 5 + 512 * sizeof (short) / sizeof (int) + 336,
123 5 + 512 * sizeof (short) / sizeof (int) + 336,
124 5 + 512 * sizeof (short) / sizeof (int) + 368,
125 5 + 512 * sizeof (short) / sizeof (int) + 384,
126 5 + 512 * sizeof (short) / sizeof (int) + 400,
127 5 + 512 * sizeof (short) / sizeof (int) + 416,
128 5 + 512 * sizeof (short) / sizeof (int) + 336,
129 5 + 512 * sizeof (short) / sizeof (int) + 336,
130 5 + 512 * sizeof (short) / sizeof (int) + 336,
131 5 + 512 * sizeof (short) / sizeof (int) + 336,
132 5 + 512 * sizeof (short) / sizeof (int) + 336,
133 5 + 512 * sizeof (short) / sizeof (int) + 336,
134 5 + 512 * sizeof (short) / sizeof (int) + 336,
135 5 + 512 * sizeof (short) / sizeof (int) + 336,
136 5 + 512 * sizeof (short) / sizeof (int) + 336,
137 5 + 512 * sizeof (short) / sizeof (int) + 336,
138 5 + 512 * sizeof (short) / sizeof (int) + 336,
139 5 + 512 * sizeof (short) / sizeof (int) + 336,
140 5 + 512 * sizeof (short) / sizeof (int) + 336,
141 5 + 512 * sizeof (short) / sizeof (int) + 336,
142 5 + 512 * sizeof (short) / sizeof (int) + 336,
143 5 + 512 * sizeof (short) / sizeof (int) + 336,
144 5 + 512 * sizeof (short) / sizeof (int) + 336,
145 5 + 512 * sizeof (short) / sizeof (int) + 336,
146 5 + 512 * sizeof (short) / sizeof (int) + 336,
147 5 + 512 * sizeof (short) / sizeof (int) + 336,
148 5 + 512 * sizeof (short) / sizeof (int) + 336,
149 5 + 512 * sizeof (short) / sizeof (int) + 432,
150 -1,
151 -1,
152 -1,
153 -1,
154 -1,
155 -1,
156 -1,
157 -1,
158 -1,
159 -1,
160 -1,
161 -1,
162 -1,
163 -1,
164 -1,
165 -1,
166 5 + 512 * sizeof (short) / sizeof (int) + 448,
167 5 + 512 * sizeof (short) / sizeof (int) + 464,
168 5 + 512 * sizeof (short) / sizeof (int) + 480,
169 5 + 512 * sizeof (short) / sizeof (int) + 496,
170 5 + 512 * sizeof (short) / sizeof (int) + 512,
171 5 + 512 * sizeof (short) / sizeof (int) + 528,
172 5 + 512 * sizeof (short) / sizeof (int) + 544,
173 5 + 512 * sizeof (short) / sizeof (int) + 560,
174 5 + 512 * sizeof (short) / sizeof (int) + 576,
175 5 + 512 * sizeof (short) / sizeof (int) + 592,
176 5 + 512 * sizeof (short) / sizeof (int) + 608,
177 5 + 512 * sizeof (short) / sizeof (int) + 624,
178 5 + 512 * sizeof (short) / sizeof (int) + 640,
179 5 + 512 * sizeof (short) / sizeof (int) + 656,
180 5 + 512 * sizeof (short) / sizeof (int) + 672,
181 5 + 512 * sizeof (short) / sizeof (int) + 688,
182 5 + 512 * sizeof (short) / sizeof (int) + 704,
183 5 + 512 * sizeof (short) / sizeof (int) + 720,
184 5 + 512 * sizeof (short) / sizeof (int) + 736,
185 5 + 512 * sizeof (short) / sizeof (int) + 752,
186 5 + 512 * sizeof (short) / sizeof (int) + 336,
187 5 + 512 * sizeof (short) / sizeof (int) + 768,
188 5 + 512 * sizeof (short) / sizeof (int) + 784,
189 -1,
190 -1,
191 -1,
192 -1,
193 5 + 512 * sizeof (short) / sizeof (int) + 800,
194 5 + 512 * sizeof (short) / sizeof (int) + 336,
195 5 + 512 * sizeof (short) / sizeof (int) + 336,
196 5 + 512 * sizeof (short) / sizeof (int) + 816,
197 5 + 512 * sizeof (short) / sizeof (int) + 336,
198 5 + 512 * sizeof (short) / sizeof (int) + 336,
199 5 + 512 * sizeof (short) / sizeof (int) + 336,
200 5 + 512 * sizeof (short) / sizeof (int) + 336,
201 5 + 512 * sizeof (short) / sizeof (int) + 336,
202 5 + 512 * sizeof (short) / sizeof (int) + 336,
203 5 + 512 * sizeof (short) / sizeof (int) + 832,
204 5 + 512 * sizeof (short) / sizeof (int) + 336,
205 5 + 512 * sizeof (short) / sizeof (int) + 848,
206 -1,
207 -1,
208 -1,
209 -1,
210 -1,
211 -1,
212 -1,
213 -1,
214 -1,
215 -1,
216 -1,
217 -1,
218 5 + 512 * sizeof (short) / sizeof (int) + 864,
219 -1,
220 -1,
221 -1,
222 5 + 512 * sizeof (short) / sizeof (int) + 336,
223 5 + 512 * sizeof (short) / sizeof (int) + 880,
224 5 + 512 * sizeof (short) / sizeof (int) + 896,
225 5 + 512 * sizeof (short) / sizeof (int) + 912,
226 5 + 512 * sizeof (short) / sizeof (int) + 336,
227 5 + 512 * sizeof (short) / sizeof (int) + 336,
228 5 + 512 * sizeof (short) / sizeof (int) + 336,
229 5 + 512 * sizeof (short) / sizeof (int) + 336,
230 5 + 512 * sizeof (short) / sizeof (int) + 336,
231 5 + 512 * sizeof (short) / sizeof (int) + 336,
232 5 + 512 * sizeof (short) / sizeof (int) + 336,
233 5 + 512 * sizeof (short) / sizeof (int) + 336,
234 5 + 512 * sizeof (short) / sizeof (int) + 336,
235 5 + 512 * sizeof (short) / sizeof (int) + 336,
236 5 + 512 * sizeof (short) / sizeof (int) + 336,
237 5 + 512 * sizeof (short) / sizeof (int) + 928,
238 5 + 512 * sizeof (short) / sizeof (int) + 336,
239 5 + 512 * sizeof (short) / sizeof (int) + 336,
240 5 + 512 * sizeof (short) / sizeof (int) + 944,
241 -1,
242 -1,
243 -1,
244 -1,
245 -1,
246 -1,
247 -1,
248 -1,
249 -1,
250 -1,
251 -1,
252 -1,
253 -1,
254 -1,
255 -1,
256 -1,
257 5 + 512 * sizeof (short) / sizeof (int) + 960,
258 5 + 512 * sizeof (short) / sizeof (int) + 976,
259 5 + 512 * sizeof (short) / sizeof (int) + 992,
260 -1,
261 -1,
262 -1,
263 -1,
264 5 + 512 * sizeof (short) / sizeof (int) + 1008,
265 -1,
266 -1,
267 -1,
268 -1,
269 -1,
270 -1,
271 -1,
272 5 + 512 * sizeof (short) / sizeof (int) + 1024,
273 -1,
274 -1,
275 -1,
276 5 + 512 * sizeof (short) / sizeof (int) + 1040,
277 5 + 512 * sizeof (short) / sizeof (int) + 1056,
278 -1,
279 -1,
280 -1,
281 5 + 512 * sizeof (short) / sizeof (int) + 1072,
282 5 + 512 * sizeof (short) / sizeof (int) + 1088,
283 5 + 512 * sizeof (short) / sizeof (int) + 1104,
284 5 + 512 * sizeof (short) / sizeof (int) + 1120,
285 5 + 512 * sizeof (short) / sizeof (int) + 1136,
286 5 + 512 * sizeof (short) / sizeof (int) + 1152,
287 -1,
288 -1,
289 5 + 512 * sizeof (short) / sizeof (int) + 1168,
290 5 + 512 * sizeof (short) / sizeof (int) + 1184,
291 -1,
292 -1,
293 -1,
294 -1,
295 5 + 512 * sizeof (short) / sizeof (int) + 1200,
296 -1,
297 -1,
298 5 + 512 * sizeof (short) / sizeof (int) + 336,
299 5 + 512 * sizeof (short) / sizeof (int) + 336,
300 5 + 512 * sizeof (short) / sizeof (int) + 336,
301 5 + 512 * sizeof (short) / sizeof (int) + 336,
302 5 + 512 * sizeof (short) / sizeof (int) + 336,
303 5 + 512 * sizeof (short) / sizeof (int) + 336,
304 5 + 512 * sizeof (short) / sizeof (int) + 336,
305 5 + 512 * sizeof (short) / sizeof (int) + 336,
306 5 + 512 * sizeof (short) / sizeof (int) + 336,
307 5 + 512 * sizeof (short) / sizeof (int) + 336,
308 5 + 512 * sizeof (short) / sizeof (int) + 336,
309 5 + 512 * sizeof (short) / sizeof (int) + 336,
310 5 + 512 * sizeof (short) / sizeof (int) + 336,
311 5 + 512 * sizeof (short) / sizeof (int) + 336,
312 5 + 512 * sizeof (short) / sizeof (int) + 336,
313 5 + 512 * sizeof (short) / sizeof (int) + 336,
314 5 + 512 * sizeof (short) / sizeof (int) + 336,
315 5 + 512 * sizeof (short) / sizeof (int) + 336,
316 5 + 512 * sizeof (short) / sizeof (int) + 336,
317 5 + 512 * sizeof (short) / sizeof (int) + 336,
318 5 + 512 * sizeof (short) / sizeof (int) + 336,
319 5 + 512 * sizeof (short) / sizeof (int) + 336,
320 5 + 512 * sizeof (short) / sizeof (int) + 336,
321 5 + 512 * sizeof (short) / sizeof (int) + 336,
322 5 + 512 * sizeof (short) / sizeof (int) + 336,
323 5 + 512 * sizeof (short) / sizeof (int) + 336,
324 5 + 512 * sizeof (short) / sizeof (int) + 336,
325 5 + 512 * sizeof (short) / sizeof (int) + 336,
326 5 + 512 * sizeof (short) / sizeof (int) + 336,
327 5 + 512 * sizeof (short) / sizeof (int) + 336,
328 5 + 512 * sizeof (short) / sizeof (int) + 336,
329 5 + 512 * sizeof (short) / sizeof (int) + 336,
330 5 + 512 * sizeof (short) / sizeof (int) + 336,
331 5 + 512 * sizeof (short) / sizeof (int) + 336,
332 5 + 512 * sizeof (short) / sizeof (int) + 336,
333 5 + 512 * sizeof (short) / sizeof (int) + 336,
334 5 + 512 * sizeof (short) / sizeof (int) + 336,
335 5 + 512 * sizeof (short) / sizeof (int) + 336,
336 5 + 512 * sizeof (short) / sizeof (int) + 336,
337 5 + 512 * sizeof (short) / sizeof (int) + 336,
338 5 + 512 * sizeof (short) / sizeof (int) + 336,
339 5 + 512 * sizeof (short) / sizeof (int) + 336,
340 5 + 512 * sizeof (short) / sizeof (int) + 336,
341 5 + 512 * sizeof (short) / sizeof (int) + 336,
342 5 + 512 * sizeof (short) / sizeof (int) + 336,
343 5 + 512 * sizeof (short) / sizeof (int) + 336,
344 5 + 512 * sizeof (short) / sizeof (int) + 336,
345 5 + 512 * sizeof (short) / sizeof (int) + 336,
346 5 + 512 * sizeof (short) / sizeof (int) + 336,
347 5 + 512 * sizeof (short) / sizeof (int) + 336,
348 5 + 512 * sizeof (short) / sizeof (int) + 336,
349 5 + 512 * sizeof (short) / sizeof (int) + 336,
350 5 + 512 * sizeof (short) / sizeof (int) + 336,
351 5 + 512 * sizeof (short) / sizeof (int) + 336,
352 5 + 512 * sizeof (short) / sizeof (int) + 336,
353 5 + 512 * sizeof (short) / sizeof (int) + 336,
354 5 + 512 * sizeof (short) / sizeof (int) + 336,
355 5 + 512 * sizeof (short) / sizeof (int) + 336,
356 5 + 512 * sizeof (short) / sizeof (int) + 336,
357 5 + 512 * sizeof (short) / sizeof (int) + 336,
358 5 + 512 * sizeof (short) / sizeof (int) + 336,
359 5 + 512 * sizeof (short) / sizeof (int) + 336,
360 5 + 512 * sizeof (short) / sizeof (int) + 336,
361 5 + 512 * sizeof (short) / sizeof (int) + 336,
362 5 + 512 * sizeof (short) / sizeof (int) + 336,
363 5 + 512 * sizeof (short) / sizeof (int) + 336,
364 5 + 512 * sizeof (short) / sizeof (int) + 336,
365 5 + 512 * sizeof (short) / sizeof (int) + 336,
366 5 + 512 * sizeof (short) / sizeof (int) + 336,
367 5 + 512 * sizeof (short) / sizeof (int) + 336,
368 5 + 512 * sizeof (short) / sizeof (int) + 336,
369 5 + 512 * sizeof (short) / sizeof (int) + 336,
370 5 + 512 * sizeof (short) / sizeof (int) + 336,
371 5 + 512 * sizeof (short) / sizeof (int) + 336,
372 5 + 512 * sizeof (short) / sizeof (int) + 336,
373 5 + 512 * sizeof (short) / sizeof (int) + 336,
374 5 + 512 * sizeof (short) / sizeof (int) + 336,
375 5 + 512 * sizeof (short) / sizeof (int) + 336,
376 5 + 512 * sizeof (short) / sizeof (int) + 336,
377 5 + 512 * sizeof (short) / sizeof (int) + 336,
378 5 + 512 * sizeof (short) / sizeof (int) + 336,
379 5 + 512 * sizeof (short) / sizeof (int) + 336,
380 5 + 512 * sizeof (short) / sizeof (int) + 336,
381 5 + 512 * sizeof (short) / sizeof (int) + 1216,
382 5 + 512 * sizeof (short) / sizeof (int) + 336,
383 5 + 512 * sizeof (short) / sizeof (int) + 336,
384 5 + 512 * sizeof (short) / sizeof (int) + 336,
385 5 + 512 * sizeof (short) / sizeof (int) + 336,
386 5 + 512 * sizeof (short) / sizeof (int) + 336,
387 5 + 512 * sizeof (short) / sizeof (int) + 336,
388 5 + 512 * sizeof (short) / sizeof (int) + 336,
389 5 + 512 * sizeof (short) / sizeof (int) + 1232,
390 5 + 512 * sizeof (short) / sizeof (int) + 1248,
391 5 + 512 * sizeof (short) / sizeof (int) + 336,
392 5 + 512 * sizeof (short) / sizeof (int) + 336,
393 5 + 512 * sizeof (short) / sizeof (int) + 336,
394 5 + 512 * sizeof (short) / sizeof (int) + 336,
395 5 + 512 * sizeof (short) / sizeof (int) + 336,
396 5 + 512 * sizeof (short) / sizeof (int) + 336,
397 5 + 512 * sizeof (short) / sizeof (int) + 336,
398 5 + 512 * sizeof (short) / sizeof (int) + 336,
399 5 + 512 * sizeof (short) / sizeof (int) + 336,
400 5 + 512 * sizeof (short) / sizeof (int) + 336,
401 5 + 512 * sizeof (short) / sizeof (int) + 1264,
402 5 + 512 * sizeof (short) / sizeof (int) + 336,
403 5 + 512 * sizeof (short) / sizeof (int) + 336,
404 5 + 512 * sizeof (short) / sizeof (int) + 336,
405 5 + 512 * sizeof (short) / sizeof (int) + 336,
406 5 + 512 * sizeof (short) / sizeof (int) + 336,
407 5 + 512 * sizeof (short) / sizeof (int) + 336,
408 5 + 512 * sizeof (short) / sizeof (int) + 336,
409 5 + 512 * sizeof (short) / sizeof (int) + 336,
410 5 + 512 * sizeof (short) / sizeof (int) + 336,
411 5 + 512 * sizeof (short) / sizeof (int) + 336,
412 5 + 512 * sizeof (short) / sizeof (int) + 336,
413 5 + 512 * sizeof (short) / sizeof (int) + 336,
414 5 + 512 * sizeof (short) / sizeof (int) + 336,
415 5 + 512 * sizeof (short) / sizeof (int) + 1280,
416 5 + 512 * sizeof (short) / sizeof (int) + 336,
417 5 + 512 * sizeof (short) / sizeof (int) + 1296,
418 -1,
419 -1,
420 -1,
421 -1,
422 5 + 512 * sizeof (short) / sizeof (int) + 336,
423 5 + 512 * sizeof (short) / sizeof (int) + 1312,
424 -1,
425 -1,
426 5 + 512 * sizeof (short) / sizeof (int) + 336,
427 5 + 512 * sizeof (short) / sizeof (int) + 336,
428 5 + 512 * sizeof (short) / sizeof (int) + 336,
429 5 + 512 * sizeof (short) / sizeof (int) + 336,
430 5 + 512 * sizeof (short) / sizeof (int) + 336,
431 5 + 512 * sizeof (short) / sizeof (int) + 336,
432 5 + 512 * sizeof (short) / sizeof (int) + 336,
433 5 + 512 * sizeof (short) / sizeof (int) + 336,
434 5 + 512 * sizeof (short) / sizeof (int) + 336,
435 5 + 512 * sizeof (short) / sizeof (int) + 1328,
436 5 + 512 * sizeof (short) / sizeof (int) + 336,
437 5 + 512 * sizeof (short) / sizeof (int) + 336,
438 5 + 512 * sizeof (short) / sizeof (int) + 336,
439 5 + 512 * sizeof (short) / sizeof (int) + 336,
440 5 + 512 * sizeof (short) / sizeof (int) + 336,
441 5 + 512 * sizeof (short) / sizeof (int) + 336,
442 5 + 512 * sizeof (short) / sizeof (int) + 336,
443 5 + 512 * sizeof (short) / sizeof (int) + 1344,
444 -1,
445 -1,
446 -1,
447 -1,
448 -1,
449 -1,
450 -1,
451 -1,
452 -1,
453 -1,
454 -1,
455 -1,
456 -1,
457 -1,
458 -1,
459 -1,
460 -1,
461 -1,
462 -1,
463 -1,
464 -1,
465 -1,
466 -1,
467 -1,
468 -1,
469 -1,
470 -1,
471 -1,
472 -1,
473 -1,
474 -1,
475 -1,
476 -1,
477 -1,
478 -1,
479 -1,
480 -1,
481 -1,
482 -1,
483 -1,
484 -1,
485 -1,
486 -1,
487 -1,
488 -1,
489 -1,
490 -1,
491 -1,
492 -1,
493 -1,
494 -1,
495 -1,
496 -1,
497 -1,
498 -1,
499 -1,
500 -1,
501 -1,
502 -1,
503 -1,
504 -1,
505 -1,
506 -1,
507 -1,
508 -1,
509 -1,
510 -1,
511 -1,
512 -1,
513 -1,
514 -1,
515 -1,
516 -1,
517 -1,
518 -1,
519 -1,
520 -1,
521 -1,
522 -1,
523 -1,
524 -1,
525 -1,
526 -1,
527 -1,
528 -1,
529 -1,
530 -1,
531 -1,
532 -1,
533 -1,
534 -1,
535 -1,
536 -1,
537 -1,
538 -1,
539 -1,
540 -1,
541 -1,
542 -1,
543 -1,
544 -1,
545 -1,
546 -1,
547 -1,
548 -1,
549 -1,
550 -1,
551 -1,
552 -1,
553 -1
554 },
555 {
556 0x00000000U, 0x00000000U, 0x07FFFFFEU, 0x07FFFFFEU,
557 0x00000000U, 0x04200400U, 0xFF7FFFFFU, 0xFF7FFFFFU,
558 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
559 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
560 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
561 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0003FFC3U, 0x0000501FU,
562 0x00000000U, 0x00000000U, 0x00000020U, 0xBCDF0000U,
563 0xFFFFD740U, 0xFFFFFFFBU, 0xFFFFFFFFU, 0xFFBFFFFFU,
564 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
565 0xFFFFFC03U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
566 0xFFFFFFFFU, 0xFFFEFFFFU, 0x027FFFFFU, 0xFFFFFFFFU,
567 0x000001FFU, 0x00000000U, 0xFFFF0000U, 0x000787FFU,
568 0x00000000U, 0xFFFFFFFFU, 0x000007FFU, 0xFFFEC3FFU,
569 0xFFFFFFFFU, 0xFFFFFFFFU, 0x002FFFFFU, 0x9FFFC060U,
570 0xFFFD0000U, 0x0000FFFFU, 0xFFFFE000U, 0xFFFFFFFFU,
571 0xFFFFFFFFU, 0x0002003FU, 0xFFFFFFFFU, 0x043007FFU,
572 0x043FFFFFU, 0x00000110U, 0x01FFFFFFU, 0xFFFF07FFU,
573 0x00007EFFU, 0xFFFFFFFFU, 0x000003FFU, 0x00000000U,
574 0xFFFFFFF0U, 0x23FFFFFFU, 0xFF010000U, 0xFFFEFFC3U,
575 0xFFF99FE1U, 0x23C5FDFFU, 0xB0004000U, 0x1003FFC3U,
576 0xFFF987E0U, 0x036DFDFFU, 0x5E000000U, 0x001CFFC0U,
577 0xFFFBBFE0U, 0x23EDFDFFU, 0x00010000U, 0x0200FFC3U,
578 0xFFF99FE0U, 0x23EDFDFFU, 0xB0000000U, 0x0002FFC3U,
579 0xD63DC7E8U, 0x03FFC718U, 0x00010000U, 0x0000FFC0U,
580 0xFFFDDFE0U, 0x23FFFDFFU, 0x27000000U, 0x0000FFC3U,
581 0xFFFDDFE1U, 0x23EFFDFFU, 0x60000000U, 0x0006FFC3U,
582 0xFFFDDFF0U, 0x27FFFFFFU, 0x80704000U, 0xFC00FFC3U,
583 0xFC7FFFE0U, 0x2FFBFFFFU, 0x0000007FU, 0x0000FFC0U,
584 0xFFFFFFFEU, 0x07FF7FFFU, 0x03FF7FBFU, 0x00000000U,
585 0xFFFFF7D6U, 0x200DFFAFU, 0xF3FF005FU, 0x00000000U,
586 0x00000001U, 0x000003FFU, 0xFFFFFEFFU, 0x00001FFFU,
587 0x00001F00U, 0x00000000U, 0x00000000U, 0x00000000U,
588 0xFFFFFFFFU, 0x800007FFU, 0x3C3F03FFU, 0xFFE1C062U,
589 0x03FF4003U, 0xFFFFFFFFU, 0xFFFF20BFU, 0xF7FFFFFFU,
590 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
591 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
592 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3D7F3DFFU, 0xFFFFFFFFU,
593 0xFFFF3DFFU, 0x7F3DFFFFU, 0xFF7FFF3DU, 0xFFFFFFFFU,
594 0xFF3DFFFFU, 0xFFFFFFFFU, 0x07FFFFFFU, 0x00000000U,
595 0x0000FFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3F3FFFFFU,
596 0xFFFFFFFEU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
597 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
598 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
599 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
600 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF9FFFU,
601 0x07FFFFFEU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x01FFC7FFU,
602 0x8003FFFFU, 0x0003FFFFU, 0x0003FFFFU, 0x0001DFFFU,
603 0xFFFFFFFFU, 0x000FFFFFU, 0x10800000U, 0x000003FFU,
604 0x03FF0000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x01FFFFFFU,
605 0xFFFFFF9FU, 0xFFFF05FFU, 0xFFFFFFFFU, 0x003FFFFFU,
606 0x7FFFFFFFU, 0x00000000U, 0xFFFFFFC0U, 0x001F3FFFU,
607 0xFFFFFFFFU, 0xFFFF0FFFU, 0x03FF03FFU, 0x00000000U,
608 0x007FFFFFU, 0xFFFFFFFFU, 0x001FFFFFU, 0x00000000U,
609 0x03FF03FFU, 0x00000080U, 0x00000000U, 0x00000000U,
610 0xFFFFFFE0U, 0x000FFFFFU, 0x03FF1FE0U, 0x00000000U,
611 0xFFFFFFF8U, 0xFFFFC001U, 0xFFFFFFFFU, 0x0000003FU,
612 0xFFFFFFFFU, 0x0000000FU, 0xFFFFE3FFU, 0x3FFFFFFFU,
613 0xFFFF07FFU, 0xE7FFFFFFU, 0x00000000U, 0x046FDE00U,
614 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
615 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000000U, 0x00000000U,
616 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
617 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
618 0x3F3FFFFFU, 0xFFFFFFFFU, 0xAAFF3F3FU, 0x3FFFFFFFU,
619 0xFFFFFFFFU, 0x5FDFFFFFU, 0x0FCF1FDCU, 0x1FDC1FFFU,
620 0x00000000U, 0x00000000U, 0x00000000U, 0x80020000U,
621 0x1FFF0000U, 0x00000000U, 0x00000000U, 0x00000000U,
622 0x3E2FFC84U, 0xF3FFBF50U, 0x000043E0U, 0xFFFFFFFFU,
623 0x000001FFU, 0x00000000U, 0x00000000U, 0x00000000U,
624 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
625 0xF0000000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000003FFU,
626 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
627 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
628 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
629 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000C781FU,
630 0xFFFFFFFFU, 0xFFFF20BFU, 0xFFFFFFFFU, 0x000080FFU,
631 0x007FFFFFU, 0x7F7F7F7FU, 0x7F7F7F7FU, 0x00000000U,
632 0x00000000U, 0x00008000U, 0x00000000U, 0x00000000U,
633 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
634 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
635 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
636 0x000000E0U, 0x1F3E03FEU, 0xFFFFFFFEU, 0xFFFFFFFFU,
637 0xE07FFFFFU, 0xFFFFFFFEU, 0xFFFFFFFFU, 0xF7FFFFFFU,
638 0xFFFFFFE0U, 0xFFFEFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
639 0x00007FFFU, 0xFFFFFFFFU, 0x00000000U, 0xFFFF0000U,
640 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
641 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
642 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
643 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
644 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
645 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
646 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
647 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000000U, 0x00000000U,
648 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
649 0x00001FFFU, 0x00000000U, 0xFFFF0000U, 0x3FFFFFFFU,
650 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
651 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
652 0xFFFF1FFFU, 0x00000FFFU, 0xFFFFFFFFU, 0x80007FFFU,
653 0x3FFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000FFFFU,
654 0xFF800000U, 0xFFFFFFFCU, 0xFFFFFFFFU, 0xFFFFFFFFU,
655 0xFFFFF9FFU, 0xFFFFFFFFU, 0x1FEB3FFFU, 0xFFFC0000U,
656 0xFFFFF7BBU, 0x00000007U, 0xFFFFFFFFU, 0x000FFFFFU,
657 0xFFFFFFFCU, 0x000FFFFFU, 0x03FF0000U, 0x68FC0000U,
658 0xFFFFFFFFU, 0xFFFF003FU, 0x0000007FU, 0x1FFFFFFFU,
659 0xFFFFFFF0U, 0x0007FFFFU, 0x03FF8000U, 0x7FFFFFDFU,
660 0xFFFFFFFFU, 0x000001FFU, 0x03FF0FF7U, 0xC47FFFFFU,
661 0xFFFFFFFFU, 0x3E62FFFFU, 0x38000005U, 0x001C07FFU,
662 0x007E7E7EU, 0xFFFF7F7FU, 0xF7FFFFFFU, 0xFFFF03FFU,
663 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FF0007U,
664 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
665 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
666 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
667 0xFFFFFFFFU, 0xFFFF000FU, 0xFFFFF87FU, 0x0FFFFFFFU,
668 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
669 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
670 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
671 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
672 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF3FFFU,
673 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FFFFFFU, 0x00000000U,
674 0xA0F8007FU, 0x5F7FFDFFU, 0xFFFFFFDBU, 0xFFFFFFFFU,
675 0xFFFFFFFFU, 0x0003FFFFU, 0xFFF80000U, 0xFFFFFFFFU,
676 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
677 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
678 0xFFFFFFFFU, 0x3FFFFFFFU, 0xFFFF0000U, 0xFFFFFFFFU,
679 0xFFFCFFFFU, 0xFFFFFFFFU, 0x000000FFU, 0x0FFF0000U,
680 0x00000000U, 0x00000000U, 0x00000000U, 0xFFDF0000U,
681 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x1FFFFFFFU,
682 0x03FF0000U, 0x07FFFFFEU, 0x07FFFFFEU, 0xFFFFFFC0U,
683 0xFFFFFFFFU, 0x7FFFFFFFU, 0x1CFCFCFCU, 0x00000000U,
684 0xFFFFEFFFU, 0xB7FFFF7FU, 0x3FFF3FFFU, 0x00000000U,
685 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x07FFFFFFU,
686 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0x001FFFFFU,
687 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
688 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
689 0x1FFFFFFFU, 0xFFFFFFFFU, 0x0001FFFFU, 0x00000000U,
690 0xFFFFFFFFU, 0xFFFFE000U, 0xFFFF07FFU, 0x003FFFFFU,
691 0x3FFFFFFFU, 0xFFFFFFFFU, 0x003EFF0FU, 0x00000000U,
692 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
693 0x3FFFFFFFU, 0xFFFF03FFU, 0xFF0FFFFFU, 0x0FFFFFFFU,
694 0xFFFFFFFFU, 0xFFFF00FFU, 0xFFFFFFFFU, 0xF7FF000FU,
695 0xFFB7F7FFU, 0x1BFBFFFBU, 0xFFFFFFFFU, 0x000FFFFFU,
696 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
697 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
698 0xFFFFFFFFU, 0x007FFFFFU, 0x003FFFFFU, 0x000000FFU,
699 0xFFFFFFBFU, 0x07FDFFFFU, 0x00000000U, 0x00000000U,
700 0xFFFFFD3FU, 0x91BFFFFFU, 0x003FFFFFU, 0x007FFFFFU,
701 0x7FFFFFFFU, 0x00000000U, 0x00000000U, 0x0037FFFFU,
702 0x003FFFFFU, 0x03FFFFFFU, 0x00000000U, 0x00000000U,
703 0xFFFFFFFFU, 0xC0FFFFFFU, 0x00000000U, 0x00000000U,
704 0xFEEF0001U, 0x003FFFFFU, 0x00000000U, 0x1FFFFFFFU,
705 0x1FFFFFFFU, 0x00000000U, 0xFFFFFEFFU, 0x0000001FU,
706 0xFFFFFFFFU, 0x003FFFFFU, 0x003FFFFFU, 0x0007FFFFU,
707 0x0003FFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
708 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000001FFU, 0x00000000U,
709 0xFFFFFFFFU, 0x0007FFFFU, 0xFFFFFFFFU, 0x0007FFFFU,
710 0xFFFFFFFFU, 0x03FF000FU, 0xFFFFFFFFU, 0xFFFF803FU,
711 0x0000003FU, 0x00000000U, 0x00000000U, 0x00000000U,
712 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
713 0xFFFFFFFFU, 0x000303FFU, 0x0000001CU, 0x00000000U,
714 0x1FFFFFFFU, 0xFFFF0080U, 0x0000003FU, 0xFFFF0000U,
715 0x00000003U, 0xFFFF0000U, 0x0000001FU, 0x007FFFFFU,
716 0xFFFFFFF8U, 0x00FFFFFFU, 0x00000000U, 0x0026FFC0U,
717 0xFFFFFFF8U, 0x0000FFFFU, 0xFFFF0000U, 0x03FF01FFU,
718 0xFFFFFFF8U, 0xFFC0007FU, 0xFFFF0090U, 0x0047FFFFU,
719 0xFFFFFFF8U, 0x0007FFFFU, 0x17FF001EU, 0x00000000U,
720 0xFFFBFFFFU, 0x80000FFFU, 0x00000001U, 0x00000000U,
721 0xBFFFBD7FU, 0xFFFF01FFU, 0x7FFFFFFFU, 0x03FF0000U,
722 0xFFF99FE0U, 0x23EDFDFFU, 0xE0010000U, 0x00000003U,
723 0xFFFF4BFFU, 0x00BFFFFFU, 0x000A0000U, 0x00000000U,
724 0xFFFFFFFFU, 0x001FFFFFU, 0x83FF0780U, 0x00000003U,
725 0xFFFFFFFFU, 0x0000FFFFU, 0x03FF00B0U, 0x00000000U,
726 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
727 0xFFFFFFFFU, 0x00007FFFU, 0x0F000000U, 0x00000000U,
728 0xFFFFFFFFU, 0x0000FFFFU, 0x03FF0010U, 0x00000000U,
729 0xFFFFFFFFU, 0x010007FFU, 0xFFFF03FFU, 0x0000000FU,
730 0x07FFFFFFU, 0x03FF0000U, 0x0000007FU, 0x00000000U,
731 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
732 0xFFFFFFFFU, 0x00000FFFU, 0x00000000U, 0x00000000U,
733 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x800003FFU,
734 0xFF6FF27FU, 0x8000FFFFU, 0x03FF0002U, 0x00000000U,
735 0x00000000U, 0xFFFFFCFFU, 0x0001FFFFU, 0x0000000AU,
736 0xFFFFF801U, 0x0407FFFFU, 0xF0010000U, 0xFFFFFFFFU,
737 0x200003FFU, 0xFFFF0000U, 0xFFFFFFFFU, 0x01FFFFFFU,
738 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
739 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0x03FF0001U,
740 0xFFFFFDFFU, 0x00007FFFU, 0x03FF0001U, 0xFFFC0000U,
741 0x0000FFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
742 0xFFFFFB7FU, 0x0001FFFFU, 0x03FF0040U, 0xFFFFFDBFU,
743 0x010003FFU, 0x000003FFU, 0x00000000U, 0x00000000U,
744 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
745 0x00000000U, 0x00000000U, 0x00000000U, 0x0007FFFFU,
746 0xFFFDFFF4U, 0x000FFFFFU, 0x03FF0000U, 0x00000000U,
747 0x00000000U, 0x00010000U, 0x00000000U, 0x00000000U,
748 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
749 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
750 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
751 0x03FFFFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
752 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00007FFFU,
753 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
754 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000000FU, 0x00000000U,
755 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
756 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
757 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
758 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
759 0xFFFF0000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0001FFFFU,
760 0xFFFFFFFFU, 0x0000FFFFU, 0x0000007EU, 0xFFFFFFFFU,
761 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
762 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
763 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
764 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
765 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
766 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
767 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x07FFFFFFU,
768 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000007FU, 0x00000000U,
769 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
770 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
771 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
772 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
773 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
774 0x3FFFFFFFU, 0x03FF0000U, 0x00000000U, 0x00000000U,
775 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
776 0xFFFFFFFFU, 0x01FFFFFFU, 0x7FFFFFFFU, 0xFFFF03FFU,
777 0xFFFFFFFFU, 0x7FFFFFFFU, 0xFFFF03FFU, 0x00003FFFU,
778 0xFFFFFFFFU, 0x0000FFFFU, 0x03FF000FU, 0xE0FFFFF8U,
779 0x0000FFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
780 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
781 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
782 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0x03FF1FFFU,
783 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
784 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU,
785 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
786 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000107FFU, 0x00000000U,
787 0xFFF80000U, 0x00000000U, 0x00000000U, 0x0000000BU,
788 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
789 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
790 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
791 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00FFFFFFU,
792 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
793 0xFFFFFFFFU, 0xFFFFFFFFU, 0x003FFFFFU, 0x80000000U,
794 0x000001FFU, 0x00000000U, 0x00000000U, 0x00000000U,
795 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
796 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
797 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
798 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
799 0x00000000U, 0x00000000U, 0x00000000U, 0x6FEF0000U,
800 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
801 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
802 0xFFFFFFFFU, 0x00040007U, 0x00270000U, 0xFFFF00F0U,
803 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
804 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
805 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0FFFFFFFU,
806 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
807 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
808 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x1FFF07FFU,
809 0x03FF01FFU, 0x00000000U, 0x00000000U, 0x00000000U,
810 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
811 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
812 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
813 0x00000000U, 0x00000000U, 0xFFC00000U, 0x03FFFFFFU,
814 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
815 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
816 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFDFFFFFU, 0xFFFFFFFFU,
817 0xDFFFFFFFU, 0xEBFFDE64U, 0xFFFFFFEFU, 0xFFFFFFFFU,
818 0xDFDFE7BFU, 0x7BFFFFFFU, 0xFFFDFC5FU, 0xFFFFFFFFU,
819 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
820 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
821 0xFFFFFFFFU, 0xFFFFFF3FU, 0xF7FFFFFDU, 0xF7FFFFFFU,
822 0xFFDFFFFFU, 0xFFDFFFFFU, 0xFFFF7FFFU, 0xFFFF7FFFU,
823 0xFFFFFDFFU, 0xFFFFFDFFU, 0xFFFFCFF7U, 0xFFFFFFFFU,
824 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
825 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
826 0x7FFFFFFFU, 0x000007E0U, 0x00000000U, 0x00000000U,
827 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
828 0x00000000U, 0xFFFF0000U, 0xFFFFFFFFU, 0x00003FFFU,
829 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
830 0xFFFFFFFFU, 0x3F801FFFU, 0x000043FFU, 0x00000000U,
831 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
832 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
833 0xFFFF0000U, 0x00003FFFU, 0xFFFFFFFFU, 0x03FF0FFFU,
834 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
835 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
836 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
837 0x00000000U, 0x00000000U, 0xFFFF0000U, 0x03FF0FFFU,
838 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
839 0x00000000U, 0x00000000U, 0xFFFF0000U, 0x07FF3FFFU,
840 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
841 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
842 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
843 0x00000000U, 0x00000000U, 0x00000000U, 0x7FFF6F7FU,
844 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
845 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000001FU, 0x00000000U,
846 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FF080FU, 0x00000000U,
847 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
848 0xFFFFFFEFU, 0x0AF7FE96U, 0xAA96EA84U, 0x5EF7F796U,
849 0x0FFFFBFFU, 0x0FFFFBEEU, 0x00000000U, 0x00000000U,
850 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
851 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
852 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
853 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
854 0xFFFF0000U, 0xFFFF1FFFU, 0xFFFF03FFU, 0xFFFF03FFU,
855 0x000007FFU, 0x00000020U, 0x00000000U, 0xFFFFFFC0U,
856 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
857 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
858 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
859 0x00000000U, 0x00000000U, 0x00000000U, 0x03FF0000U,
860 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
861 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000000U,
862 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
863 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
864 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
865 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
866 0xFFFFFFFFU, 0x03FFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
867 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
868 0x3FFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
869 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
870 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
871 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
872 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
873 0xFFFFFFFFU, 0xFFFF0003U, 0xFFFFFFFFU, 0xFFFFFFFFU,
874 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
875 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
876 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
877 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
878 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
879 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF0001U,
880 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3FFFFFFFU, 0x00000000U,
881 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
882 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
883 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
884 0x3FFFFFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
885 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
886 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
887 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
888 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
889 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
890 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF07FFU, 0xFFFFFFFFU,
891 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
892 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
893 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
894 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
895 0xFFFFFFFFU, 0x0000FFFFU, 0x00000000U, 0x00000000U
896 }
897};
diff --git a/gl/unictype/ctype_blank.c b/gl/unictype/ctype_blank.c
new file mode 100644
index 00000000..25a08013
--- /dev/null
+++ b/gl/unictype/ctype_blank.c
@@ -0,0 +1,32 @@
1/* ISO C <ctype.h> like properties of Unicode characters.
2 Copyright (C) 2002, 2006-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2002.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include "unictype.h"
22
23#include "bitmap.h"
24
25/* Define u_is_blank table. */
26#include "ctype_blank.h"
27
28bool
29uc_is_blank (ucs4_t uc)
30{
31 return bitmap_lookup (&u_is_blank, uc);
32}
diff --git a/gl/unictype/ctype_blank.h b/gl/unictype/ctype_blank.h
new file mode 100644
index 00000000..23fac0f3
--- /dev/null
+++ b/gl/unictype/ctype_blank.h
@@ -0,0 +1,184 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* ISO C <ctype.h> like properties of Unicode characters. */
3/* Generated automatically by gen-uni-tables.c for Unicode 16.0.0. */
4
5/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
6
7 This file is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 This file is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19
20#define header_0 16
21#define header_2 9
22#define header_3 127
23#define header_4 15
24static const
25struct
26 {
27 int header[1];
28 int level1[1];
29 short level2[1 << 7];
30 unsigned int level3[4 << 4];
31 }
32u_is_blank =
33{
34 { 1 },
35 { 2 * sizeof (int) / sizeof (short) + 0 },
36 {
37 2 + 128 * sizeof (short) / sizeof (int) + 0,
38 -1,
39 -1,
40 -1,
41 -1,
42 -1,
43 -1,
44 -1,
45 -1,
46 -1,
47 -1,
48 2 + 128 * sizeof (short) / sizeof (int) + 16,
49 -1,
50 -1,
51 -1,
52 -1,
53 2 + 128 * sizeof (short) / sizeof (int) + 32,
54 -1,
55 -1,
56 -1,
57 -1,
58 -1,
59 -1,
60 -1,
61 2 + 128 * sizeof (short) / sizeof (int) + 48,
62 -1,
63 -1,
64 -1,
65 -1,
66 -1,
67 -1,
68 -1,
69 -1,
70 -1,
71 -1,
72 -1,
73 -1,
74 -1,
75 -1,
76 -1,
77 -1,
78 -1,
79 -1,
80 -1,
81 -1,
82 -1,
83 -1,
84 -1,
85 -1,
86 -1,
87 -1,
88 -1,
89 -1,
90 -1,
91 -1,
92 -1,
93 -1,
94 -1,
95 -1,
96 -1,
97 -1,
98 -1,
99 -1,
100 -1,
101 -1,
102 -1,
103 -1,
104 -1,
105 -1,
106 -1,
107 -1,
108 -1,
109 -1,
110 -1,
111 -1,
112 -1,
113 -1,
114 -1,
115 -1,
116 -1,
117 -1,
118 -1,
119 -1,
120 -1,
121 -1,
122 -1,
123 -1,
124 -1,
125 -1,
126 -1,
127 -1,
128 -1,
129 -1,
130 -1,
131 -1,
132 -1,
133 -1,
134 -1,
135 -1,
136 -1,
137 -1,
138 -1,
139 -1,
140 -1,
141 -1,
142 -1,
143 -1,
144 -1,
145 -1,
146 -1,
147 -1,
148 -1,
149 -1,
150 -1,
151 -1,
152 -1,
153 -1,
154 -1,
155 -1,
156 -1,
157 -1,
158 -1,
159 -1,
160 -1,
161 -1,
162 -1,
163 -1,
164 -1
165 },
166 {
167 0x00000200U, 0x00000001U, 0x00000000U, 0x00000000U,
168 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
169 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
170 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
171 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
172 0x00000001U, 0x00000000U, 0x00000000U, 0x00000000U,
173 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
174 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
175 0x0000077FU, 0x00000000U, 0x80000000U, 0x00000000U,
176 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
177 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
178 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
179 0x00000001U, 0x00000000U, 0x00000000U, 0x00000000U,
180 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
181 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
182 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U
183 }
184};
diff --git a/gl/unictype/ctype_cntrl.c b/gl/unictype/ctype_cntrl.c
new file mode 100644
index 00000000..eb7467dd
--- /dev/null
+++ b/gl/unictype/ctype_cntrl.c
@@ -0,0 +1,32 @@
1/* ISO C <ctype.h> like properties of Unicode characters.
2 Copyright (C) 2002, 2006-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2002.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include "unictype.h"
22
23#include "bitmap.h"
24
25/* Define u_is_cntrl table. */
26#include "ctype_cntrl.h"
27
28bool
29uc_is_cntrl (ucs4_t uc)
30{
31 return bitmap_lookup (&u_is_cntrl, uc);
32}
diff --git a/gl/unictype/ctype_cntrl.h b/gl/unictype/ctype_cntrl.h
new file mode 100644
index 00000000..58df7e76
--- /dev/null
+++ b/gl/unictype/ctype_cntrl.h
@@ -0,0 +1,176 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* ISO C <ctype.h> like properties of Unicode characters. */
3/* Generated automatically by gen-uni-tables.c for Unicode 16.0.0. */
4
5/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
6
7 This file is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 This file is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19
20#define header_0 16
21#define header_2 9
22#define header_3 127
23#define header_4 15
24static const
25struct
26 {
27 int header[1];
28 int level1[1];
29 short level2[1 << 7];
30 unsigned int level3[2 << 4];
31 }
32u_is_cntrl =
33{
34 { 1 },
35 { 2 * sizeof (int) / sizeof (short) + 0 },
36 {
37 2 + 128 * sizeof (short) / sizeof (int) + 0,
38 -1,
39 -1,
40 -1,
41 -1,
42 -1,
43 -1,
44 -1,
45 -1,
46 -1,
47 -1,
48 -1,
49 -1,
50 -1,
51 -1,
52 -1,
53 2 + 128 * sizeof (short) / sizeof (int) + 16,
54 -1,
55 -1,
56 -1,
57 -1,
58 -1,
59 -1,
60 -1,
61 -1,
62 -1,
63 -1,
64 -1,
65 -1,
66 -1,
67 -1,
68 -1,
69 -1,
70 -1,
71 -1,
72 -1,
73 -1,
74 -1,
75 -1,
76 -1,
77 -1,
78 -1,
79 -1,
80 -1,
81 -1,
82 -1,
83 -1,
84 -1,
85 -1,
86 -1,
87 -1,
88 -1,
89 -1,
90 -1,
91 -1,
92 -1,
93 -1,
94 -1,
95 -1,
96 -1,
97 -1,
98 -1,
99 -1,
100 -1,
101 -1,
102 -1,
103 -1,
104 -1,
105 -1,
106 -1,
107 -1,
108 -1,
109 -1,
110 -1,
111 -1,
112 -1,
113 -1,
114 -1,
115 -1,
116 -1,
117 -1,
118 -1,
119 -1,
120 -1,
121 -1,
122 -1,
123 -1,
124 -1,
125 -1,
126 -1,
127 -1,
128 -1,
129 -1,
130 -1,
131 -1,
132 -1,
133 -1,
134 -1,
135 -1,
136 -1,
137 -1,
138 -1,
139 -1,
140 -1,
141 -1,
142 -1,
143 -1,
144 -1,
145 -1,
146 -1,
147 -1,
148 -1,
149 -1,
150 -1,
151 -1,
152 -1,
153 -1,
154 -1,
155 -1,
156 -1,
157 -1,
158 -1,
159 -1,
160 -1,
161 -1,
162 -1,
163 -1,
164 -1
165 },
166 {
167 0xFFFFFFFFU, 0x00000000U, 0x00000000U, 0x80000000U,
168 0xFFFFFFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
169 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
170 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
171 0x00000000U, 0x00000300U, 0x00000000U, 0x00000000U,
172 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
173 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
174 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U
175 }
176};
diff --git a/gl/unictype/ctype_digit.c b/gl/unictype/ctype_digit.c
new file mode 100644
index 00000000..a82b3bb0
--- /dev/null
+++ b/gl/unictype/ctype_digit.c
@@ -0,0 +1,32 @@
1/* ISO C <ctype.h> like properties of Unicode characters.
2 Copyright (C) 2002, 2006-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2002.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include "unictype.h"
22
23#include "bitmap.h"
24
25/* Define u_is_digit table. */
26#include "ctype_digit.h"
27
28bool
29uc_is_digit (ucs4_t uc)
30{
31 return bitmap_lookup (&u_is_digit, uc);
32}
diff --git a/gl/unictype/ctype_digit.h b/gl/unictype/ctype_digit.h
new file mode 100644
index 00000000..2f7d1822
--- /dev/null
+++ b/gl/unictype/ctype_digit.h
@@ -0,0 +1,172 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* ISO C <ctype.h> like properties of Unicode characters. */
3/* Generated automatically by gen-uni-tables.c for Unicode 16.0.0. */
4
5/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
6
7 This file is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 This file is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19
20#define header_0 16
21#define header_2 9
22#define header_3 127
23#define header_4 15
24static const
25struct
26 {
27 int header[1];
28 int level1[1];
29 short level2[1 << 7];
30 unsigned int level3[1 << 4];
31 }
32u_is_digit =
33{
34 { 1 },
35 { 2 * sizeof (int) / sizeof (short) + 0 },
36 {
37 2 + 128 * sizeof (short) / sizeof (int) + 0,
38 -1,
39 -1,
40 -1,
41 -1,
42 -1,
43 -1,
44 -1,
45 -1,
46 -1,
47 -1,
48 -1,
49 -1,
50 -1,
51 -1,
52 -1,
53 -1,
54 -1,
55 -1,
56 -1,
57 -1,
58 -1,
59 -1,
60 -1,
61 -1,
62 -1,
63 -1,
64 -1,
65 -1,
66 -1,
67 -1,
68 -1,
69 -1,
70 -1,
71 -1,
72 -1,
73 -1,
74 -1,
75 -1,
76 -1,
77 -1,
78 -1,
79 -1,
80 -1,
81 -1,
82 -1,
83 -1,
84 -1,
85 -1,
86 -1,
87 -1,
88 -1,
89 -1,
90 -1,
91 -1,
92 -1,
93 -1,
94 -1,
95 -1,
96 -1,
97 -1,
98 -1,
99 -1,
100 -1,
101 -1,
102 -1,
103 -1,
104 -1,
105 -1,
106 -1,
107 -1,
108 -1,
109 -1,
110 -1,
111 -1,
112 -1,
113 -1,
114 -1,
115 -1,
116 -1,
117 -1,
118 -1,
119 -1,
120 -1,
121 -1,
122 -1,
123 -1,
124 -1,
125 -1,
126 -1,
127 -1,
128 -1,
129 -1,
130 -1,
131 -1,
132 -1,
133 -1,
134 -1,
135 -1,
136 -1,
137 -1,
138 -1,
139 -1,
140 -1,
141 -1,
142 -1,
143 -1,
144 -1,
145 -1,
146 -1,
147 -1,
148 -1,
149 -1,
150 -1,
151 -1,
152 -1,
153 -1,
154 -1,
155 -1,
156 -1,
157 -1,
158 -1,
159 -1,
160 -1,
161 -1,
162 -1,
163 -1,
164 -1
165 },
166 {
167 0x00000000U, 0x03FF0000U, 0x00000000U, 0x00000000U,
168 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
169 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
170 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U
171 }
172};
diff --git a/gl/unictype/ctype_graph.c b/gl/unictype/ctype_graph.c
new file mode 100644
index 00000000..2c41c794
--- /dev/null
+++ b/gl/unictype/ctype_graph.c
@@ -0,0 +1,32 @@
1/* ISO C <ctype.h> like properties of Unicode characters.
2 Copyright (C) 2002, 2006-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2002.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include "unictype.h"
22
23#include "bitmap.h"
24
25/* Define u_is_graph table. */
26#include "ctype_graph.h"
27
28bool
29uc_is_graph (ucs4_t uc)
30{
31 return bitmap_lookup (&u_is_graph, uc);
32}
diff --git a/gl/unictype/ctype_graph.h b/gl/unictype/ctype_graph.h
new file mode 100644
index 00000000..5627ad0f
--- /dev/null
+++ b/gl/unictype/ctype_graph.h
@@ -0,0 +1,1202 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* ISO C <ctype.h> like properties of Unicode characters. */
3/* Generated automatically by gen-uni-tables.c for Unicode 16.0.0. */
4
5/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
6
7 This file is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 This file is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19
20#define header_0 16
21#define header_2 9
22#define header_3 127
23#define header_4 15
24static const
25struct
26 {
27 int header[1];
28 int level1[17];
29 short level2[6 << 7];
30 unsigned int level3[94 << 4];
31 }
32u_is_graph =
33{
34 { 17 },
35 {
36 18 * sizeof (int) / sizeof (short) + 0,
37 18 * sizeof (int) / sizeof (short) + 128,
38 18 * sizeof (int) / sizeof (short) + 256,
39 18 * sizeof (int) / sizeof (short) + 384,
40 -1,
41 -1,
42 -1,
43 -1,
44 -1,
45 -1,
46 -1,
47 -1,
48 -1,
49 -1,
50 18 * sizeof (int) / sizeof (short) + 512,
51 18 * sizeof (int) / sizeof (short) + 640,
52 18 * sizeof (int) / sizeof (short) + 640
53 },
54 {
55 18 + 768 * sizeof (short) / sizeof (int) + 0,
56 18 + 768 * sizeof (short) / sizeof (int) + 16,
57 18 + 768 * sizeof (short) / sizeof (int) + 32,
58 18 + 768 * sizeof (short) / sizeof (int) + 48,
59 18 + 768 * sizeof (short) / sizeof (int) + 64,
60 18 + 768 * sizeof (short) / sizeof (int) + 80,
61 18 + 768 * sizeof (short) / sizeof (int) + 96,
62 18 + 768 * sizeof (short) / sizeof (int) + 112,
63 18 + 768 * sizeof (short) / sizeof (int) + 128,
64 18 + 768 * sizeof (short) / sizeof (int) + 144,
65 18 + 768 * sizeof (short) / sizeof (int) + 160,
66 18 + 768 * sizeof (short) / sizeof (int) + 176,
67 18 + 768 * sizeof (short) / sizeof (int) + 192,
68 18 + 768 * sizeof (short) / sizeof (int) + 208,
69 18 + 768 * sizeof (short) / sizeof (int) + 224,
70 18 + 768 * sizeof (short) / sizeof (int) + 240,
71 18 + 768 * sizeof (short) / sizeof (int) + 256,
72 18 + 768 * sizeof (short) / sizeof (int) + 160,
73 18 + 768 * sizeof (short) / sizeof (int) + 272,
74 18 + 768 * sizeof (short) / sizeof (int) + 160,
75 18 + 768 * sizeof (short) / sizeof (int) + 160,
76 18 + 768 * sizeof (short) / sizeof (int) + 288,
77 18 + 768 * sizeof (short) / sizeof (int) + 304,
78 18 + 768 * sizeof (short) / sizeof (int) + 320,
79 18 + 768 * sizeof (short) / sizeof (int) + 336,
80 18 + 768 * sizeof (short) / sizeof (int) + 352,
81 18 + 768 * sizeof (short) / sizeof (int) + 160,
82 18 + 768 * sizeof (short) / sizeof (int) + 160,
83 18 + 768 * sizeof (short) / sizeof (int) + 160,
84 18 + 768 * sizeof (short) / sizeof (int) + 160,
85 18 + 768 * sizeof (short) / sizeof (int) + 160,
86 18 + 768 * sizeof (short) / sizeof (int) + 160,
87 18 + 768 * sizeof (short) / sizeof (int) + 160,
88 18 + 768 * sizeof (short) / sizeof (int) + 160,
89 18 + 768 * sizeof (short) / sizeof (int) + 160,
90 18 + 768 * sizeof (short) / sizeof (int) + 160,
91 18 + 768 * sizeof (short) / sizeof (int) + 160,
92 18 + 768 * sizeof (short) / sizeof (int) + 160,
93 18 + 768 * sizeof (short) / sizeof (int) + 160,
94 18 + 768 * sizeof (short) / sizeof (int) + 160,
95 18 + 768 * sizeof (short) / sizeof (int) + 160,
96 18 + 768 * sizeof (short) / sizeof (int) + 160,
97 18 + 768 * sizeof (short) / sizeof (int) + 160,
98 18 + 768 * sizeof (short) / sizeof (int) + 160,
99 18 + 768 * sizeof (short) / sizeof (int) + 160,
100 18 + 768 * sizeof (short) / sizeof (int) + 160,
101 18 + 768 * sizeof (short) / sizeof (int) + 160,
102 18 + 768 * sizeof (short) / sizeof (int) + 160,
103 18 + 768 * sizeof (short) / sizeof (int) + 160,
104 18 + 768 * sizeof (short) / sizeof (int) + 160,
105 18 + 768 * sizeof (short) / sizeof (int) + 160,
106 18 + 768 * sizeof (short) / sizeof (int) + 160,
107 18 + 768 * sizeof (short) / sizeof (int) + 160,
108 18 + 768 * sizeof (short) / sizeof (int) + 160,
109 18 + 768 * sizeof (short) / sizeof (int) + 160,
110 18 + 768 * sizeof (short) / sizeof (int) + 160,
111 18 + 768 * sizeof (short) / sizeof (int) + 160,
112 18 + 768 * sizeof (short) / sizeof (int) + 160,
113 18 + 768 * sizeof (short) / sizeof (int) + 160,
114 18 + 768 * sizeof (short) / sizeof (int) + 160,
115 18 + 768 * sizeof (short) / sizeof (int) + 160,
116 18 + 768 * sizeof (short) / sizeof (int) + 160,
117 18 + 768 * sizeof (short) / sizeof (int) + 160,
118 18 + 768 * sizeof (short) / sizeof (int) + 160,
119 18 + 768 * sizeof (short) / sizeof (int) + 160,
120 18 + 768 * sizeof (short) / sizeof (int) + 160,
121 18 + 768 * sizeof (short) / sizeof (int) + 160,
122 18 + 768 * sizeof (short) / sizeof (int) + 160,
123 18 + 768 * sizeof (short) / sizeof (int) + 160,
124 18 + 768 * sizeof (short) / sizeof (int) + 160,
125 18 + 768 * sizeof (short) / sizeof (int) + 160,
126 18 + 768 * sizeof (short) / sizeof (int) + 160,
127 18 + 768 * sizeof (short) / sizeof (int) + 160,
128 18 + 768 * sizeof (short) / sizeof (int) + 160,
129 18 + 768 * sizeof (short) / sizeof (int) + 160,
130 18 + 768 * sizeof (short) / sizeof (int) + 160,
131 18 + 768 * sizeof (short) / sizeof (int) + 160,
132 18 + 768 * sizeof (short) / sizeof (int) + 160,
133 18 + 768 * sizeof (short) / sizeof (int) + 160,
134 18 + 768 * sizeof (short) / sizeof (int) + 160,
135 18 + 768 * sizeof (short) / sizeof (int) + 160,
136 18 + 768 * sizeof (short) / sizeof (int) + 160,
137 18 + 768 * sizeof (short) / sizeof (int) + 368,
138 18 + 768 * sizeof (short) / sizeof (int) + 384,
139 18 + 768 * sizeof (short) / sizeof (int) + 400,
140 18 + 768 * sizeof (short) / sizeof (int) + 416,
141 18 + 768 * sizeof (short) / sizeof (int) + 160,
142 18 + 768 * sizeof (short) / sizeof (int) + 160,
143 18 + 768 * sizeof (short) / sizeof (int) + 160,
144 18 + 768 * sizeof (short) / sizeof (int) + 160,
145 18 + 768 * sizeof (short) / sizeof (int) + 160,
146 18 + 768 * sizeof (short) / sizeof (int) + 160,
147 18 + 768 * sizeof (short) / sizeof (int) + 160,
148 18 + 768 * sizeof (short) / sizeof (int) + 160,
149 18 + 768 * sizeof (short) / sizeof (int) + 160,
150 18 + 768 * sizeof (short) / sizeof (int) + 160,
151 18 + 768 * sizeof (short) / sizeof (int) + 160,
152 18 + 768 * sizeof (short) / sizeof (int) + 160,
153 18 + 768 * sizeof (short) / sizeof (int) + 160,
154 18 + 768 * sizeof (short) / sizeof (int) + 160,
155 18 + 768 * sizeof (short) / sizeof (int) + 160,
156 18 + 768 * sizeof (short) / sizeof (int) + 160,
157 18 + 768 * sizeof (short) / sizeof (int) + 160,
158 18 + 768 * sizeof (short) / sizeof (int) + 160,
159 18 + 768 * sizeof (short) / sizeof (int) + 160,
160 18 + 768 * sizeof (short) / sizeof (int) + 160,
161 18 + 768 * sizeof (short) / sizeof (int) + 160,
162 18 + 768 * sizeof (short) / sizeof (int) + 432,
163 -1,
164 -1,
165 -1,
166 -1,
167 18 + 768 * sizeof (short) / sizeof (int) + 160,
168 18 + 768 * sizeof (short) / sizeof (int) + 160,
169 18 + 768 * sizeof (short) / sizeof (int) + 160,
170 18 + 768 * sizeof (short) / sizeof (int) + 160,
171 18 + 768 * sizeof (short) / sizeof (int) + 160,
172 18 + 768 * sizeof (short) / sizeof (int) + 160,
173 18 + 768 * sizeof (short) / sizeof (int) + 160,
174 18 + 768 * sizeof (short) / sizeof (int) + 160,
175 18 + 768 * sizeof (short) / sizeof (int) + 160,
176 18 + 768 * sizeof (short) / sizeof (int) + 160,
177 18 + 768 * sizeof (short) / sizeof (int) + 160,
178 18 + 768 * sizeof (short) / sizeof (int) + 160,
179 18 + 768 * sizeof (short) / sizeof (int) + 160,
180 18 + 768 * sizeof (short) / sizeof (int) + 448,
181 18 + 768 * sizeof (short) / sizeof (int) + 464,
182 18 + 768 * sizeof (short) / sizeof (int) + 480,
183 18 + 768 * sizeof (short) / sizeof (int) + 496,
184 18 + 768 * sizeof (short) / sizeof (int) + 512,
185 18 + 768 * sizeof (short) / sizeof (int) + 528,
186 18 + 768 * sizeof (short) / sizeof (int) + 544,
187 18 + 768 * sizeof (short) / sizeof (int) + 560,
188 18 + 768 * sizeof (short) / sizeof (int) + 576,
189 18 + 768 * sizeof (short) / sizeof (int) + 592,
190 18 + 768 * sizeof (short) / sizeof (int) + 608,
191 18 + 768 * sizeof (short) / sizeof (int) + 624,
192 18 + 768 * sizeof (short) / sizeof (int) + 640,
193 18 + 768 * sizeof (short) / sizeof (int) + 656,
194 18 + 768 * sizeof (short) / sizeof (int) + 672,
195 18 + 768 * sizeof (short) / sizeof (int) + 688,
196 18 + 768 * sizeof (short) / sizeof (int) + 704,
197 18 + 768 * sizeof (short) / sizeof (int) + 720,
198 18 + 768 * sizeof (short) / sizeof (int) + 736,
199 18 + 768 * sizeof (short) / sizeof (int) + 160,
200 18 + 768 * sizeof (short) / sizeof (int) + 752,
201 18 + 768 * sizeof (short) / sizeof (int) + 768,
202 -1,
203 -1,
204 -1,
205 -1,
206 18 + 768 * sizeof (short) / sizeof (int) + 784,
207 18 + 768 * sizeof (short) / sizeof (int) + 160,
208 18 + 768 * sizeof (short) / sizeof (int) + 160,
209 18 + 768 * sizeof (short) / sizeof (int) + 800,
210 18 + 768 * sizeof (short) / sizeof (int) + 160,
211 18 + 768 * sizeof (short) / sizeof (int) + 160,
212 18 + 768 * sizeof (short) / sizeof (int) + 160,
213 18 + 768 * sizeof (short) / sizeof (int) + 160,
214 18 + 768 * sizeof (short) / sizeof (int) + 160,
215 18 + 768 * sizeof (short) / sizeof (int) + 160,
216 18 + 768 * sizeof (short) / sizeof (int) + 816,
217 18 + 768 * sizeof (short) / sizeof (int) + 160,
218 18 + 768 * sizeof (short) / sizeof (int) + 832,
219 -1,
220 -1,
221 -1,
222 -1,
223 -1,
224 -1,
225 -1,
226 -1,
227 -1,
228 -1,
229 -1,
230 -1,
231 18 + 768 * sizeof (short) / sizeof (int) + 848,
232 -1,
233 -1,
234 -1,
235 18 + 768 * sizeof (short) / sizeof (int) + 160,
236 18 + 768 * sizeof (short) / sizeof (int) + 864,
237 18 + 768 * sizeof (short) / sizeof (int) + 880,
238 18 + 768 * sizeof (short) / sizeof (int) + 896,
239 18 + 768 * sizeof (short) / sizeof (int) + 160,
240 18 + 768 * sizeof (short) / sizeof (int) + 160,
241 18 + 768 * sizeof (short) / sizeof (int) + 160,
242 18 + 768 * sizeof (short) / sizeof (int) + 160,
243 18 + 768 * sizeof (short) / sizeof (int) + 160,
244 18 + 768 * sizeof (short) / sizeof (int) + 160,
245 18 + 768 * sizeof (short) / sizeof (int) + 160,
246 18 + 768 * sizeof (short) / sizeof (int) + 160,
247 18 + 768 * sizeof (short) / sizeof (int) + 160,
248 18 + 768 * sizeof (short) / sizeof (int) + 160,
249 18 + 768 * sizeof (short) / sizeof (int) + 160,
250 18 + 768 * sizeof (short) / sizeof (int) + 912,
251 18 + 768 * sizeof (short) / sizeof (int) + 160,
252 18 + 768 * sizeof (short) / sizeof (int) + 160,
253 18 + 768 * sizeof (short) / sizeof (int) + 928,
254 -1,
255 -1,
256 -1,
257 -1,
258 -1,
259 -1,
260 -1,
261 -1,
262 -1,
263 -1,
264 -1,
265 -1,
266 -1,
267 -1,
268 -1,
269 -1,
270 18 + 768 * sizeof (short) / sizeof (int) + 944,
271 18 + 768 * sizeof (short) / sizeof (int) + 960,
272 18 + 768 * sizeof (short) / sizeof (int) + 976,
273 -1,
274 -1,
275 -1,
276 -1,
277 18 + 768 * sizeof (short) / sizeof (int) + 992,
278 -1,
279 -1,
280 -1,
281 -1,
282 -1,
283 -1,
284 -1,
285 18 + 768 * sizeof (short) / sizeof (int) + 1008,
286 18 + 768 * sizeof (short) / sizeof (int) + 1024,
287 18 + 768 * sizeof (short) / sizeof (int) + 1040,
288 18 + 768 * sizeof (short) / sizeof (int) + 1056,
289 18 + 768 * sizeof (short) / sizeof (int) + 1072,
290 18 + 768 * sizeof (short) / sizeof (int) + 1088,
291 18 + 768 * sizeof (short) / sizeof (int) + 160,
292 18 + 768 * sizeof (short) / sizeof (int) + 1104,
293 -1,
294 18 + 768 * sizeof (short) / sizeof (int) + 1120,
295 18 + 768 * sizeof (short) / sizeof (int) + 1136,
296 18 + 768 * sizeof (short) / sizeof (int) + 1152,
297 18 + 768 * sizeof (short) / sizeof (int) + 1168,
298 18 + 768 * sizeof (short) / sizeof (int) + 1184,
299 18 + 768 * sizeof (short) / sizeof (int) + 1200,
300 -1,
301 18 + 768 * sizeof (short) / sizeof (int) + 1216,
302 18 + 768 * sizeof (short) / sizeof (int) + 1232,
303 18 + 768 * sizeof (short) / sizeof (int) + 1248,
304 18 + 768 * sizeof (short) / sizeof (int) + 1264,
305 18 + 768 * sizeof (short) / sizeof (int) + 160,
306 18 + 768 * sizeof (short) / sizeof (int) + 1280,
307 18 + 768 * sizeof (short) / sizeof (int) + 1296,
308 18 + 768 * sizeof (short) / sizeof (int) + 1312,
309 -1,
310 -1,
311 18 + 768 * sizeof (short) / sizeof (int) + 160,
312 18 + 768 * sizeof (short) / sizeof (int) + 160,
313 18 + 768 * sizeof (short) / sizeof (int) + 160,
314 18 + 768 * sizeof (short) / sizeof (int) + 160,
315 18 + 768 * sizeof (short) / sizeof (int) + 160,
316 18 + 768 * sizeof (short) / sizeof (int) + 160,
317 18 + 768 * sizeof (short) / sizeof (int) + 160,
318 18 + 768 * sizeof (short) / sizeof (int) + 160,
319 18 + 768 * sizeof (short) / sizeof (int) + 160,
320 18 + 768 * sizeof (short) / sizeof (int) + 160,
321 18 + 768 * sizeof (short) / sizeof (int) + 160,
322 18 + 768 * sizeof (short) / sizeof (int) + 160,
323 18 + 768 * sizeof (short) / sizeof (int) + 160,
324 18 + 768 * sizeof (short) / sizeof (int) + 160,
325 18 + 768 * sizeof (short) / sizeof (int) + 160,
326 18 + 768 * sizeof (short) / sizeof (int) + 160,
327 18 + 768 * sizeof (short) / sizeof (int) + 160,
328 18 + 768 * sizeof (short) / sizeof (int) + 160,
329 18 + 768 * sizeof (short) / sizeof (int) + 160,
330 18 + 768 * sizeof (short) / sizeof (int) + 160,
331 18 + 768 * sizeof (short) / sizeof (int) + 160,
332 18 + 768 * sizeof (short) / sizeof (int) + 160,
333 18 + 768 * sizeof (short) / sizeof (int) + 160,
334 18 + 768 * sizeof (short) / sizeof (int) + 160,
335 18 + 768 * sizeof (short) / sizeof (int) + 160,
336 18 + 768 * sizeof (short) / sizeof (int) + 160,
337 18 + 768 * sizeof (short) / sizeof (int) + 160,
338 18 + 768 * sizeof (short) / sizeof (int) + 160,
339 18 + 768 * sizeof (short) / sizeof (int) + 160,
340 18 + 768 * sizeof (short) / sizeof (int) + 160,
341 18 + 768 * sizeof (short) / sizeof (int) + 160,
342 18 + 768 * sizeof (short) / sizeof (int) + 160,
343 18 + 768 * sizeof (short) / sizeof (int) + 160,
344 18 + 768 * sizeof (short) / sizeof (int) + 160,
345 18 + 768 * sizeof (short) / sizeof (int) + 160,
346 18 + 768 * sizeof (short) / sizeof (int) + 160,
347 18 + 768 * sizeof (short) / sizeof (int) + 160,
348 18 + 768 * sizeof (short) / sizeof (int) + 160,
349 18 + 768 * sizeof (short) / sizeof (int) + 160,
350 18 + 768 * sizeof (short) / sizeof (int) + 160,
351 18 + 768 * sizeof (short) / sizeof (int) + 160,
352 18 + 768 * sizeof (short) / sizeof (int) + 160,
353 18 + 768 * sizeof (short) / sizeof (int) + 160,
354 18 + 768 * sizeof (short) / sizeof (int) + 160,
355 18 + 768 * sizeof (short) / sizeof (int) + 160,
356 18 + 768 * sizeof (short) / sizeof (int) + 160,
357 18 + 768 * sizeof (short) / sizeof (int) + 160,
358 18 + 768 * sizeof (short) / sizeof (int) + 160,
359 18 + 768 * sizeof (short) / sizeof (int) + 160,
360 18 + 768 * sizeof (short) / sizeof (int) + 160,
361 18 + 768 * sizeof (short) / sizeof (int) + 160,
362 18 + 768 * sizeof (short) / sizeof (int) + 160,
363 18 + 768 * sizeof (short) / sizeof (int) + 160,
364 18 + 768 * sizeof (short) / sizeof (int) + 160,
365 18 + 768 * sizeof (short) / sizeof (int) + 160,
366 18 + 768 * sizeof (short) / sizeof (int) + 160,
367 18 + 768 * sizeof (short) / sizeof (int) + 160,
368 18 + 768 * sizeof (short) / sizeof (int) + 160,
369 18 + 768 * sizeof (short) / sizeof (int) + 160,
370 18 + 768 * sizeof (short) / sizeof (int) + 160,
371 18 + 768 * sizeof (short) / sizeof (int) + 160,
372 18 + 768 * sizeof (short) / sizeof (int) + 160,
373 18 + 768 * sizeof (short) / sizeof (int) + 160,
374 18 + 768 * sizeof (short) / sizeof (int) + 160,
375 18 + 768 * sizeof (short) / sizeof (int) + 160,
376 18 + 768 * sizeof (short) / sizeof (int) + 160,
377 18 + 768 * sizeof (short) / sizeof (int) + 160,
378 18 + 768 * sizeof (short) / sizeof (int) + 160,
379 18 + 768 * sizeof (short) / sizeof (int) + 160,
380 18 + 768 * sizeof (short) / sizeof (int) + 160,
381 18 + 768 * sizeof (short) / sizeof (int) + 160,
382 18 + 768 * sizeof (short) / sizeof (int) + 160,
383 18 + 768 * sizeof (short) / sizeof (int) + 160,
384 18 + 768 * sizeof (short) / sizeof (int) + 160,
385 18 + 768 * sizeof (short) / sizeof (int) + 160,
386 18 + 768 * sizeof (short) / sizeof (int) + 160,
387 18 + 768 * sizeof (short) / sizeof (int) + 160,
388 18 + 768 * sizeof (short) / sizeof (int) + 160,
389 18 + 768 * sizeof (short) / sizeof (int) + 160,
390 18 + 768 * sizeof (short) / sizeof (int) + 160,
391 18 + 768 * sizeof (short) / sizeof (int) + 160,
392 18 + 768 * sizeof (short) / sizeof (int) + 160,
393 18 + 768 * sizeof (short) / sizeof (int) + 160,
394 18 + 768 * sizeof (short) / sizeof (int) + 1328,
395 18 + 768 * sizeof (short) / sizeof (int) + 160,
396 18 + 768 * sizeof (short) / sizeof (int) + 160,
397 18 + 768 * sizeof (short) / sizeof (int) + 160,
398 18 + 768 * sizeof (short) / sizeof (int) + 160,
399 18 + 768 * sizeof (short) / sizeof (int) + 160,
400 18 + 768 * sizeof (short) / sizeof (int) + 160,
401 18 + 768 * sizeof (short) / sizeof (int) + 160,
402 18 + 768 * sizeof (short) / sizeof (int) + 1344,
403 18 + 768 * sizeof (short) / sizeof (int) + 1360,
404 18 + 768 * sizeof (short) / sizeof (int) + 160,
405 18 + 768 * sizeof (short) / sizeof (int) + 160,
406 18 + 768 * sizeof (short) / sizeof (int) + 160,
407 18 + 768 * sizeof (short) / sizeof (int) + 160,
408 18 + 768 * sizeof (short) / sizeof (int) + 160,
409 18 + 768 * sizeof (short) / sizeof (int) + 160,
410 18 + 768 * sizeof (short) / sizeof (int) + 160,
411 18 + 768 * sizeof (short) / sizeof (int) + 160,
412 18 + 768 * sizeof (short) / sizeof (int) + 160,
413 18 + 768 * sizeof (short) / sizeof (int) + 160,
414 18 + 768 * sizeof (short) / sizeof (int) + 1376,
415 18 + 768 * sizeof (short) / sizeof (int) + 160,
416 18 + 768 * sizeof (short) / sizeof (int) + 160,
417 18 + 768 * sizeof (short) / sizeof (int) + 160,
418 18 + 768 * sizeof (short) / sizeof (int) + 160,
419 18 + 768 * sizeof (short) / sizeof (int) + 160,
420 18 + 768 * sizeof (short) / sizeof (int) + 160,
421 18 + 768 * sizeof (short) / sizeof (int) + 160,
422 18 + 768 * sizeof (short) / sizeof (int) + 160,
423 18 + 768 * sizeof (short) / sizeof (int) + 160,
424 18 + 768 * sizeof (short) / sizeof (int) + 160,
425 18 + 768 * sizeof (short) / sizeof (int) + 160,
426 18 + 768 * sizeof (short) / sizeof (int) + 160,
427 18 + 768 * sizeof (short) / sizeof (int) + 160,
428 18 + 768 * sizeof (short) / sizeof (int) + 1392,
429 18 + 768 * sizeof (short) / sizeof (int) + 160,
430 18 + 768 * sizeof (short) / sizeof (int) + 1408,
431 -1,
432 -1,
433 -1,
434 -1,
435 18 + 768 * sizeof (short) / sizeof (int) + 160,
436 18 + 768 * sizeof (short) / sizeof (int) + 1424,
437 -1,
438 -1,
439 18 + 768 * sizeof (short) / sizeof (int) + 160,
440 18 + 768 * sizeof (short) / sizeof (int) + 160,
441 18 + 768 * sizeof (short) / sizeof (int) + 160,
442 18 + 768 * sizeof (short) / sizeof (int) + 160,
443 18 + 768 * sizeof (short) / sizeof (int) + 160,
444 18 + 768 * sizeof (short) / sizeof (int) + 160,
445 18 + 768 * sizeof (short) / sizeof (int) + 160,
446 18 + 768 * sizeof (short) / sizeof (int) + 160,
447 18 + 768 * sizeof (short) / sizeof (int) + 160,
448 18 + 768 * sizeof (short) / sizeof (int) + 1440,
449 18 + 768 * sizeof (short) / sizeof (int) + 160,
450 18 + 768 * sizeof (short) / sizeof (int) + 160,
451 18 + 768 * sizeof (short) / sizeof (int) + 160,
452 18 + 768 * sizeof (short) / sizeof (int) + 160,
453 18 + 768 * sizeof (short) / sizeof (int) + 160,
454 18 + 768 * sizeof (short) / sizeof (int) + 160,
455 18 + 768 * sizeof (short) / sizeof (int) + 160,
456 18 + 768 * sizeof (short) / sizeof (int) + 1456,
457 -1,
458 -1,
459 -1,
460 -1,
461 -1,
462 -1,
463 -1,
464 -1,
465 -1,
466 -1,
467 -1,
468 -1,
469 -1,
470 -1,
471 -1,
472 -1,
473 -1,
474 -1,
475 -1,
476 -1,
477 -1,
478 -1,
479 -1,
480 -1,
481 -1,
482 -1,
483 -1,
484 -1,
485 -1,
486 -1,
487 -1,
488 -1,
489 -1,
490 -1,
491 -1,
492 -1,
493 -1,
494 -1,
495 -1,
496 -1,
497 -1,
498 -1,
499 -1,
500 -1,
501 -1,
502 -1,
503 -1,
504 -1,
505 -1,
506 -1,
507 -1,
508 -1,
509 -1,
510 -1,
511 -1,
512 -1,
513 -1,
514 -1,
515 -1,
516 -1,
517 -1,
518 -1,
519 -1,
520 -1,
521 -1,
522 -1,
523 -1,
524 -1,
525 -1,
526 -1,
527 -1,
528 -1,
529 -1,
530 -1,
531 -1,
532 -1,
533 -1,
534 -1,
535 -1,
536 -1,
537 -1,
538 -1,
539 -1,
540 -1,
541 -1,
542 -1,
543 -1,
544 -1,
545 -1,
546 -1,
547 -1,
548 -1,
549 -1,
550 -1,
551 -1,
552 -1,
553 -1,
554 -1,
555 -1,
556 -1,
557 -1,
558 -1,
559 -1,
560 -1,
561 -1,
562 -1,
563 -1,
564 -1,
565 -1,
566 -1,
567 18 + 768 * sizeof (short) / sizeof (int) + 1472,
568 -1,
569 -1,
570 -1,
571 -1,
572 -1,
573 -1,
574 -1,
575 -1,
576 -1,
577 -1,
578 -1,
579 -1,
580 -1,
581 -1,
582 -1,
583 -1,
584 -1,
585 -1,
586 -1,
587 -1,
588 -1,
589 -1,
590 -1,
591 -1,
592 -1,
593 -1,
594 -1,
595 -1,
596 -1,
597 -1,
598 -1,
599 -1,
600 -1,
601 -1,
602 -1,
603 -1,
604 -1,
605 -1,
606 -1,
607 -1,
608 -1,
609 -1,
610 -1,
611 -1,
612 -1,
613 -1,
614 -1,
615 -1,
616 -1,
617 -1,
618 -1,
619 -1,
620 -1,
621 -1,
622 -1,
623 -1,
624 -1,
625 -1,
626 -1,
627 -1,
628 -1,
629 -1,
630 -1,
631 -1,
632 -1,
633 -1,
634 -1,
635 -1,
636 -1,
637 -1,
638 -1,
639 -1,
640 -1,
641 -1,
642 -1,
643 -1,
644 -1,
645 -1,
646 -1,
647 -1,
648 -1,
649 -1,
650 -1,
651 -1,
652 -1,
653 -1,
654 -1,
655 -1,
656 -1,
657 -1,
658 -1,
659 -1,
660 -1,
661 -1,
662 -1,
663 -1,
664 -1,
665 -1,
666 -1,
667 -1,
668 -1,
669 -1,
670 -1,
671 -1,
672 -1,
673 -1,
674 -1,
675 -1,
676 -1,
677 -1,
678 -1,
679 -1,
680 -1,
681 -1,
682 -1,
683 -1,
684 -1,
685 -1,
686 -1,
687 -1,
688 -1,
689 -1,
690 -1,
691 -1,
692 -1,
693 -1,
694 -1,
695 18 + 768 * sizeof (short) / sizeof (int) + 160,
696 18 + 768 * sizeof (short) / sizeof (int) + 160,
697 18 + 768 * sizeof (short) / sizeof (int) + 160,
698 18 + 768 * sizeof (short) / sizeof (int) + 160,
699 18 + 768 * sizeof (short) / sizeof (int) + 160,
700 18 + 768 * sizeof (short) / sizeof (int) + 160,
701 18 + 768 * sizeof (short) / sizeof (int) + 160,
702 18 + 768 * sizeof (short) / sizeof (int) + 160,
703 18 + 768 * sizeof (short) / sizeof (int) + 160,
704 18 + 768 * sizeof (short) / sizeof (int) + 160,
705 18 + 768 * sizeof (short) / sizeof (int) + 160,
706 18 + 768 * sizeof (short) / sizeof (int) + 160,
707 18 + 768 * sizeof (short) / sizeof (int) + 160,
708 18 + 768 * sizeof (short) / sizeof (int) + 160,
709 18 + 768 * sizeof (short) / sizeof (int) + 160,
710 18 + 768 * sizeof (short) / sizeof (int) + 160,
711 18 + 768 * sizeof (short) / sizeof (int) + 160,
712 18 + 768 * sizeof (short) / sizeof (int) + 160,
713 18 + 768 * sizeof (short) / sizeof (int) + 160,
714 18 + 768 * sizeof (short) / sizeof (int) + 160,
715 18 + 768 * sizeof (short) / sizeof (int) + 160,
716 18 + 768 * sizeof (short) / sizeof (int) + 160,
717 18 + 768 * sizeof (short) / sizeof (int) + 160,
718 18 + 768 * sizeof (short) / sizeof (int) + 160,
719 18 + 768 * sizeof (short) / sizeof (int) + 160,
720 18 + 768 * sizeof (short) / sizeof (int) + 160,
721 18 + 768 * sizeof (short) / sizeof (int) + 160,
722 18 + 768 * sizeof (short) / sizeof (int) + 160,
723 18 + 768 * sizeof (short) / sizeof (int) + 160,
724 18 + 768 * sizeof (short) / sizeof (int) + 160,
725 18 + 768 * sizeof (short) / sizeof (int) + 160,
726 18 + 768 * sizeof (short) / sizeof (int) + 160,
727 18 + 768 * sizeof (short) / sizeof (int) + 160,
728 18 + 768 * sizeof (short) / sizeof (int) + 160,
729 18 + 768 * sizeof (short) / sizeof (int) + 160,
730 18 + 768 * sizeof (short) / sizeof (int) + 160,
731 18 + 768 * sizeof (short) / sizeof (int) + 160,
732 18 + 768 * sizeof (short) / sizeof (int) + 160,
733 18 + 768 * sizeof (short) / sizeof (int) + 160,
734 18 + 768 * sizeof (short) / sizeof (int) + 160,
735 18 + 768 * sizeof (short) / sizeof (int) + 160,
736 18 + 768 * sizeof (short) / sizeof (int) + 160,
737 18 + 768 * sizeof (short) / sizeof (int) + 160,
738 18 + 768 * sizeof (short) / sizeof (int) + 160,
739 18 + 768 * sizeof (short) / sizeof (int) + 160,
740 18 + 768 * sizeof (short) / sizeof (int) + 160,
741 18 + 768 * sizeof (short) / sizeof (int) + 160,
742 18 + 768 * sizeof (short) / sizeof (int) + 160,
743 18 + 768 * sizeof (short) / sizeof (int) + 160,
744 18 + 768 * sizeof (short) / sizeof (int) + 160,
745 18 + 768 * sizeof (short) / sizeof (int) + 160,
746 18 + 768 * sizeof (short) / sizeof (int) + 160,
747 18 + 768 * sizeof (short) / sizeof (int) + 160,
748 18 + 768 * sizeof (short) / sizeof (int) + 160,
749 18 + 768 * sizeof (short) / sizeof (int) + 160,
750 18 + 768 * sizeof (short) / sizeof (int) + 160,
751 18 + 768 * sizeof (short) / sizeof (int) + 160,
752 18 + 768 * sizeof (short) / sizeof (int) + 160,
753 18 + 768 * sizeof (short) / sizeof (int) + 160,
754 18 + 768 * sizeof (short) / sizeof (int) + 160,
755 18 + 768 * sizeof (short) / sizeof (int) + 160,
756 18 + 768 * sizeof (short) / sizeof (int) + 160,
757 18 + 768 * sizeof (short) / sizeof (int) + 160,
758 18 + 768 * sizeof (short) / sizeof (int) + 160,
759 18 + 768 * sizeof (short) / sizeof (int) + 160,
760 18 + 768 * sizeof (short) / sizeof (int) + 160,
761 18 + 768 * sizeof (short) / sizeof (int) + 160,
762 18 + 768 * sizeof (short) / sizeof (int) + 160,
763 18 + 768 * sizeof (short) / sizeof (int) + 160,
764 18 + 768 * sizeof (short) / sizeof (int) + 160,
765 18 + 768 * sizeof (short) / sizeof (int) + 160,
766 18 + 768 * sizeof (short) / sizeof (int) + 160,
767 18 + 768 * sizeof (short) / sizeof (int) + 160,
768 18 + 768 * sizeof (short) / sizeof (int) + 160,
769 18 + 768 * sizeof (short) / sizeof (int) + 160,
770 18 + 768 * sizeof (short) / sizeof (int) + 160,
771 18 + 768 * sizeof (short) / sizeof (int) + 160,
772 18 + 768 * sizeof (short) / sizeof (int) + 160,
773 18 + 768 * sizeof (short) / sizeof (int) + 160,
774 18 + 768 * sizeof (short) / sizeof (int) + 160,
775 18 + 768 * sizeof (short) / sizeof (int) + 160,
776 18 + 768 * sizeof (short) / sizeof (int) + 160,
777 18 + 768 * sizeof (short) / sizeof (int) + 160,
778 18 + 768 * sizeof (short) / sizeof (int) + 160,
779 18 + 768 * sizeof (short) / sizeof (int) + 160,
780 18 + 768 * sizeof (short) / sizeof (int) + 160,
781 18 + 768 * sizeof (short) / sizeof (int) + 160,
782 18 + 768 * sizeof (short) / sizeof (int) + 160,
783 18 + 768 * sizeof (short) / sizeof (int) + 160,
784 18 + 768 * sizeof (short) / sizeof (int) + 160,
785 18 + 768 * sizeof (short) / sizeof (int) + 160,
786 18 + 768 * sizeof (short) / sizeof (int) + 160,
787 18 + 768 * sizeof (short) / sizeof (int) + 160,
788 18 + 768 * sizeof (short) / sizeof (int) + 160,
789 18 + 768 * sizeof (short) / sizeof (int) + 160,
790 18 + 768 * sizeof (short) / sizeof (int) + 160,
791 18 + 768 * sizeof (short) / sizeof (int) + 160,
792 18 + 768 * sizeof (short) / sizeof (int) + 160,
793 18 + 768 * sizeof (short) / sizeof (int) + 160,
794 18 + 768 * sizeof (short) / sizeof (int) + 160,
795 18 + 768 * sizeof (short) / sizeof (int) + 160,
796 18 + 768 * sizeof (short) / sizeof (int) + 160,
797 18 + 768 * sizeof (short) / sizeof (int) + 160,
798 18 + 768 * sizeof (short) / sizeof (int) + 160,
799 18 + 768 * sizeof (short) / sizeof (int) + 160,
800 18 + 768 * sizeof (short) / sizeof (int) + 160,
801 18 + 768 * sizeof (short) / sizeof (int) + 160,
802 18 + 768 * sizeof (short) / sizeof (int) + 160,
803 18 + 768 * sizeof (short) / sizeof (int) + 160,
804 18 + 768 * sizeof (short) / sizeof (int) + 160,
805 18 + 768 * sizeof (short) / sizeof (int) + 160,
806 18 + 768 * sizeof (short) / sizeof (int) + 160,
807 18 + 768 * sizeof (short) / sizeof (int) + 160,
808 18 + 768 * sizeof (short) / sizeof (int) + 160,
809 18 + 768 * sizeof (short) / sizeof (int) + 160,
810 18 + 768 * sizeof (short) / sizeof (int) + 160,
811 18 + 768 * sizeof (short) / sizeof (int) + 160,
812 18 + 768 * sizeof (short) / sizeof (int) + 160,
813 18 + 768 * sizeof (short) / sizeof (int) + 160,
814 18 + 768 * sizeof (short) / sizeof (int) + 160,
815 18 + 768 * sizeof (short) / sizeof (int) + 160,
816 18 + 768 * sizeof (short) / sizeof (int) + 160,
817 18 + 768 * sizeof (short) / sizeof (int) + 160,
818 18 + 768 * sizeof (short) / sizeof (int) + 160,
819 18 + 768 * sizeof (short) / sizeof (int) + 160,
820 18 + 768 * sizeof (short) / sizeof (int) + 160,
821 18 + 768 * sizeof (short) / sizeof (int) + 160,
822 18 + 768 * sizeof (short) / sizeof (int) + 1488
823 },
824 {
825 0x00000000U, 0xFFFFFFFEU, 0xFFFFFFFFU, 0x7FFFFFFFU,
826 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
827 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
828 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
829 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
830 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
831 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFCFFFFFFU,
832 0xFFFFD7F0U, 0xFFFFFFFBU, 0xFFFFFFFFU, 0xFFFFFFFFU,
833 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
834 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
835 0xFFFFFFFFU, 0xFFFEFFFFU, 0xFE7FFFFFU, 0xFFFFFFFFU,
836 0xFFFEE7FFU, 0xFFFFFFFFU, 0xFFFF00FFU, 0x001F87FFU,
837 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
838 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
839 0xFFFFBFFFU, 0xFFFFFFFFU, 0xFFFFE7FFU, 0xFFFFFFFFU,
840 0xFFFFFFFFU, 0x0003FFFFU, 0xFFFFFFFFU, 0xE7FFFFFFU,
841 0xFFFFFFFFU, 0x7FFF3FFFU, 0x4FFFFFFFU, 0xFFFF07FFU,
842 0xFF837FFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
843 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
844 0xFFF99FEFU, 0xF3C5FDFFU, 0xB080799FU, 0x7FFFFFCFU,
845 0xFFF987EEU, 0xD36DFDFFU, 0x5E023987U, 0x007FFFC0U,
846 0xFFFBBFEEU, 0xF3EDFDFFU, 0x00013BBFU, 0xFE03FFCFU,
847 0xFFF99FEEU, 0xF3EDFDFFU, 0xB0E0399FU, 0x00FFFFCFU,
848 0xD63DC7ECU, 0xC3FFC718U, 0x00813DC7U, 0x07FFFFC0U,
849 0xFFFDDFFFU, 0xF3FFFDFFU, 0x27603DDFU, 0xFF80FFCFU,
850 0xFFFDDFFFU, 0xF3EFFDFFU, 0x60603DDFU, 0x000EFFCFU,
851 0xFFFDDFFFU, 0xFFFFFFFFU, 0xFFF0FDDFU, 0xFFFFFFCFU,
852 0xFC7FFFEEU, 0x2FFBFFFFU, 0xFF5F847FU, 0x001CFFC0U,
853 0xFFFFFFFEU, 0x87FFFFFFU, 0x0FFFFFFFU, 0x00000000U,
854 0xFFFFF7D6U, 0x3FFFFFAFU, 0xF3FF7F5FU, 0x00000000U,
855 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFEFFU, 0xFFFE1FFFU,
856 0xFEFFFFFFU, 0xDFFFFFFFU, 0x07FFDFFFU, 0x00000000U,
857 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
858 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF20BFU, 0xFFFFFFFFU,
859 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
860 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
861 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3D7F3DFFU, 0xFFFFFFFFU,
862 0xFFFF3DFFU, 0x7F3DFFFFU, 0xFF7FFF3DU, 0xFFFFFFFFU,
863 0xFF3DFFFFU, 0xFFFFFFFFU, 0xE7FFFFFFU, 0x1FFFFFFFU,
864 0x03FFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3F3FFFFFU,
865 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
866 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
867 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
868 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
869 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
870 0x1FFFFFFEU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x01FFFFFFU,
871 0x803FFFFFU, 0x007FFFFFU, 0x000FFFFFU, 0x000DDFFFU,
872 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3FFFFFFFU, 0x03FF03FFU,
873 0x03FFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x01FFFFFFU,
874 0xFFFFFFFFU, 0xFFFF07FFU, 0xFFFFFFFFU, 0x003FFFFFU,
875 0x7FFFFFFFU, 0x0FFF0FFFU, 0xFFFFFFF1U, 0x001F3FFFU,
876 0xFFFFFFFFU, 0xFFFF0FFFU, 0xC7FF03FFU, 0xFFFFFFFFU,
877 0xCFFFFFFFU, 0xFFFFFFFFU, 0x7FFFFFFFU, 0x9FFFFFFFU,
878 0x03FF03FFU, 0xFFFF3FFFU, 0x00007FFFU, 0x00000000U,
879 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFDFFFU, 0xFFFFFFFFU,
880 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xF00FFFFFU,
881 0xFFFFFFFFU, 0xF8FFFFFFU, 0xFFFFE3FFU, 0xFFFFFFFFU,
882 0xFFFF07FFU, 0xE7FFFFFFU, 0xFFFF00FFU, 0x07FFFFFFU,
883 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
884 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
885 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
886 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
887 0x3F3FFFFFU, 0xFFFFFFFFU, 0xAAFF3F3FU, 0x3FFFFFFFU,
888 0xFFFFFFFFU, 0xFFDFFFFFU, 0xEFCFFFDFU, 0x7FDCFFFFU,
889 0xFFFFF880U, 0xFFFFFCFFU, 0x7FFFFFFFU, 0xFFF3FFDFU,
890 0x1FFF7FFFU, 0xFFFFFFFFU, 0xFFFF0001U, 0x0001FFFFU,
891 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
892 0xFFFF0FFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
893 0xFFFFFFFFU, 0x000003FFU, 0x000007FFU, 0xFFFFFFFFU,
894 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
895 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
896 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
897 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
898 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
899 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFCFFFFFU,
900 0xFFBFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
901 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
902 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFE0FFFFFU,
903 0xFFFFFFFFU, 0xFFFF20BFU, 0xFFFFFFFFU, 0x800180FFU,
904 0x007FFFFFU, 0x7F7F7F7FU, 0x7F7F7F7FU, 0xFFFFFFFFU,
905 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3FFFFFFFU, 0x00000000U,
906 0xFBFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000FFFFFU,
907 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
908 0xFFFFFFFFU, 0xFFFFFFFFU, 0x003FFFFFU, 0xFFFF0000U,
909 0xFFFFFFFEU, 0xFFFFFFFFU, 0xFFFFFFFEU, 0xFFFFFFFFU,
910 0xFE7FFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
911 0xFFFFFFE0U, 0xFFFEFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
912 0xFFFF7FFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF803FU,
913 0x7FFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
914 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
915 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
916 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
917 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
918 0xFFFF1FFFU, 0xFFFFFFFFU, 0xFFFF007FU, 0xFFFFFFFFU,
919 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
920 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
921 0xFFFFFFFFU, 0x00000FFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
922 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00FFFFFFU,
923 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
924 0xFFFFFFFFU, 0xFFFFFFFFU, 0x1FEB3FFFU, 0xFFFC0000U,
925 0xFFFFFFFFU, 0x03FF1FFFU, 0xFFFFFFFFU, 0x00FFFFFFU,
926 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FFC03FU, 0xFFFFFFFFU,
927 0xFFFFFFFFU, 0xFFFFFFFFU, 0x800FFFFFU, 0x1FFFFFFFU,
928 0xFFFFFFFFU, 0xFFFFFFFFU, 0xC3FFBFFFU, 0x7FFFFFFFU,
929 0xFFFFFFFFU, 0x007FFFFFU, 0xF3FF3FFFU, 0xFFFFFFFFU,
930 0xFFFFFFFFU, 0xFFFFFFFFU, 0xF8000007U, 0x007FFFFFU,
931 0x007E7E7EU, 0xFFFF7F7FU, 0xFFFFFFFFU, 0xFFFF0FFFU,
932 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FF3FFFU,
933 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
934 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
935 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
936 0xFFFFFFFFU, 0xFFFF000FU, 0xFFFFF87FU, 0x0FFFFFFFU,
937 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF3FFFU,
938 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FFFFFFU, 0x00000000U,
939 0xE0F8007FU, 0x5F7FFFFFU, 0xFFFFFFDBU, 0xFFFFFFFFU,
940 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFF80007U, 0xFFFFFFFFU,
941 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
942 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
943 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
944 0xFFFCFFFFU, 0xFFFFFFFFU, 0x000080FFU, 0xFFFF0000U,
945 0x03FFFFFFU, 0xFFFFFFFFU, 0xFFF7FFFFU, 0xFFDF0F7FU,
946 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x9FFFFFFFU,
947 0xFFFFFFFEU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
948 0xFFFFFFFFU, 0x7FFFFFFFU, 0x1CFCFCFCU, 0x3E007F7FU,
949 0xFFFFEFFFU, 0xB7FFFF7FU, 0x3FFF3FFFU, 0x00000000U,
950 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x07FFFFFFU,
951 0xFFFFFF87U, 0xFF8FFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
952 0x1FFF7FFFU, 0x00000001U, 0xFFFF0000U, 0x3FFFFFFFU,
953 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
954 0x1FFFFFFFU, 0xFFFFFFFFU, 0x0001FFFFU, 0x0FFFFFFFU,
955 0xFFFFFFFFU, 0xFFFFE00FU, 0xFFFF07FFU, 0x07FFFFFFU,
956 0xBFFFFFFFU, 0xFFFFFFFFU, 0x003FFF0FU, 0x00000000U,
957 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
958 0x3FFFFFFFU, 0xFFFF03FFU, 0xFF0FFFFFU, 0x0FFFFFFFU,
959 0xFFFFFFFFU, 0xFFFF00FFU, 0xFFFFFFFFU, 0xF7FF800FU,
960 0xFFB7F7FFU, 0x1BFBFFFBU, 0xFFFFFFFFU, 0x000FFFFFU,
961 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
962 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
963 0xFFFFFFFFU, 0x007FFFFFU, 0x003FFFFFU, 0x000000FFU,
964 0xFFFFFFBFU, 0x07FDFFFFU, 0x00000000U, 0x00000000U,
965 0xFFFFFD3FU, 0x91BFFFFFU, 0xFFBFFFFFU, 0xFFFFFFFFU,
966 0x7FFFFFFFU, 0x0000FF80U, 0x00000000U, 0xF837FFFFU,
967 0x8FFFFFFFU, 0x83FFFFFFU, 0x00000000U, 0x00000000U,
968 0xFFFFFFFFU, 0xF0FFFFFFU, 0xFFFCFFFFU, 0xFFFFFFFFU,
969 0xFEEFF06FU, 0x873FFFFFU, 0x01FF01FFU, 0xFFFFFFFFU,
970 0xFFFFFFFFU, 0x00000000U, 0xFFFFFFFFU, 0x007FF87FU,
971 0xFFFFFFFFU, 0xFE3FFFFFU, 0xFF3FFFFFU, 0xFF07FFFFU,
972 0x1E03FFFFU, 0x0000FE00U, 0x00000000U, 0x00000000U,
973 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000001FFU, 0x00000000U,
974 0xFFFFFFFFU, 0x0007FFFFU, 0xFFFFFFFFU, 0xFC07FFFFU,
975 0xFFFFFFFFU, 0x03FF00FFU, 0xFFFFFFFFU, 0xFFFFFE3FU,
976 0x0000C03FU, 0x00000000U, 0x00000000U, 0x00000000U,
977 0x00000000U, 0x00000000U, 0x00000000U, 0x7FFFFFFFU,
978 0xFFFFFFFFU, 0x00033BFFU, 0x0000001CU, 0xF0000000U,
979 0xFFFFFFFFU, 0xFFFF00FFU, 0x03FFFFFFU, 0xFFFF0000U,
980 0x000003FFU, 0xFFFF0000U, 0x00000FFFU, 0x007FFFFFU,
981 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFC3FFFU, 0x803FFFFFU,
982 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF2007U, 0x03FF01FFU,
983 0xFFFFFFFFU, 0xFFDFFFFFU, 0xFFFF00FFU, 0x007FFFFFU,
984 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x001FFFFEU,
985 0xFFFBFFFFU, 0xFFFFFFFFU, 0x00000003U, 0x00000000U,
986 0xBFFFBD7FU, 0xFFFF03FFU, 0xFFFFFFFFU, 0x03FF07FFU,
987 0xFFF99FEFU, 0xFBEDFDFFU, 0xE081399FU, 0x001F1FCFU,
988 0xFFFF4BFFU, 0xFFBFFFFFU, 0x01BFF7A5U, 0x00000006U,
989 0xFFFFFFFFU, 0xFFFFFFFFU, 0xEFFFFFFFU, 0x00000003U,
990 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FF00FFU, 0x00000000U,
991 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
992 0xFFFFFFFFU, 0xFF3FFFFFU, 0x3FFFFFFFU, 0x00000000U,
993 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FF001FU, 0x00001FFFU,
994 0xFFFFFFFFU, 0x03FFFFFFU, 0xFFFF03FFU, 0x0000000FU,
995 0xE7FFFFFFU, 0xFFFF0FFFU, 0x0000007FU, 0x00000000U,
996 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
997 0xFFFFFFFFU, 0x0FFFFFFFU, 0x00000000U, 0x00000000U,
998 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x8007FFFFU,
999 0xFF6FF27FU, 0xF9BFFFFFU, 0x03FF007FU, 0x00000000U,
1000 0x00000000U, 0xFFFFFCFFU, 0xFCFFFFFFU, 0x0000001FU,
1001 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF00FFU, 0xFFFFFFFFU,
1002 0xFFFFFFFFU, 0xFFFF0007U, 0xFFFFFFFFU, 0x01FFFFFFU,
1003 0x000003FFU, 0x00000000U, 0x00000000U, 0x00000000U,
1004 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0x03FF0003U,
1005 0xFFFFFDFFU, 0xFF7FFFFFU, 0xFFFF003FU, 0xFFFF1FFFU,
1006 0xFFFCFFFFU, 0x007FFEFFU, 0x00000000U, 0x00000000U,
1007 0xFFFFFB7FU, 0xB47FFFFFU, 0x03FF00FFU, 0xFFFFFDBFU,
1008 0x01FB7FFFU, 0x000003FFU, 0x00000000U, 0x00000000U,
1009 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1010 0x00000000U, 0x00000000U, 0x00000000U, 0x01FFFFFFU,
1011 0xFFFDFFFFU, 0xC7FFFFFFU, 0x07FFFFFFU, 0x00000000U,
1012 0x00000000U, 0x00010000U, 0xFFFFFFFFU, 0x8003FFFFU,
1013 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1014 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1015 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1016 0x03FFFFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
1017 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x001F7FFFU,
1018 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1019 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000000FU, 0x00000000U,
1020 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1021 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1022 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1023 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1024 0xFFFF0000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0007FFFFU,
1025 0xFFFFFFFFU, 0xFFFFFFFFU, 0x003FFFFFU, 0xFFFFFFFFU,
1026 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1027 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1028 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1029 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1030 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1031 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1032 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x07FFFFFFU,
1033 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000007FU, 0x00000000U,
1034 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1035 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1036 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1037 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1038 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1039 0xFFFFFFFFU, 0x03FFFFFFU, 0x00000000U, 0x00000000U,
1040 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1041 0xFFFFFFFFU, 0x01FFFFFFU, 0x7FFFFFFFU, 0xFFFFC3FFU,
1042 0xFFFFFFFFU, 0x7FFFFFFFU, 0xFFFF03FFU, 0x003F3FFFU,
1043 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFBFF003FU, 0xE0FFFFFBU,
1044 0x0000FFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
1045 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1046 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1047 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0x03FFFFFFU,
1048 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1049 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU,
1050 0x07FFFFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
1051 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF87FFU, 0xFFFFFFFFU,
1052 0xFFFF80FFU, 0x00000000U, 0x00000000U, 0x0003001FU,
1053 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1054 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1055 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1056 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00FFFFFFU,
1057 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1058 0xFFFFFFFFU, 0xFFFFFFFFU, 0x003FFFFFU, 0x80000000U,
1059 0x000001FFU, 0x00000000U, 0x00000000U, 0x00000000U,
1060 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1061 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1062 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1063 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1064 0x00000000U, 0x00000000U, 0x00000000U, 0x6FEF0000U,
1065 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1066 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1067 0xFFFFFFFFU, 0x00040007U, 0x00270000U, 0xFFFF00F0U,
1068 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1069 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1070 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0FFFFFFFU,
1071 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1072 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1073 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x1FFF07FFU,
1074 0xF3FF01FFU, 0x0000000FU, 0x00000000U, 0x00000000U,
1075 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1076 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1077 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1078 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FFFFFFU,
1079 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1080 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1081 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1082 0xFFFFFFFFU, 0x000FFFFFU, 0x00000000U, 0x00000000U,
1083 0xFFFFFFFFU, 0xFFFF3FFFU, 0xFFFF007FU, 0xFFFFFFFFU,
1084 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000000FU, 0x00000000U,
1085 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1086 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x003FFFFFU,
1087 0xFFFFFFFFU, 0xFFFFFE7FU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1088 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000007FFU,
1089 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000003FU, 0x00000000U,
1090 0x00000000U, 0x00000000U, 0x000FFFFFU, 0x000FFFFFU,
1091 0xFFFFFFFFU, 0xFFFFFFFFU, 0x007FFFFFU, 0x01FFFFFFU,
1092 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1093 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFDFFFFFU, 0xFFFFFFFFU,
1094 0xDFFFFFFFU, 0xEBFFDE64U, 0xFFFFFFEFU, 0xFFFFFFFFU,
1095 0xDFDFE7BFU, 0x7BFFFFFFU, 0xFFFDFC5FU, 0xFFFFFFFFU,
1096 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1097 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1098 0xFFFFFFFFU, 0xFFFFFF3FU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1099 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1100 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFCFFFU, 0xFFFFFFFFU,
1101 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1102 0xF8000FFFU, 0x0000FFFEU, 0x00000000U, 0x00000000U,
1103 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1104 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1105 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1106 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1107 0x7FFFFFFFU, 0x000007E0U, 0x00000000U, 0x00000000U,
1108 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1109 0xF9FFFF7FU, 0xFFFF07DBU, 0xFFFFFFFFU, 0x00003FFFU,
1110 0x00008000U, 0x00000000U, 0x00000000U, 0x00000000U,
1111 0xFFFFFFFFU, 0x3FFF1FFFU, 0x0000C3FFU, 0x00000000U,
1112 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1113 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1114 0xFFFF0000U, 0x00007FFFU, 0xFFFFFFFFU, 0x83FFFFFFU,
1115 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1116 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1117 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1118 0x00000000U, 0x00000000U, 0xFFFF0000U, 0x03FFFFFFU,
1119 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1120 0x00000000U, 0x00000000U, 0xFFFF0000U, 0x87FFFFFFU,
1121 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1122 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1123 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1124 0x00000000U, 0x00000000U, 0x00000000U, 0x7FFF6F7FU,
1125 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1126 0xFFFFFFFFU, 0xFFFFFFFFU, 0x007FFF9FU, 0x00000000U,
1127 0xFFFFFFFFU, 0xFFFFFFFFU, 0xC3FF0FFFU, 0x00000000U,
1128 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1129 0x00000000U, 0x00000000U, 0x00000000U, 0xFFFE0000U,
1130 0xFFFFFFFFU, 0x001FFFFFU, 0x00000000U, 0x00000000U,
1131 0xFFFFFFFEU, 0x3FFFFFFFU, 0x00000000U, 0x00000000U,
1132 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1133 0xFFFFFFEFU, 0x0AF7FE96U, 0xAA96EA84U, 0x5EF7F796U,
1134 0x0FFFFBFFU, 0x0FFFFBEEU, 0x00000000U, 0x00030000U,
1135 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1136 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1137 0xFFFFFFFFU, 0xFFFF0FFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1138 0x000FFFFFU, 0xFFFE7FFFU, 0xFFFEFFFEU, 0x003FFFFFU,
1139 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1140 0xFFFFFFFFU, 0x00003FFFU, 0x00000000U, 0xFFFFFFC0U,
1141 0xFFFF0007U, 0x0FFFFFFFU, 0x000301FFU, 0x0000003FU,
1142 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1143 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1144 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1145 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1146 0xFFFFFFFFU, 0xFFFFFFFFU, 0xF0FFFFFFU, 0x1FFF1FFFU,
1147 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xF87FFFFFU,
1148 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FFFFFFU, 0x00010FFFU,
1149 0xFFFF0FFFU, 0xFFFFFFFFU, 0x03FF00FFU, 0xFFFFFFFFU,
1150 0xFFFF00FFU, 0x0FFF3FFFU, 0x00000003U, 0x00000000U,
1151 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1152 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1153 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000FFFFFU, 0x1FFF3FFFU,
1154 0xFFFF83FFU, 0xFFFFFFFFU, 0x9FFFC07FU, 0x01FF03FFU,
1155 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1156 0xFFF7FFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FFFFFFU,
1157 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1158 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000000U,
1159 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1160 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1161 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1162 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1163 0xFFFFFFFFU, 0x03FFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1164 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1165 0x3FFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1166 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1167 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1168 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1169 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1170 0xFFFFFFFFU, 0xFFFF0003U, 0xFFFFFFFFU, 0xFFFFFFFFU,
1171 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1172 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1173 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1174 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1175 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1176 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF0001U,
1177 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3FFFFFFFU, 0x00000000U,
1178 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1179 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1180 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1181 0x3FFFFFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
1182 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1183 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1184 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1185 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1186 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1187 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF07FFU, 0xFFFFFFFFU,
1188 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1189 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1190 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1191 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1192 0xFFFFFFFFU, 0x0000FFFFU, 0x00000000U, 0x00000000U,
1193 0x00000002U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1194 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1195 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1196 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000FFFFU,
1197 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1198 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1199 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1200 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3FFFFFFFU
1201 }
1202};
diff --git a/gl/unictype/ctype_lower.c b/gl/unictype/ctype_lower.c
new file mode 100644
index 00000000..99a05e09
--- /dev/null
+++ b/gl/unictype/ctype_lower.c
@@ -0,0 +1,32 @@
1/* ISO C <ctype.h> like properties of Unicode characters.
2 Copyright (C) 2002, 2006-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2002.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include "unictype.h"
22
23#include "bitmap.h"
24
25/* Define u_is_lower table. */
26#include "ctype_lower.h"
27
28bool
29uc_is_lower (ucs4_t uc)
30{
31 return bitmap_lookup (&u_is_lower, uc);
32}
diff --git a/gl/unictype/ctype_lower.h b/gl/unictype/ctype_lower.h
new file mode 100644
index 00000000..cbf7d26d
--- /dev/null
+++ b/gl/unictype/ctype_lower.h
@@ -0,0 +1,371 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* ISO C <ctype.h> like properties of Unicode characters. */
3/* Generated automatically by gen-uni-tables.c for Unicode 16.0.0. */
4
5/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
6
7 This file is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 This file is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19
20#define header_0 16
21#define header_2 9
22#define header_3 127
23#define header_4 15
24static const
25struct
26 {
27 int header[1];
28 int level1[2];
29 short level2[2 << 7];
30 unsigned int level3[18 << 4];
31 }
32u_is_lower =
33{
34 { 2 },
35 {
36 3 * sizeof (int) / sizeof (short) + 0,
37 3 * sizeof (int) / sizeof (short) + 128
38 },
39 {
40 3 + 256 * sizeof (short) / sizeof (int) + 0,
41 3 + 256 * sizeof (short) / sizeof (int) + 16,
42 3 + 256 * sizeof (short) / sizeof (int) + 32,
43 -1,
44 -1,
45 -1,
46 -1,
47 -1,
48 3 + 256 * sizeof (short) / sizeof (int) + 48,
49 3 + 256 * sizeof (short) / sizeof (int) + 64,
50 -1,
51 -1,
52 -1,
53 -1,
54 3 + 256 * sizeof (short) / sizeof (int) + 80,
55 3 + 256 * sizeof (short) / sizeof (int) + 96,
56 3 + 256 * sizeof (short) / sizeof (int) + 112,
57 -1,
58 3 + 256 * sizeof (short) / sizeof (int) + 128,
59 -1,
60 -1,
61 -1,
62 3 + 256 * sizeof (short) / sizeof (int) + 144,
63 -1,
64 -1,
65 -1,
66 -1,
67 -1,
68 -1,
69 -1,
70 -1,
71 -1,
72 -1,
73 -1,
74 -1,
75 -1,
76 -1,
77 -1,
78 -1,
79 -1,
80 -1,
81 -1,
82 -1,
83 -1,
84 -1,
85 -1,
86 -1,
87 -1,
88 -1,
89 -1,
90 -1,
91 -1,
92 -1,
93 -1,
94 -1,
95 -1,
96 -1,
97 -1,
98 -1,
99 -1,
100 -1,
101 -1,
102 -1,
103 -1,
104 -1,
105 -1,
106 -1,
107 -1,
108 -1,
109 -1,
110 -1,
111 -1,
112 -1,
113 -1,
114 -1,
115 -1,
116 -1,
117 -1,
118 -1,
119 -1,
120 -1,
121 -1,
122 -1,
123 3 + 256 * sizeof (short) / sizeof (int) + 160,
124 -1,
125 3 + 256 * sizeof (short) / sizeof (int) + 176,
126 -1,
127 -1,
128 -1,
129 -1,
130 -1,
131 -1,
132 -1,
133 -1,
134 -1,
135 -1,
136 -1,
137 -1,
138 -1,
139 -1,
140 -1,
141 -1,
142 -1,
143 -1,
144 -1,
145 -1,
146 -1,
147 -1,
148 -1,
149 -1,
150 -1,
151 -1,
152 -1,
153 -1,
154 -1,
155 -1,
156 -1,
157 -1,
158 -1,
159 -1,
160 -1,
161 -1,
162 -1,
163 -1,
164 -1,
165 -1,
166 -1,
167 3 + 256 * sizeof (short) / sizeof (int) + 192,
168 -1,
169 -1,
170 3 + 256 * sizeof (short) / sizeof (int) + 208,
171 -1,
172 -1,
173 -1,
174 3 + 256 * sizeof (short) / sizeof (int) + 224,
175 -1,
176 -1,
177 -1,
178 -1,
179 -1,
180 3 + 256 * sizeof (short) / sizeof (int) + 240,
181 -1,
182 -1,
183 -1,
184 -1,
185 -1,
186 -1,
187 -1,
188 -1,
189 -1,
190 -1,
191 -1,
192 -1,
193 -1,
194 -1,
195 -1,
196 -1,
197 -1,
198 -1,
199 -1,
200 -1,
201 -1,
202 -1,
203 -1,
204 -1,
205 -1,
206 -1,
207 -1,
208 -1,
209 -1,
210 -1,
211 -1,
212 -1,
213 -1,
214 -1,
215 -1,
216 -1,
217 -1,
218 -1,
219 -1,
220 -1,
221 -1,
222 -1,
223 3 + 256 * sizeof (short) / sizeof (int) + 256,
224 -1,
225 -1,
226 -1,
227 -1,
228 -1,
229 -1,
230 -1,
231 -1,
232 -1,
233 -1,
234 -1,
235 -1,
236 -1,
237 -1,
238 -1,
239 -1,
240 -1,
241 -1,
242 -1,
243 -1,
244 -1,
245 -1,
246 -1,
247 -1,
248 -1,
249 -1,
250 -1,
251 -1,
252 -1,
253 -1,
254 -1,
255 -1,
256 -1,
257 -1,
258 -1,
259 -1,
260 -1,
261 -1,
262 -1,
263 -1,
264 -1,
265 -1,
266 -1,
267 -1,
268 -1,
269 -1,
270 -1,
271 -1,
272 -1,
273 -1,
274 -1,
275 -1,
276 -1,
277 -1,
278 -1,
279 -1,
280 -1,
281 -1,
282 -1,
283 -1,
284 3 + 256 * sizeof (short) / sizeof (int) + 272,
285 -1,
286 -1,
287 -1,
288 -1,
289 -1,
290 -1,
291 -1,
292 -1,
293 -1,
294 -1,
295 -1
296 },
297 {
298 0x00000000U, 0x00000000U, 0x00000000U, 0x07FFFFFEU,
299 0x00000000U, 0x00200000U, 0x80000000U, 0xFF7FFFFFU,
300 0xAAAAAAAAU, 0x54AAAAAAU, 0xAAAAA955U, 0xD4AAAAAAU,
301 0x4E241129U, 0xA251212AU, 0xB5555B60U, 0xAA2CAAAAU,
302 0xAAAAAAAAU, 0x900AAAA8U, 0x1ADFAA85U, 0x20269F7BU,
303 0x60041F8DU, 0x00000000U, 0x00000000U, 0x00000000U,
304 0x00000000U, 0x00000000U, 0x00000020U, 0x388A0000U,
305 0x00000000U, 0xFFFEF000U, 0xAAE37FFFU, 0x092FAAAAU,
306 0x00000000U, 0xFFFF0000U, 0xFFFFFFFFU, 0xAAAAAAAAU,
307 0xAAAAA802U, 0xAAAAAAAAU, 0xAAAAD554U, 0xAAAAAAAAU,
308 0xAAAAAAAAU, 0x0000AAAAU, 0x00000000U, 0xFFFFFFFEU,
309 0x0000007FU, 0x00000000U, 0x00000000U, 0x00000000U,
310 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
311 0x00000000U, 0x00000000U, 0xFFFF0000U, 0xE7FFFFFFU,
312 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
313 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
314 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
315 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
316 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
317 0x00000000U, 0x00000000U, 0x00000000U, 0x3F000000U,
318 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
319 0x000005FFU, 0x00000000U, 0x00000000U, 0x00000000U,
320 0x00000000U, 0x00000000U, 0x00000000U, 0x22000000U,
321 0x00004000U, 0x00000000U, 0x00000000U, 0x00000000U,
322 0xAAAAAAAAU, 0xAAAAAAAAU, 0xAAAAAAAAU, 0xAAAAAAAAU,
323 0x082AAAAAU, 0xAAAAAAAAU, 0xAAAAAAAAU, 0xAAAAAAAAU,
324 0x003F00FFU, 0x00FF00FFU, 0x00AA003FU, 0x3FFF00FFU,
325 0x00FF00FFU, 0x400B00FFU, 0x00030008U, 0x00080023U,
326 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
327 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
328 0x00000000U, 0x00000000U, 0x00004000U, 0xFFFF0000U,
329 0x00000010U, 0x00000000U, 0x00000000U, 0x00000000U,
330 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
331 0x00000000U, 0x00000000U, 0xFFFF0000U, 0x000003FFU,
332 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
333 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
334 0x00000000U, 0xFFFF0000U, 0xFFFFFFFFU, 0x00481562U,
335 0xAAAAAAAAU, 0xAAAAAAAAU, 0xAAAAAAAAU, 0x0008500AU,
336 0xFFFFFFFFU, 0x000020BFU, 0x00000000U, 0x00000000U,
337 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
338 0x00000000U, 0x00000000U, 0xAAAAAAAAU, 0x00002AAAU,
339 0x0AAAAAAAU, 0x00000000U, 0x00000000U, 0x00000000U,
340 0x00000000U, 0xAAA8AAA8U, 0xAAAAAAAAU, 0x9400AAAAU,
341 0xAA9A10AAU, 0xAAA002AAU, 0x0A82250AU, 0x00400000U,
342 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
343 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
344 0x00000000U, 0x00000000U, 0x00080000U, 0xFFFF0000U,
345 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000000U, 0x00000000U,
346 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
347 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
348 0x00000000U, 0x00000000U, 0x07FFFFFEU, 0x00000000U,
349 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
350 0x00000000U, 0xFFFFFF00U, 0x0000FFFFU, 0x00000000U,
351 0x00000000U, 0x00000000U, 0xFF000000U, 0x0FFFFFFFU,
352 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
353 0xFF800000U, 0x1BFBFFFBU, 0x00000000U, 0x00000000U,
354 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
355 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0x0007FFFFU,
356 0x00000000U, 0x00000000U, 0x00000000U, 0xFFFF0000U,
357 0x0000003FU, 0x00000000U, 0x00000000U, 0x00000000U,
358 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
359 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0x00000000U,
360 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
361 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
362 0x00000000U, 0x00000000U, 0x00000000U, 0xFFFFFFFFU,
363 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
364 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
365 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
366 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
367 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
368 0x00000000U, 0xFFFFFFFCU, 0x0000000FU, 0x00000000U,
369 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U
370 }
371};
diff --git a/gl/unictype/ctype_print.c b/gl/unictype/ctype_print.c
new file mode 100644
index 00000000..0197d496
--- /dev/null
+++ b/gl/unictype/ctype_print.c
@@ -0,0 +1,32 @@
1/* ISO C <ctype.h> like properties of Unicode characters.
2 Copyright (C) 2002, 2006-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2002.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include "unictype.h"
22
23#include "bitmap.h"
24
25/* Define u_is_print table. */
26#include "ctype_print.h"
27
28bool
29uc_is_print (ucs4_t uc)
30{
31 return bitmap_lookup (&u_is_print, uc);
32}
diff --git a/gl/unictype/ctype_print.h b/gl/unictype/ctype_print.h
new file mode 100644
index 00000000..b7007828
--- /dev/null
+++ b/gl/unictype/ctype_print.h
@@ -0,0 +1,1202 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* ISO C <ctype.h> like properties of Unicode characters. */
3/* Generated automatically by gen-uni-tables.c for Unicode 16.0.0. */
4
5/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
6
7 This file is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 This file is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19
20#define header_0 16
21#define header_2 9
22#define header_3 127
23#define header_4 15
24static const
25struct
26 {
27 int header[1];
28 int level1[17];
29 short level2[6 << 7];
30 unsigned int level3[94 << 4];
31 }
32u_is_print =
33{
34 { 17 },
35 {
36 18 * sizeof (int) / sizeof (short) + 0,
37 18 * sizeof (int) / sizeof (short) + 128,
38 18 * sizeof (int) / sizeof (short) + 256,
39 18 * sizeof (int) / sizeof (short) + 384,
40 -1,
41 -1,
42 -1,
43 -1,
44 -1,
45 -1,
46 -1,
47 -1,
48 -1,
49 -1,
50 18 * sizeof (int) / sizeof (short) + 512,
51 18 * sizeof (int) / sizeof (short) + 640,
52 18 * sizeof (int) / sizeof (short) + 640
53 },
54 {
55 18 + 768 * sizeof (short) / sizeof (int) + 0,
56 18 + 768 * sizeof (short) / sizeof (int) + 16,
57 18 + 768 * sizeof (short) / sizeof (int) + 32,
58 18 + 768 * sizeof (short) / sizeof (int) + 48,
59 18 + 768 * sizeof (short) / sizeof (int) + 64,
60 18 + 768 * sizeof (short) / sizeof (int) + 80,
61 18 + 768 * sizeof (short) / sizeof (int) + 96,
62 18 + 768 * sizeof (short) / sizeof (int) + 112,
63 18 + 768 * sizeof (short) / sizeof (int) + 128,
64 18 + 768 * sizeof (short) / sizeof (int) + 144,
65 18 + 768 * sizeof (short) / sizeof (int) + 160,
66 18 + 768 * sizeof (short) / sizeof (int) + 176,
67 18 + 768 * sizeof (short) / sizeof (int) + 192,
68 18 + 768 * sizeof (short) / sizeof (int) + 208,
69 18 + 768 * sizeof (short) / sizeof (int) + 224,
70 18 + 768 * sizeof (short) / sizeof (int) + 240,
71 18 + 768 * sizeof (short) / sizeof (int) + 256,
72 18 + 768 * sizeof (short) / sizeof (int) + 160,
73 18 + 768 * sizeof (short) / sizeof (int) + 272,
74 18 + 768 * sizeof (short) / sizeof (int) + 160,
75 18 + 768 * sizeof (short) / sizeof (int) + 160,
76 18 + 768 * sizeof (short) / sizeof (int) + 288,
77 18 + 768 * sizeof (short) / sizeof (int) + 304,
78 18 + 768 * sizeof (short) / sizeof (int) + 320,
79 18 + 768 * sizeof (short) / sizeof (int) + 336,
80 18 + 768 * sizeof (short) / sizeof (int) + 352,
81 18 + 768 * sizeof (short) / sizeof (int) + 160,
82 18 + 768 * sizeof (short) / sizeof (int) + 160,
83 18 + 768 * sizeof (short) / sizeof (int) + 160,
84 18 + 768 * sizeof (short) / sizeof (int) + 160,
85 18 + 768 * sizeof (short) / sizeof (int) + 160,
86 18 + 768 * sizeof (short) / sizeof (int) + 160,
87 18 + 768 * sizeof (short) / sizeof (int) + 160,
88 18 + 768 * sizeof (short) / sizeof (int) + 160,
89 18 + 768 * sizeof (short) / sizeof (int) + 160,
90 18 + 768 * sizeof (short) / sizeof (int) + 160,
91 18 + 768 * sizeof (short) / sizeof (int) + 160,
92 18 + 768 * sizeof (short) / sizeof (int) + 160,
93 18 + 768 * sizeof (short) / sizeof (int) + 160,
94 18 + 768 * sizeof (short) / sizeof (int) + 160,
95 18 + 768 * sizeof (short) / sizeof (int) + 160,
96 18 + 768 * sizeof (short) / sizeof (int) + 160,
97 18 + 768 * sizeof (short) / sizeof (int) + 160,
98 18 + 768 * sizeof (short) / sizeof (int) + 160,
99 18 + 768 * sizeof (short) / sizeof (int) + 160,
100 18 + 768 * sizeof (short) / sizeof (int) + 160,
101 18 + 768 * sizeof (short) / sizeof (int) + 160,
102 18 + 768 * sizeof (short) / sizeof (int) + 160,
103 18 + 768 * sizeof (short) / sizeof (int) + 160,
104 18 + 768 * sizeof (short) / sizeof (int) + 160,
105 18 + 768 * sizeof (short) / sizeof (int) + 160,
106 18 + 768 * sizeof (short) / sizeof (int) + 160,
107 18 + 768 * sizeof (short) / sizeof (int) + 160,
108 18 + 768 * sizeof (short) / sizeof (int) + 160,
109 18 + 768 * sizeof (short) / sizeof (int) + 160,
110 18 + 768 * sizeof (short) / sizeof (int) + 160,
111 18 + 768 * sizeof (short) / sizeof (int) + 160,
112 18 + 768 * sizeof (short) / sizeof (int) + 160,
113 18 + 768 * sizeof (short) / sizeof (int) + 160,
114 18 + 768 * sizeof (short) / sizeof (int) + 160,
115 18 + 768 * sizeof (short) / sizeof (int) + 160,
116 18 + 768 * sizeof (short) / sizeof (int) + 160,
117 18 + 768 * sizeof (short) / sizeof (int) + 160,
118 18 + 768 * sizeof (short) / sizeof (int) + 160,
119 18 + 768 * sizeof (short) / sizeof (int) + 160,
120 18 + 768 * sizeof (short) / sizeof (int) + 160,
121 18 + 768 * sizeof (short) / sizeof (int) + 160,
122 18 + 768 * sizeof (short) / sizeof (int) + 160,
123 18 + 768 * sizeof (short) / sizeof (int) + 160,
124 18 + 768 * sizeof (short) / sizeof (int) + 160,
125 18 + 768 * sizeof (short) / sizeof (int) + 160,
126 18 + 768 * sizeof (short) / sizeof (int) + 160,
127 18 + 768 * sizeof (short) / sizeof (int) + 160,
128 18 + 768 * sizeof (short) / sizeof (int) + 160,
129 18 + 768 * sizeof (short) / sizeof (int) + 160,
130 18 + 768 * sizeof (short) / sizeof (int) + 160,
131 18 + 768 * sizeof (short) / sizeof (int) + 160,
132 18 + 768 * sizeof (short) / sizeof (int) + 160,
133 18 + 768 * sizeof (short) / sizeof (int) + 160,
134 18 + 768 * sizeof (short) / sizeof (int) + 160,
135 18 + 768 * sizeof (short) / sizeof (int) + 160,
136 18 + 768 * sizeof (short) / sizeof (int) + 160,
137 18 + 768 * sizeof (short) / sizeof (int) + 368,
138 18 + 768 * sizeof (short) / sizeof (int) + 384,
139 18 + 768 * sizeof (short) / sizeof (int) + 400,
140 18 + 768 * sizeof (short) / sizeof (int) + 416,
141 18 + 768 * sizeof (short) / sizeof (int) + 160,
142 18 + 768 * sizeof (short) / sizeof (int) + 160,
143 18 + 768 * sizeof (short) / sizeof (int) + 160,
144 18 + 768 * sizeof (short) / sizeof (int) + 160,
145 18 + 768 * sizeof (short) / sizeof (int) + 160,
146 18 + 768 * sizeof (short) / sizeof (int) + 160,
147 18 + 768 * sizeof (short) / sizeof (int) + 160,
148 18 + 768 * sizeof (short) / sizeof (int) + 160,
149 18 + 768 * sizeof (short) / sizeof (int) + 160,
150 18 + 768 * sizeof (short) / sizeof (int) + 160,
151 18 + 768 * sizeof (short) / sizeof (int) + 160,
152 18 + 768 * sizeof (short) / sizeof (int) + 160,
153 18 + 768 * sizeof (short) / sizeof (int) + 160,
154 18 + 768 * sizeof (short) / sizeof (int) + 160,
155 18 + 768 * sizeof (short) / sizeof (int) + 160,
156 18 + 768 * sizeof (short) / sizeof (int) + 160,
157 18 + 768 * sizeof (short) / sizeof (int) + 160,
158 18 + 768 * sizeof (short) / sizeof (int) + 160,
159 18 + 768 * sizeof (short) / sizeof (int) + 160,
160 18 + 768 * sizeof (short) / sizeof (int) + 160,
161 18 + 768 * sizeof (short) / sizeof (int) + 160,
162 18 + 768 * sizeof (short) / sizeof (int) + 432,
163 -1,
164 -1,
165 -1,
166 -1,
167 18 + 768 * sizeof (short) / sizeof (int) + 160,
168 18 + 768 * sizeof (short) / sizeof (int) + 160,
169 18 + 768 * sizeof (short) / sizeof (int) + 160,
170 18 + 768 * sizeof (short) / sizeof (int) + 160,
171 18 + 768 * sizeof (short) / sizeof (int) + 160,
172 18 + 768 * sizeof (short) / sizeof (int) + 160,
173 18 + 768 * sizeof (short) / sizeof (int) + 160,
174 18 + 768 * sizeof (short) / sizeof (int) + 160,
175 18 + 768 * sizeof (short) / sizeof (int) + 160,
176 18 + 768 * sizeof (short) / sizeof (int) + 160,
177 18 + 768 * sizeof (short) / sizeof (int) + 160,
178 18 + 768 * sizeof (short) / sizeof (int) + 160,
179 18 + 768 * sizeof (short) / sizeof (int) + 160,
180 18 + 768 * sizeof (short) / sizeof (int) + 448,
181 18 + 768 * sizeof (short) / sizeof (int) + 464,
182 18 + 768 * sizeof (short) / sizeof (int) + 480,
183 18 + 768 * sizeof (short) / sizeof (int) + 496,
184 18 + 768 * sizeof (short) / sizeof (int) + 512,
185 18 + 768 * sizeof (short) / sizeof (int) + 528,
186 18 + 768 * sizeof (short) / sizeof (int) + 544,
187 18 + 768 * sizeof (short) / sizeof (int) + 560,
188 18 + 768 * sizeof (short) / sizeof (int) + 576,
189 18 + 768 * sizeof (short) / sizeof (int) + 592,
190 18 + 768 * sizeof (short) / sizeof (int) + 608,
191 18 + 768 * sizeof (short) / sizeof (int) + 624,
192 18 + 768 * sizeof (short) / sizeof (int) + 640,
193 18 + 768 * sizeof (short) / sizeof (int) + 656,
194 18 + 768 * sizeof (short) / sizeof (int) + 672,
195 18 + 768 * sizeof (short) / sizeof (int) + 688,
196 18 + 768 * sizeof (short) / sizeof (int) + 704,
197 18 + 768 * sizeof (short) / sizeof (int) + 720,
198 18 + 768 * sizeof (short) / sizeof (int) + 736,
199 18 + 768 * sizeof (short) / sizeof (int) + 160,
200 18 + 768 * sizeof (short) / sizeof (int) + 752,
201 18 + 768 * sizeof (short) / sizeof (int) + 768,
202 -1,
203 -1,
204 -1,
205 -1,
206 18 + 768 * sizeof (short) / sizeof (int) + 784,
207 18 + 768 * sizeof (short) / sizeof (int) + 160,
208 18 + 768 * sizeof (short) / sizeof (int) + 160,
209 18 + 768 * sizeof (short) / sizeof (int) + 800,
210 18 + 768 * sizeof (short) / sizeof (int) + 160,
211 18 + 768 * sizeof (short) / sizeof (int) + 160,
212 18 + 768 * sizeof (short) / sizeof (int) + 160,
213 18 + 768 * sizeof (short) / sizeof (int) + 160,
214 18 + 768 * sizeof (short) / sizeof (int) + 160,
215 18 + 768 * sizeof (short) / sizeof (int) + 160,
216 18 + 768 * sizeof (short) / sizeof (int) + 816,
217 18 + 768 * sizeof (short) / sizeof (int) + 160,
218 18 + 768 * sizeof (short) / sizeof (int) + 832,
219 -1,
220 -1,
221 -1,
222 -1,
223 -1,
224 -1,
225 -1,
226 -1,
227 -1,
228 -1,
229 -1,
230 -1,
231 18 + 768 * sizeof (short) / sizeof (int) + 848,
232 -1,
233 -1,
234 -1,
235 18 + 768 * sizeof (short) / sizeof (int) + 160,
236 18 + 768 * sizeof (short) / sizeof (int) + 864,
237 18 + 768 * sizeof (short) / sizeof (int) + 880,
238 18 + 768 * sizeof (short) / sizeof (int) + 896,
239 18 + 768 * sizeof (short) / sizeof (int) + 160,
240 18 + 768 * sizeof (short) / sizeof (int) + 160,
241 18 + 768 * sizeof (short) / sizeof (int) + 160,
242 18 + 768 * sizeof (short) / sizeof (int) + 160,
243 18 + 768 * sizeof (short) / sizeof (int) + 160,
244 18 + 768 * sizeof (short) / sizeof (int) + 160,
245 18 + 768 * sizeof (short) / sizeof (int) + 160,
246 18 + 768 * sizeof (short) / sizeof (int) + 160,
247 18 + 768 * sizeof (short) / sizeof (int) + 160,
248 18 + 768 * sizeof (short) / sizeof (int) + 160,
249 18 + 768 * sizeof (short) / sizeof (int) + 160,
250 18 + 768 * sizeof (short) / sizeof (int) + 912,
251 18 + 768 * sizeof (short) / sizeof (int) + 160,
252 18 + 768 * sizeof (short) / sizeof (int) + 160,
253 18 + 768 * sizeof (short) / sizeof (int) + 928,
254 -1,
255 -1,
256 -1,
257 -1,
258 -1,
259 -1,
260 -1,
261 -1,
262 -1,
263 -1,
264 -1,
265 -1,
266 -1,
267 -1,
268 -1,
269 -1,
270 18 + 768 * sizeof (short) / sizeof (int) + 944,
271 18 + 768 * sizeof (short) / sizeof (int) + 960,
272 18 + 768 * sizeof (short) / sizeof (int) + 976,
273 -1,
274 -1,
275 -1,
276 -1,
277 18 + 768 * sizeof (short) / sizeof (int) + 992,
278 -1,
279 -1,
280 -1,
281 -1,
282 -1,
283 -1,
284 -1,
285 18 + 768 * sizeof (short) / sizeof (int) + 1008,
286 18 + 768 * sizeof (short) / sizeof (int) + 1024,
287 18 + 768 * sizeof (short) / sizeof (int) + 1040,
288 18 + 768 * sizeof (short) / sizeof (int) + 1056,
289 18 + 768 * sizeof (short) / sizeof (int) + 1072,
290 18 + 768 * sizeof (short) / sizeof (int) + 1088,
291 18 + 768 * sizeof (short) / sizeof (int) + 160,
292 18 + 768 * sizeof (short) / sizeof (int) + 1104,
293 -1,
294 18 + 768 * sizeof (short) / sizeof (int) + 1120,
295 18 + 768 * sizeof (short) / sizeof (int) + 1136,
296 18 + 768 * sizeof (short) / sizeof (int) + 1152,
297 18 + 768 * sizeof (short) / sizeof (int) + 1168,
298 18 + 768 * sizeof (short) / sizeof (int) + 1184,
299 18 + 768 * sizeof (short) / sizeof (int) + 1200,
300 -1,
301 18 + 768 * sizeof (short) / sizeof (int) + 1216,
302 18 + 768 * sizeof (short) / sizeof (int) + 1232,
303 18 + 768 * sizeof (short) / sizeof (int) + 1248,
304 18 + 768 * sizeof (short) / sizeof (int) + 1264,
305 18 + 768 * sizeof (short) / sizeof (int) + 160,
306 18 + 768 * sizeof (short) / sizeof (int) + 1280,
307 18 + 768 * sizeof (short) / sizeof (int) + 1296,
308 18 + 768 * sizeof (short) / sizeof (int) + 1312,
309 -1,
310 -1,
311 18 + 768 * sizeof (short) / sizeof (int) + 160,
312 18 + 768 * sizeof (short) / sizeof (int) + 160,
313 18 + 768 * sizeof (short) / sizeof (int) + 160,
314 18 + 768 * sizeof (short) / sizeof (int) + 160,
315 18 + 768 * sizeof (short) / sizeof (int) + 160,
316 18 + 768 * sizeof (short) / sizeof (int) + 160,
317 18 + 768 * sizeof (short) / sizeof (int) + 160,
318 18 + 768 * sizeof (short) / sizeof (int) + 160,
319 18 + 768 * sizeof (short) / sizeof (int) + 160,
320 18 + 768 * sizeof (short) / sizeof (int) + 160,
321 18 + 768 * sizeof (short) / sizeof (int) + 160,
322 18 + 768 * sizeof (short) / sizeof (int) + 160,
323 18 + 768 * sizeof (short) / sizeof (int) + 160,
324 18 + 768 * sizeof (short) / sizeof (int) + 160,
325 18 + 768 * sizeof (short) / sizeof (int) + 160,
326 18 + 768 * sizeof (short) / sizeof (int) + 160,
327 18 + 768 * sizeof (short) / sizeof (int) + 160,
328 18 + 768 * sizeof (short) / sizeof (int) + 160,
329 18 + 768 * sizeof (short) / sizeof (int) + 160,
330 18 + 768 * sizeof (short) / sizeof (int) + 160,
331 18 + 768 * sizeof (short) / sizeof (int) + 160,
332 18 + 768 * sizeof (short) / sizeof (int) + 160,
333 18 + 768 * sizeof (short) / sizeof (int) + 160,
334 18 + 768 * sizeof (short) / sizeof (int) + 160,
335 18 + 768 * sizeof (short) / sizeof (int) + 160,
336 18 + 768 * sizeof (short) / sizeof (int) + 160,
337 18 + 768 * sizeof (short) / sizeof (int) + 160,
338 18 + 768 * sizeof (short) / sizeof (int) + 160,
339 18 + 768 * sizeof (short) / sizeof (int) + 160,
340 18 + 768 * sizeof (short) / sizeof (int) + 160,
341 18 + 768 * sizeof (short) / sizeof (int) + 160,
342 18 + 768 * sizeof (short) / sizeof (int) + 160,
343 18 + 768 * sizeof (short) / sizeof (int) + 160,
344 18 + 768 * sizeof (short) / sizeof (int) + 160,
345 18 + 768 * sizeof (short) / sizeof (int) + 160,
346 18 + 768 * sizeof (short) / sizeof (int) + 160,
347 18 + 768 * sizeof (short) / sizeof (int) + 160,
348 18 + 768 * sizeof (short) / sizeof (int) + 160,
349 18 + 768 * sizeof (short) / sizeof (int) + 160,
350 18 + 768 * sizeof (short) / sizeof (int) + 160,
351 18 + 768 * sizeof (short) / sizeof (int) + 160,
352 18 + 768 * sizeof (short) / sizeof (int) + 160,
353 18 + 768 * sizeof (short) / sizeof (int) + 160,
354 18 + 768 * sizeof (short) / sizeof (int) + 160,
355 18 + 768 * sizeof (short) / sizeof (int) + 160,
356 18 + 768 * sizeof (short) / sizeof (int) + 160,
357 18 + 768 * sizeof (short) / sizeof (int) + 160,
358 18 + 768 * sizeof (short) / sizeof (int) + 160,
359 18 + 768 * sizeof (short) / sizeof (int) + 160,
360 18 + 768 * sizeof (short) / sizeof (int) + 160,
361 18 + 768 * sizeof (short) / sizeof (int) + 160,
362 18 + 768 * sizeof (short) / sizeof (int) + 160,
363 18 + 768 * sizeof (short) / sizeof (int) + 160,
364 18 + 768 * sizeof (short) / sizeof (int) + 160,
365 18 + 768 * sizeof (short) / sizeof (int) + 160,
366 18 + 768 * sizeof (short) / sizeof (int) + 160,
367 18 + 768 * sizeof (short) / sizeof (int) + 160,
368 18 + 768 * sizeof (short) / sizeof (int) + 160,
369 18 + 768 * sizeof (short) / sizeof (int) + 160,
370 18 + 768 * sizeof (short) / sizeof (int) + 160,
371 18 + 768 * sizeof (short) / sizeof (int) + 160,
372 18 + 768 * sizeof (short) / sizeof (int) + 160,
373 18 + 768 * sizeof (short) / sizeof (int) + 160,
374 18 + 768 * sizeof (short) / sizeof (int) + 160,
375 18 + 768 * sizeof (short) / sizeof (int) + 160,
376 18 + 768 * sizeof (short) / sizeof (int) + 160,
377 18 + 768 * sizeof (short) / sizeof (int) + 160,
378 18 + 768 * sizeof (short) / sizeof (int) + 160,
379 18 + 768 * sizeof (short) / sizeof (int) + 160,
380 18 + 768 * sizeof (short) / sizeof (int) + 160,
381 18 + 768 * sizeof (short) / sizeof (int) + 160,
382 18 + 768 * sizeof (short) / sizeof (int) + 160,
383 18 + 768 * sizeof (short) / sizeof (int) + 160,
384 18 + 768 * sizeof (short) / sizeof (int) + 160,
385 18 + 768 * sizeof (short) / sizeof (int) + 160,
386 18 + 768 * sizeof (short) / sizeof (int) + 160,
387 18 + 768 * sizeof (short) / sizeof (int) + 160,
388 18 + 768 * sizeof (short) / sizeof (int) + 160,
389 18 + 768 * sizeof (short) / sizeof (int) + 160,
390 18 + 768 * sizeof (short) / sizeof (int) + 160,
391 18 + 768 * sizeof (short) / sizeof (int) + 160,
392 18 + 768 * sizeof (short) / sizeof (int) + 160,
393 18 + 768 * sizeof (short) / sizeof (int) + 160,
394 18 + 768 * sizeof (short) / sizeof (int) + 1328,
395 18 + 768 * sizeof (short) / sizeof (int) + 160,
396 18 + 768 * sizeof (short) / sizeof (int) + 160,
397 18 + 768 * sizeof (short) / sizeof (int) + 160,
398 18 + 768 * sizeof (short) / sizeof (int) + 160,
399 18 + 768 * sizeof (short) / sizeof (int) + 160,
400 18 + 768 * sizeof (short) / sizeof (int) + 160,
401 18 + 768 * sizeof (short) / sizeof (int) + 160,
402 18 + 768 * sizeof (short) / sizeof (int) + 1344,
403 18 + 768 * sizeof (short) / sizeof (int) + 1360,
404 18 + 768 * sizeof (short) / sizeof (int) + 160,
405 18 + 768 * sizeof (short) / sizeof (int) + 160,
406 18 + 768 * sizeof (short) / sizeof (int) + 160,
407 18 + 768 * sizeof (short) / sizeof (int) + 160,
408 18 + 768 * sizeof (short) / sizeof (int) + 160,
409 18 + 768 * sizeof (short) / sizeof (int) + 160,
410 18 + 768 * sizeof (short) / sizeof (int) + 160,
411 18 + 768 * sizeof (short) / sizeof (int) + 160,
412 18 + 768 * sizeof (short) / sizeof (int) + 160,
413 18 + 768 * sizeof (short) / sizeof (int) + 160,
414 18 + 768 * sizeof (short) / sizeof (int) + 1376,
415 18 + 768 * sizeof (short) / sizeof (int) + 160,
416 18 + 768 * sizeof (short) / sizeof (int) + 160,
417 18 + 768 * sizeof (short) / sizeof (int) + 160,
418 18 + 768 * sizeof (short) / sizeof (int) + 160,
419 18 + 768 * sizeof (short) / sizeof (int) + 160,
420 18 + 768 * sizeof (short) / sizeof (int) + 160,
421 18 + 768 * sizeof (short) / sizeof (int) + 160,
422 18 + 768 * sizeof (short) / sizeof (int) + 160,
423 18 + 768 * sizeof (short) / sizeof (int) + 160,
424 18 + 768 * sizeof (short) / sizeof (int) + 160,
425 18 + 768 * sizeof (short) / sizeof (int) + 160,
426 18 + 768 * sizeof (short) / sizeof (int) + 160,
427 18 + 768 * sizeof (short) / sizeof (int) + 160,
428 18 + 768 * sizeof (short) / sizeof (int) + 1392,
429 18 + 768 * sizeof (short) / sizeof (int) + 160,
430 18 + 768 * sizeof (short) / sizeof (int) + 1408,
431 -1,
432 -1,
433 -1,
434 -1,
435 18 + 768 * sizeof (short) / sizeof (int) + 160,
436 18 + 768 * sizeof (short) / sizeof (int) + 1424,
437 -1,
438 -1,
439 18 + 768 * sizeof (short) / sizeof (int) + 160,
440 18 + 768 * sizeof (short) / sizeof (int) + 160,
441 18 + 768 * sizeof (short) / sizeof (int) + 160,
442 18 + 768 * sizeof (short) / sizeof (int) + 160,
443 18 + 768 * sizeof (short) / sizeof (int) + 160,
444 18 + 768 * sizeof (short) / sizeof (int) + 160,
445 18 + 768 * sizeof (short) / sizeof (int) + 160,
446 18 + 768 * sizeof (short) / sizeof (int) + 160,
447 18 + 768 * sizeof (short) / sizeof (int) + 160,
448 18 + 768 * sizeof (short) / sizeof (int) + 1440,
449 18 + 768 * sizeof (short) / sizeof (int) + 160,
450 18 + 768 * sizeof (short) / sizeof (int) + 160,
451 18 + 768 * sizeof (short) / sizeof (int) + 160,
452 18 + 768 * sizeof (short) / sizeof (int) + 160,
453 18 + 768 * sizeof (short) / sizeof (int) + 160,
454 18 + 768 * sizeof (short) / sizeof (int) + 160,
455 18 + 768 * sizeof (short) / sizeof (int) + 160,
456 18 + 768 * sizeof (short) / sizeof (int) + 1456,
457 -1,
458 -1,
459 -1,
460 -1,
461 -1,
462 -1,
463 -1,
464 -1,
465 -1,
466 -1,
467 -1,
468 -1,
469 -1,
470 -1,
471 -1,
472 -1,
473 -1,
474 -1,
475 -1,
476 -1,
477 -1,
478 -1,
479 -1,
480 -1,
481 -1,
482 -1,
483 -1,
484 -1,
485 -1,
486 -1,
487 -1,
488 -1,
489 -1,
490 -1,
491 -1,
492 -1,
493 -1,
494 -1,
495 -1,
496 -1,
497 -1,
498 -1,
499 -1,
500 -1,
501 -1,
502 -1,
503 -1,
504 -1,
505 -1,
506 -1,
507 -1,
508 -1,
509 -1,
510 -1,
511 -1,
512 -1,
513 -1,
514 -1,
515 -1,
516 -1,
517 -1,
518 -1,
519 -1,
520 -1,
521 -1,
522 -1,
523 -1,
524 -1,
525 -1,
526 -1,
527 -1,
528 -1,
529 -1,
530 -1,
531 -1,
532 -1,
533 -1,
534 -1,
535 -1,
536 -1,
537 -1,
538 -1,
539 -1,
540 -1,
541 -1,
542 -1,
543 -1,
544 -1,
545 -1,
546 -1,
547 -1,
548 -1,
549 -1,
550 -1,
551 -1,
552 -1,
553 -1,
554 -1,
555 -1,
556 -1,
557 -1,
558 -1,
559 -1,
560 -1,
561 -1,
562 -1,
563 -1,
564 -1,
565 -1,
566 -1,
567 18 + 768 * sizeof (short) / sizeof (int) + 1472,
568 -1,
569 -1,
570 -1,
571 -1,
572 -1,
573 -1,
574 -1,
575 -1,
576 -1,
577 -1,
578 -1,
579 -1,
580 -1,
581 -1,
582 -1,
583 -1,
584 -1,
585 -1,
586 -1,
587 -1,
588 -1,
589 -1,
590 -1,
591 -1,
592 -1,
593 -1,
594 -1,
595 -1,
596 -1,
597 -1,
598 -1,
599 -1,
600 -1,
601 -1,
602 -1,
603 -1,
604 -1,
605 -1,
606 -1,
607 -1,
608 -1,
609 -1,
610 -1,
611 -1,
612 -1,
613 -1,
614 -1,
615 -1,
616 -1,
617 -1,
618 -1,
619 -1,
620 -1,
621 -1,
622 -1,
623 -1,
624 -1,
625 -1,
626 -1,
627 -1,
628 -1,
629 -1,
630 -1,
631 -1,
632 -1,
633 -1,
634 -1,
635 -1,
636 -1,
637 -1,
638 -1,
639 -1,
640 -1,
641 -1,
642 -1,
643 -1,
644 -1,
645 -1,
646 -1,
647 -1,
648 -1,
649 -1,
650 -1,
651 -1,
652 -1,
653 -1,
654 -1,
655 -1,
656 -1,
657 -1,
658 -1,
659 -1,
660 -1,
661 -1,
662 -1,
663 -1,
664 -1,
665 -1,
666 -1,
667 -1,
668 -1,
669 -1,
670 -1,
671 -1,
672 -1,
673 -1,
674 -1,
675 -1,
676 -1,
677 -1,
678 -1,
679 -1,
680 -1,
681 -1,
682 -1,
683 -1,
684 -1,
685 -1,
686 -1,
687 -1,
688 -1,
689 -1,
690 -1,
691 -1,
692 -1,
693 -1,
694 -1,
695 18 + 768 * sizeof (short) / sizeof (int) + 160,
696 18 + 768 * sizeof (short) / sizeof (int) + 160,
697 18 + 768 * sizeof (short) / sizeof (int) + 160,
698 18 + 768 * sizeof (short) / sizeof (int) + 160,
699 18 + 768 * sizeof (short) / sizeof (int) + 160,
700 18 + 768 * sizeof (short) / sizeof (int) + 160,
701 18 + 768 * sizeof (short) / sizeof (int) + 160,
702 18 + 768 * sizeof (short) / sizeof (int) + 160,
703 18 + 768 * sizeof (short) / sizeof (int) + 160,
704 18 + 768 * sizeof (short) / sizeof (int) + 160,
705 18 + 768 * sizeof (short) / sizeof (int) + 160,
706 18 + 768 * sizeof (short) / sizeof (int) + 160,
707 18 + 768 * sizeof (short) / sizeof (int) + 160,
708 18 + 768 * sizeof (short) / sizeof (int) + 160,
709 18 + 768 * sizeof (short) / sizeof (int) + 160,
710 18 + 768 * sizeof (short) / sizeof (int) + 160,
711 18 + 768 * sizeof (short) / sizeof (int) + 160,
712 18 + 768 * sizeof (short) / sizeof (int) + 160,
713 18 + 768 * sizeof (short) / sizeof (int) + 160,
714 18 + 768 * sizeof (short) / sizeof (int) + 160,
715 18 + 768 * sizeof (short) / sizeof (int) + 160,
716 18 + 768 * sizeof (short) / sizeof (int) + 160,
717 18 + 768 * sizeof (short) / sizeof (int) + 160,
718 18 + 768 * sizeof (short) / sizeof (int) + 160,
719 18 + 768 * sizeof (short) / sizeof (int) + 160,
720 18 + 768 * sizeof (short) / sizeof (int) + 160,
721 18 + 768 * sizeof (short) / sizeof (int) + 160,
722 18 + 768 * sizeof (short) / sizeof (int) + 160,
723 18 + 768 * sizeof (short) / sizeof (int) + 160,
724 18 + 768 * sizeof (short) / sizeof (int) + 160,
725 18 + 768 * sizeof (short) / sizeof (int) + 160,
726 18 + 768 * sizeof (short) / sizeof (int) + 160,
727 18 + 768 * sizeof (short) / sizeof (int) + 160,
728 18 + 768 * sizeof (short) / sizeof (int) + 160,
729 18 + 768 * sizeof (short) / sizeof (int) + 160,
730 18 + 768 * sizeof (short) / sizeof (int) + 160,
731 18 + 768 * sizeof (short) / sizeof (int) + 160,
732 18 + 768 * sizeof (short) / sizeof (int) + 160,
733 18 + 768 * sizeof (short) / sizeof (int) + 160,
734 18 + 768 * sizeof (short) / sizeof (int) + 160,
735 18 + 768 * sizeof (short) / sizeof (int) + 160,
736 18 + 768 * sizeof (short) / sizeof (int) + 160,
737 18 + 768 * sizeof (short) / sizeof (int) + 160,
738 18 + 768 * sizeof (short) / sizeof (int) + 160,
739 18 + 768 * sizeof (short) / sizeof (int) + 160,
740 18 + 768 * sizeof (short) / sizeof (int) + 160,
741 18 + 768 * sizeof (short) / sizeof (int) + 160,
742 18 + 768 * sizeof (short) / sizeof (int) + 160,
743 18 + 768 * sizeof (short) / sizeof (int) + 160,
744 18 + 768 * sizeof (short) / sizeof (int) + 160,
745 18 + 768 * sizeof (short) / sizeof (int) + 160,
746 18 + 768 * sizeof (short) / sizeof (int) + 160,
747 18 + 768 * sizeof (short) / sizeof (int) + 160,
748 18 + 768 * sizeof (short) / sizeof (int) + 160,
749 18 + 768 * sizeof (short) / sizeof (int) + 160,
750 18 + 768 * sizeof (short) / sizeof (int) + 160,
751 18 + 768 * sizeof (short) / sizeof (int) + 160,
752 18 + 768 * sizeof (short) / sizeof (int) + 160,
753 18 + 768 * sizeof (short) / sizeof (int) + 160,
754 18 + 768 * sizeof (short) / sizeof (int) + 160,
755 18 + 768 * sizeof (short) / sizeof (int) + 160,
756 18 + 768 * sizeof (short) / sizeof (int) + 160,
757 18 + 768 * sizeof (short) / sizeof (int) + 160,
758 18 + 768 * sizeof (short) / sizeof (int) + 160,
759 18 + 768 * sizeof (short) / sizeof (int) + 160,
760 18 + 768 * sizeof (short) / sizeof (int) + 160,
761 18 + 768 * sizeof (short) / sizeof (int) + 160,
762 18 + 768 * sizeof (short) / sizeof (int) + 160,
763 18 + 768 * sizeof (short) / sizeof (int) + 160,
764 18 + 768 * sizeof (short) / sizeof (int) + 160,
765 18 + 768 * sizeof (short) / sizeof (int) + 160,
766 18 + 768 * sizeof (short) / sizeof (int) + 160,
767 18 + 768 * sizeof (short) / sizeof (int) + 160,
768 18 + 768 * sizeof (short) / sizeof (int) + 160,
769 18 + 768 * sizeof (short) / sizeof (int) + 160,
770 18 + 768 * sizeof (short) / sizeof (int) + 160,
771 18 + 768 * sizeof (short) / sizeof (int) + 160,
772 18 + 768 * sizeof (short) / sizeof (int) + 160,
773 18 + 768 * sizeof (short) / sizeof (int) + 160,
774 18 + 768 * sizeof (short) / sizeof (int) + 160,
775 18 + 768 * sizeof (short) / sizeof (int) + 160,
776 18 + 768 * sizeof (short) / sizeof (int) + 160,
777 18 + 768 * sizeof (short) / sizeof (int) + 160,
778 18 + 768 * sizeof (short) / sizeof (int) + 160,
779 18 + 768 * sizeof (short) / sizeof (int) + 160,
780 18 + 768 * sizeof (short) / sizeof (int) + 160,
781 18 + 768 * sizeof (short) / sizeof (int) + 160,
782 18 + 768 * sizeof (short) / sizeof (int) + 160,
783 18 + 768 * sizeof (short) / sizeof (int) + 160,
784 18 + 768 * sizeof (short) / sizeof (int) + 160,
785 18 + 768 * sizeof (short) / sizeof (int) + 160,
786 18 + 768 * sizeof (short) / sizeof (int) + 160,
787 18 + 768 * sizeof (short) / sizeof (int) + 160,
788 18 + 768 * sizeof (short) / sizeof (int) + 160,
789 18 + 768 * sizeof (short) / sizeof (int) + 160,
790 18 + 768 * sizeof (short) / sizeof (int) + 160,
791 18 + 768 * sizeof (short) / sizeof (int) + 160,
792 18 + 768 * sizeof (short) / sizeof (int) + 160,
793 18 + 768 * sizeof (short) / sizeof (int) + 160,
794 18 + 768 * sizeof (short) / sizeof (int) + 160,
795 18 + 768 * sizeof (short) / sizeof (int) + 160,
796 18 + 768 * sizeof (short) / sizeof (int) + 160,
797 18 + 768 * sizeof (short) / sizeof (int) + 160,
798 18 + 768 * sizeof (short) / sizeof (int) + 160,
799 18 + 768 * sizeof (short) / sizeof (int) + 160,
800 18 + 768 * sizeof (short) / sizeof (int) + 160,
801 18 + 768 * sizeof (short) / sizeof (int) + 160,
802 18 + 768 * sizeof (short) / sizeof (int) + 160,
803 18 + 768 * sizeof (short) / sizeof (int) + 160,
804 18 + 768 * sizeof (short) / sizeof (int) + 160,
805 18 + 768 * sizeof (short) / sizeof (int) + 160,
806 18 + 768 * sizeof (short) / sizeof (int) + 160,
807 18 + 768 * sizeof (short) / sizeof (int) + 160,
808 18 + 768 * sizeof (short) / sizeof (int) + 160,
809 18 + 768 * sizeof (short) / sizeof (int) + 160,
810 18 + 768 * sizeof (short) / sizeof (int) + 160,
811 18 + 768 * sizeof (short) / sizeof (int) + 160,
812 18 + 768 * sizeof (short) / sizeof (int) + 160,
813 18 + 768 * sizeof (short) / sizeof (int) + 160,
814 18 + 768 * sizeof (short) / sizeof (int) + 160,
815 18 + 768 * sizeof (short) / sizeof (int) + 160,
816 18 + 768 * sizeof (short) / sizeof (int) + 160,
817 18 + 768 * sizeof (short) / sizeof (int) + 160,
818 18 + 768 * sizeof (short) / sizeof (int) + 160,
819 18 + 768 * sizeof (short) / sizeof (int) + 160,
820 18 + 768 * sizeof (short) / sizeof (int) + 160,
821 18 + 768 * sizeof (short) / sizeof (int) + 160,
822 18 + 768 * sizeof (short) / sizeof (int) + 1488
823 },
824 {
825 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x7FFFFFFFU,
826 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
827 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
828 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
829 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
830 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
831 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFCFFFFFFU,
832 0xFFFFD7F0U, 0xFFFFFFFBU, 0xFFFFFFFFU, 0xFFFFFFFFU,
833 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
834 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
835 0xFFFFFFFFU, 0xFFFEFFFFU, 0xFE7FFFFFU, 0xFFFFFFFFU,
836 0xFFFEE7FFU, 0xFFFFFFFFU, 0xFFFF00FFU, 0x001F87FFU,
837 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
838 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
839 0xFFFFBFFFU, 0xFFFFFFFFU, 0xFFFFE7FFU, 0xFFFFFFFFU,
840 0xFFFFFFFFU, 0x0003FFFFU, 0xFFFFFFFFU, 0xE7FFFFFFU,
841 0xFFFFFFFFU, 0x7FFF3FFFU, 0x4FFFFFFFU, 0xFFFF07FFU,
842 0xFF837FFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
843 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
844 0xFFF99FEFU, 0xF3C5FDFFU, 0xB080799FU, 0x7FFFFFCFU,
845 0xFFF987EEU, 0xD36DFDFFU, 0x5E023987U, 0x007FFFC0U,
846 0xFFFBBFEEU, 0xF3EDFDFFU, 0x00013BBFU, 0xFE03FFCFU,
847 0xFFF99FEEU, 0xF3EDFDFFU, 0xB0E0399FU, 0x00FFFFCFU,
848 0xD63DC7ECU, 0xC3FFC718U, 0x00813DC7U, 0x07FFFFC0U,
849 0xFFFDDFFFU, 0xF3FFFDFFU, 0x27603DDFU, 0xFF80FFCFU,
850 0xFFFDDFFFU, 0xF3EFFDFFU, 0x60603DDFU, 0x000EFFCFU,
851 0xFFFDDFFFU, 0xFFFFFFFFU, 0xFFF0FDDFU, 0xFFFFFFCFU,
852 0xFC7FFFEEU, 0x2FFBFFFFU, 0xFF5F847FU, 0x001CFFC0U,
853 0xFFFFFFFEU, 0x87FFFFFFU, 0x0FFFFFFFU, 0x00000000U,
854 0xFFFFF7D6U, 0x3FFFFFAFU, 0xF3FF7F5FU, 0x00000000U,
855 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFEFFU, 0xFFFE1FFFU,
856 0xFEFFFFFFU, 0xDFFFFFFFU, 0x07FFDFFFU, 0x00000000U,
857 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
858 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF20BFU, 0xFFFFFFFFU,
859 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
860 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
861 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3D7F3DFFU, 0xFFFFFFFFU,
862 0xFFFF3DFFU, 0x7F3DFFFFU, 0xFF7FFF3DU, 0xFFFFFFFFU,
863 0xFF3DFFFFU, 0xFFFFFFFFU, 0xE7FFFFFFU, 0x1FFFFFFFU,
864 0x03FFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3F3FFFFFU,
865 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
866 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
867 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
868 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
869 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
870 0x1FFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x01FFFFFFU,
871 0x803FFFFFU, 0x007FFFFFU, 0x000FFFFFU, 0x000DDFFFU,
872 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3FFFFFFFU, 0x03FF03FFU,
873 0x03FFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x01FFFFFFU,
874 0xFFFFFFFFU, 0xFFFF07FFU, 0xFFFFFFFFU, 0x003FFFFFU,
875 0x7FFFFFFFU, 0x0FFF0FFFU, 0xFFFFFFF1U, 0x001F3FFFU,
876 0xFFFFFFFFU, 0xFFFF0FFFU, 0xC7FF03FFU, 0xFFFFFFFFU,
877 0xCFFFFFFFU, 0xFFFFFFFFU, 0x7FFFFFFFU, 0x9FFFFFFFU,
878 0x03FF03FFU, 0xFFFF3FFFU, 0x00007FFFU, 0x00000000U,
879 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFDFFFU, 0xFFFFFFFFU,
880 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xF00FFFFFU,
881 0xFFFFFFFFU, 0xF8FFFFFFU, 0xFFFFE3FFU, 0xFFFFFFFFU,
882 0xFFFF07FFU, 0xE7FFFFFFU, 0xFFFF00FFU, 0x07FFFFFFU,
883 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
884 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
885 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
886 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
887 0x3F3FFFFFU, 0xFFFFFFFFU, 0xAAFF3F3FU, 0x3FFFFFFFU,
888 0xFFFFFFFFU, 0xFFDFFFFFU, 0xEFCFFFDFU, 0x7FDCFFFFU,
889 0xFFFFFFFFU, 0xFFFFFCFFU, 0xFFFFFFFFU, 0xFFF3FFDFU,
890 0x1FFF7FFFU, 0xFFFFFFFFU, 0xFFFF0001U, 0x0001FFFFU,
891 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
892 0xFFFF0FFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
893 0xFFFFFFFFU, 0x000003FFU, 0x000007FFU, 0xFFFFFFFFU,
894 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
895 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
896 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
897 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
898 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
899 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFCFFFFFU,
900 0xFFBFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
901 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
902 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFE0FFFFFU,
903 0xFFFFFFFFU, 0xFFFF20BFU, 0xFFFFFFFFU, 0x800180FFU,
904 0x007FFFFFU, 0x7F7F7F7FU, 0x7F7F7F7FU, 0xFFFFFFFFU,
905 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3FFFFFFFU, 0x00000000U,
906 0xFBFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000FFFFFU,
907 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
908 0xFFFFFFFFU, 0xFFFFFFFFU, 0x003FFFFFU, 0xFFFF0000U,
909 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFEU, 0xFFFFFFFFU,
910 0xFE7FFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
911 0xFFFFFFE0U, 0xFFFEFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
912 0xFFFF7FFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF803FU,
913 0x7FFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
914 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
915 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
916 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
917 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
918 0xFFFF1FFFU, 0xFFFFFFFFU, 0xFFFF007FU, 0xFFFFFFFFU,
919 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
920 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
921 0xFFFFFFFFU, 0x00000FFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
922 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00FFFFFFU,
923 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
924 0xFFFFFFFFU, 0xFFFFFFFFU, 0x1FEB3FFFU, 0xFFFC0000U,
925 0xFFFFFFFFU, 0x03FF1FFFU, 0xFFFFFFFFU, 0x00FFFFFFU,
926 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FFC03FU, 0xFFFFFFFFU,
927 0xFFFFFFFFU, 0xFFFFFFFFU, 0x800FFFFFU, 0x1FFFFFFFU,
928 0xFFFFFFFFU, 0xFFFFFFFFU, 0xC3FFBFFFU, 0x7FFFFFFFU,
929 0xFFFFFFFFU, 0x007FFFFFU, 0xF3FF3FFFU, 0xFFFFFFFFU,
930 0xFFFFFFFFU, 0xFFFFFFFFU, 0xF8000007U, 0x007FFFFFU,
931 0x007E7E7EU, 0xFFFF7F7FU, 0xFFFFFFFFU, 0xFFFF0FFFU,
932 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FF3FFFU,
933 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
934 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
935 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
936 0xFFFFFFFFU, 0xFFFF000FU, 0xFFFFF87FU, 0x0FFFFFFFU,
937 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF3FFFU,
938 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FFFFFFU, 0x00000000U,
939 0xE0F8007FU, 0x5F7FFFFFU, 0xFFFFFFDBU, 0xFFFFFFFFU,
940 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFF80007U, 0xFFFFFFFFU,
941 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
942 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
943 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
944 0xFFFCFFFFU, 0xFFFFFFFFU, 0x000080FFU, 0xFFFF0000U,
945 0x03FFFFFFU, 0xFFFFFFFFU, 0xFFF7FFFFU, 0xFFDF0F7FU,
946 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x9FFFFFFFU,
947 0xFFFFFFFEU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
948 0xFFFFFFFFU, 0x7FFFFFFFU, 0x1CFCFCFCU, 0x3E007F7FU,
949 0xFFFFEFFFU, 0xB7FFFF7FU, 0x3FFF3FFFU, 0x00000000U,
950 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x07FFFFFFU,
951 0xFFFFFF87U, 0xFF8FFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
952 0x1FFF7FFFU, 0x00000001U, 0xFFFF0000U, 0x3FFFFFFFU,
953 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
954 0x1FFFFFFFU, 0xFFFFFFFFU, 0x0001FFFFU, 0x0FFFFFFFU,
955 0xFFFFFFFFU, 0xFFFFE00FU, 0xFFFF07FFU, 0x07FFFFFFU,
956 0xBFFFFFFFU, 0xFFFFFFFFU, 0x003FFF0FU, 0x00000000U,
957 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
958 0x3FFFFFFFU, 0xFFFF03FFU, 0xFF0FFFFFU, 0x0FFFFFFFU,
959 0xFFFFFFFFU, 0xFFFF00FFU, 0xFFFFFFFFU, 0xF7FF800FU,
960 0xFFB7F7FFU, 0x1BFBFFFBU, 0xFFFFFFFFU, 0x000FFFFFU,
961 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
962 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
963 0xFFFFFFFFU, 0x007FFFFFU, 0x003FFFFFU, 0x000000FFU,
964 0xFFFFFFBFU, 0x07FDFFFFU, 0x00000000U, 0x00000000U,
965 0xFFFFFD3FU, 0x91BFFFFFU, 0xFFBFFFFFU, 0xFFFFFFFFU,
966 0x7FFFFFFFU, 0x0000FF80U, 0x00000000U, 0xF837FFFFU,
967 0x8FFFFFFFU, 0x83FFFFFFU, 0x00000000U, 0x00000000U,
968 0xFFFFFFFFU, 0xF0FFFFFFU, 0xFFFCFFFFU, 0xFFFFFFFFU,
969 0xFEEFF06FU, 0x873FFFFFU, 0x01FF01FFU, 0xFFFFFFFFU,
970 0xFFFFFFFFU, 0x00000000U, 0xFFFFFFFFU, 0x007FF87FU,
971 0xFFFFFFFFU, 0xFE3FFFFFU, 0xFF3FFFFFU, 0xFF07FFFFU,
972 0x1E03FFFFU, 0x0000FE00U, 0x00000000U, 0x00000000U,
973 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000001FFU, 0x00000000U,
974 0xFFFFFFFFU, 0x0007FFFFU, 0xFFFFFFFFU, 0xFC07FFFFU,
975 0xFFFFFFFFU, 0x03FF00FFU, 0xFFFFFFFFU, 0xFFFFFE3FU,
976 0x0000C03FU, 0x00000000U, 0x00000000U, 0x00000000U,
977 0x00000000U, 0x00000000U, 0x00000000U, 0x7FFFFFFFU,
978 0xFFFFFFFFU, 0x00033BFFU, 0x0000001CU, 0xF0000000U,
979 0xFFFFFFFFU, 0xFFFF00FFU, 0x03FFFFFFU, 0xFFFF0000U,
980 0x000003FFU, 0xFFFF0000U, 0x00000FFFU, 0x007FFFFFU,
981 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFC3FFFU, 0x803FFFFFU,
982 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF2007U, 0x03FF01FFU,
983 0xFFFFFFFFU, 0xFFDFFFFFU, 0xFFFF00FFU, 0x007FFFFFU,
984 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x001FFFFEU,
985 0xFFFBFFFFU, 0xFFFFFFFFU, 0x00000003U, 0x00000000U,
986 0xBFFFBD7FU, 0xFFFF03FFU, 0xFFFFFFFFU, 0x03FF07FFU,
987 0xFFF99FEFU, 0xFBEDFDFFU, 0xE081399FU, 0x001F1FCFU,
988 0xFFFF4BFFU, 0xFFBFFFFFU, 0x01BFF7A5U, 0x00000006U,
989 0xFFFFFFFFU, 0xFFFFFFFFU, 0xEFFFFFFFU, 0x00000003U,
990 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FF00FFU, 0x00000000U,
991 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
992 0xFFFFFFFFU, 0xFF3FFFFFU, 0x3FFFFFFFU, 0x00000000U,
993 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FF001FU, 0x00001FFFU,
994 0xFFFFFFFFU, 0x03FFFFFFU, 0xFFFF03FFU, 0x0000000FU,
995 0xE7FFFFFFU, 0xFFFF0FFFU, 0x0000007FU, 0x00000000U,
996 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
997 0xFFFFFFFFU, 0x0FFFFFFFU, 0x00000000U, 0x00000000U,
998 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x8007FFFFU,
999 0xFF6FF27FU, 0xF9BFFFFFU, 0x03FF007FU, 0x00000000U,
1000 0x00000000U, 0xFFFFFCFFU, 0xFCFFFFFFU, 0x0000001FU,
1001 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF00FFU, 0xFFFFFFFFU,
1002 0xFFFFFFFFU, 0xFFFF0007U, 0xFFFFFFFFU, 0x01FFFFFFU,
1003 0x000003FFU, 0x00000000U, 0x00000000U, 0x00000000U,
1004 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0x03FF0003U,
1005 0xFFFFFDFFU, 0xFF7FFFFFU, 0xFFFF003FU, 0xFFFF1FFFU,
1006 0xFFFCFFFFU, 0x007FFEFFU, 0x00000000U, 0x00000000U,
1007 0xFFFFFB7FU, 0xB47FFFFFU, 0x03FF00FFU, 0xFFFFFDBFU,
1008 0x01FB7FFFU, 0x000003FFU, 0x00000000U, 0x00000000U,
1009 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1010 0x00000000U, 0x00000000U, 0x00000000U, 0x01FFFFFFU,
1011 0xFFFDFFFFU, 0xC7FFFFFFU, 0x07FFFFFFU, 0x00000000U,
1012 0x00000000U, 0x00010000U, 0xFFFFFFFFU, 0x8003FFFFU,
1013 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1014 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1015 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1016 0x03FFFFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
1017 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x001F7FFFU,
1018 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1019 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000000FU, 0x00000000U,
1020 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1021 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1022 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1023 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1024 0xFFFF0000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0007FFFFU,
1025 0xFFFFFFFFU, 0xFFFFFFFFU, 0x003FFFFFU, 0xFFFFFFFFU,
1026 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1027 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1028 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1029 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1030 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1031 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1032 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x07FFFFFFU,
1033 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000007FU, 0x00000000U,
1034 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1035 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1036 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1037 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1038 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1039 0xFFFFFFFFU, 0x03FFFFFFU, 0x00000000U, 0x00000000U,
1040 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1041 0xFFFFFFFFU, 0x01FFFFFFU, 0x7FFFFFFFU, 0xFFFFC3FFU,
1042 0xFFFFFFFFU, 0x7FFFFFFFU, 0xFFFF03FFU, 0x003F3FFFU,
1043 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFBFF003FU, 0xE0FFFFFBU,
1044 0x0000FFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
1045 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1046 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1047 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0x03FFFFFFU,
1048 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1049 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU,
1050 0x07FFFFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
1051 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF87FFU, 0xFFFFFFFFU,
1052 0xFFFF80FFU, 0x00000000U, 0x00000000U, 0x0003001FU,
1053 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1054 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1055 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1056 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00FFFFFFU,
1057 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1058 0xFFFFFFFFU, 0xFFFFFFFFU, 0x003FFFFFU, 0x80000000U,
1059 0x000001FFU, 0x00000000U, 0x00000000U, 0x00000000U,
1060 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1061 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1062 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1063 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1064 0x00000000U, 0x00000000U, 0x00000000U, 0x6FEF0000U,
1065 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1066 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1067 0xFFFFFFFFU, 0x00040007U, 0x00270000U, 0xFFFF00F0U,
1068 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1069 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1070 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0FFFFFFFU,
1071 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1072 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1073 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x1FFF07FFU,
1074 0xF3FF01FFU, 0x0000000FU, 0x00000000U, 0x00000000U,
1075 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1076 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1077 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1078 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FFFFFFU,
1079 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1080 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1081 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1082 0xFFFFFFFFU, 0x000FFFFFU, 0x00000000U, 0x00000000U,
1083 0xFFFFFFFFU, 0xFFFF3FFFU, 0xFFFF007FU, 0xFFFFFFFFU,
1084 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000000FU, 0x00000000U,
1085 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1086 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x003FFFFFU,
1087 0xFFFFFFFFU, 0xFFFFFE7FU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1088 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000007FFU,
1089 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000003FU, 0x00000000U,
1090 0x00000000U, 0x00000000U, 0x000FFFFFU, 0x000FFFFFU,
1091 0xFFFFFFFFU, 0xFFFFFFFFU, 0x007FFFFFU, 0x01FFFFFFU,
1092 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1093 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFDFFFFFU, 0xFFFFFFFFU,
1094 0xDFFFFFFFU, 0xEBFFDE64U, 0xFFFFFFEFU, 0xFFFFFFFFU,
1095 0xDFDFE7BFU, 0x7BFFFFFFU, 0xFFFDFC5FU, 0xFFFFFFFFU,
1096 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1097 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1098 0xFFFFFFFFU, 0xFFFFFF3FU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1099 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1100 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFCFFFU, 0xFFFFFFFFU,
1101 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1102 0xF8000FFFU, 0x0000FFFEU, 0x00000000U, 0x00000000U,
1103 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1104 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1105 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1106 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1107 0x7FFFFFFFU, 0x000007E0U, 0x00000000U, 0x00000000U,
1108 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1109 0xF9FFFF7FU, 0xFFFF07DBU, 0xFFFFFFFFU, 0x00003FFFU,
1110 0x00008000U, 0x00000000U, 0x00000000U, 0x00000000U,
1111 0xFFFFFFFFU, 0x3FFF1FFFU, 0x0000C3FFU, 0x00000000U,
1112 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1113 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1114 0xFFFF0000U, 0x00007FFFU, 0xFFFFFFFFU, 0x83FFFFFFU,
1115 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1116 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1117 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1118 0x00000000U, 0x00000000U, 0xFFFF0000U, 0x03FFFFFFU,
1119 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1120 0x00000000U, 0x00000000U, 0xFFFF0000U, 0x87FFFFFFU,
1121 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1122 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1123 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1124 0x00000000U, 0x00000000U, 0x00000000U, 0x7FFF6F7FU,
1125 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1126 0xFFFFFFFFU, 0xFFFFFFFFU, 0x007FFF9FU, 0x00000000U,
1127 0xFFFFFFFFU, 0xFFFFFFFFU, 0xC3FF0FFFU, 0x00000000U,
1128 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1129 0x00000000U, 0x00000000U, 0x00000000U, 0xFFFE0000U,
1130 0xFFFFFFFFU, 0x001FFFFFU, 0x00000000U, 0x00000000U,
1131 0xFFFFFFFEU, 0x3FFFFFFFU, 0x00000000U, 0x00000000U,
1132 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1133 0xFFFFFFEFU, 0x0AF7FE96U, 0xAA96EA84U, 0x5EF7F796U,
1134 0x0FFFFBFFU, 0x0FFFFBEEU, 0x00000000U, 0x00030000U,
1135 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1136 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1137 0xFFFFFFFFU, 0xFFFF0FFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1138 0x000FFFFFU, 0xFFFE7FFFU, 0xFFFEFFFEU, 0x003FFFFFU,
1139 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1140 0xFFFFFFFFU, 0x00003FFFU, 0x00000000U, 0xFFFFFFC0U,
1141 0xFFFF0007U, 0x0FFFFFFFU, 0x000301FFU, 0x0000003FU,
1142 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1143 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1144 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1145 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1146 0xFFFFFFFFU, 0xFFFFFFFFU, 0xF0FFFFFFU, 0x1FFF1FFFU,
1147 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xF87FFFFFU,
1148 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FFFFFFU, 0x00010FFFU,
1149 0xFFFF0FFFU, 0xFFFFFFFFU, 0x03FF00FFU, 0xFFFFFFFFU,
1150 0xFFFF00FFU, 0x0FFF3FFFU, 0x00000003U, 0x00000000U,
1151 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1152 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1153 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000FFFFFU, 0x1FFF3FFFU,
1154 0xFFFF83FFU, 0xFFFFFFFFU, 0x9FFFC07FU, 0x01FF03FFU,
1155 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1156 0xFFF7FFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FFFFFFU,
1157 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1158 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000000U,
1159 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1160 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1161 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1162 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1163 0xFFFFFFFFU, 0x03FFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1164 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1165 0x3FFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1166 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1167 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1168 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1169 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1170 0xFFFFFFFFU, 0xFFFF0003U, 0xFFFFFFFFU, 0xFFFFFFFFU,
1171 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1172 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1173 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1174 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1175 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1176 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF0001U,
1177 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3FFFFFFFU, 0x00000000U,
1178 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1179 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1180 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1181 0x3FFFFFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
1182 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1183 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1184 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1185 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1186 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1187 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF07FFU, 0xFFFFFFFFU,
1188 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1189 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1190 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1191 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1192 0xFFFFFFFFU, 0x0000FFFFU, 0x00000000U, 0x00000000U,
1193 0x00000002U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1194 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
1195 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1196 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000FFFFU,
1197 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1198 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1199 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
1200 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3FFFFFFFU
1201 }
1202};
diff --git a/gl/unictype/ctype_punct.c b/gl/unictype/ctype_punct.c
new file mode 100644
index 00000000..f2d647de
--- /dev/null
+++ b/gl/unictype/ctype_punct.c
@@ -0,0 +1,32 @@
1/* ISO C <ctype.h> like properties of Unicode characters.
2 Copyright (C) 2002, 2006-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2002.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include "unictype.h"
22
23#include "bitmap.h"
24
25/* Define u_is_punct table. */
26#include "ctype_punct.h"
27
28bool
29uc_is_punct (ucs4_t uc)
30{
31 return bitmap_lookup (&u_is_punct, uc);
32}
diff --git a/gl/unictype/ctype_punct.h b/gl/unictype/ctype_punct.h
new file mode 100644
index 00000000..cb252114
--- /dev/null
+++ b/gl/unictype/ctype_punct.h
@@ -0,0 +1,870 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* ISO C <ctype.h> like properties of Unicode characters. */
3/* Generated automatically by gen-uni-tables.c for Unicode 16.0.0. */
4
5/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
6
7 This file is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 This file is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19
20#define header_0 16
21#define header_2 9
22#define header_3 127
23#define header_4 15
24static const
25struct
26 {
27 int header[1];
28 int level1[17];
29 short level2[4 << 7];
30 unsigned int level3[75 << 4];
31 }
32u_is_punct =
33{
34 { 17 },
35 {
36 18 * sizeof (int) / sizeof (short) + 0,
37 18 * sizeof (int) / sizeof (short) + 128,
38 -1,
39 -1,
40 -1,
41 -1,
42 -1,
43 -1,
44 -1,
45 -1,
46 -1,
47 -1,
48 -1,
49 -1,
50 18 * sizeof (int) / sizeof (short) + 256,
51 18 * sizeof (int) / sizeof (short) + 384,
52 18 * sizeof (int) / sizeof (short) + 384
53 },
54 {
55 18 + 512 * sizeof (short) / sizeof (int) + 0,
56 18 + 512 * sizeof (short) / sizeof (int) + 16,
57 18 + 512 * sizeof (short) / sizeof (int) + 32,
58 18 + 512 * sizeof (short) / sizeof (int) + 48,
59 18 + 512 * sizeof (short) / sizeof (int) + 64,
60 18 + 512 * sizeof (short) / sizeof (int) + 80,
61 18 + 512 * sizeof (short) / sizeof (int) + 96,
62 18 + 512 * sizeof (short) / sizeof (int) + 112,
63 18 + 512 * sizeof (short) / sizeof (int) + 128,
64 18 + 512 * sizeof (short) / sizeof (int) + 144,
65 18 + 512 * sizeof (short) / sizeof (int) + 160,
66 18 + 512 * sizeof (short) / sizeof (int) + 176,
67 18 + 512 * sizeof (short) / sizeof (int) + 192,
68 18 + 512 * sizeof (short) / sizeof (int) + 208,
69 18 + 512 * sizeof (short) / sizeof (int) + 224,
70 18 + 512 * sizeof (short) / sizeof (int) + 240,
71 18 + 512 * sizeof (short) / sizeof (int) + 256,
72 18 + 512 * sizeof (short) / sizeof (int) + 272,
73 18 + 512 * sizeof (short) / sizeof (int) + 288,
74 18 + 512 * sizeof (short) / sizeof (int) + 272,
75 18 + 512 * sizeof (short) / sizeof (int) + 272,
76 18 + 512 * sizeof (short) / sizeof (int) + 304,
77 18 + 512 * sizeof (short) / sizeof (int) + 320,
78 18 + 512 * sizeof (short) / sizeof (int) + 336,
79 18 + 512 * sizeof (short) / sizeof (int) + 352,
80 18 + 512 * sizeof (short) / sizeof (int) + 368,
81 -1,
82 -1,
83 -1,
84 -1,
85 -1,
86 -1,
87 -1,
88 -1,
89 -1,
90 -1,
91 -1,
92 -1,
93 18 + 512 * sizeof (short) / sizeof (int) + 384,
94 -1,
95 -1,
96 -1,
97 -1,
98 -1,
99 -1,
100 -1,
101 -1,
102 -1,
103 -1,
104 -1,
105 -1,
106 -1,
107 -1,
108 -1,
109 -1,
110 -1,
111 -1,
112 -1,
113 -1,
114 -1,
115 -1,
116 -1,
117 -1,
118 -1,
119 -1,
120 -1,
121 -1,
122 -1,
123 -1,
124 -1,
125 -1,
126 -1,
127 -1,
128 -1,
129 -1,
130 -1,
131 -1,
132 -1,
133 -1,
134 -1,
135 -1,
136 -1,
137 18 + 512 * sizeof (short) / sizeof (int) + 400,
138 18 + 512 * sizeof (short) / sizeof (int) + 416,
139 18 + 512 * sizeof (short) / sizeof (int) + 432,
140 18 + 512 * sizeof (short) / sizeof (int) + 448,
141 -1,
142 -1,
143 -1,
144 -1,
145 -1,
146 -1,
147 -1,
148 -1,
149 -1,
150 -1,
151 -1,
152 -1,
153 -1,
154 -1,
155 -1,
156 -1,
157 -1,
158 -1,
159 -1,
160 -1,
161 -1,
162 -1,
163 -1,
164 -1,
165 -1,
166 -1,
167 18 + 512 * sizeof (short) / sizeof (int) + 272,
168 18 + 512 * sizeof (short) / sizeof (int) + 272,
169 18 + 512 * sizeof (short) / sizeof (int) + 272,
170 18 + 512 * sizeof (short) / sizeof (int) + 272,
171 18 + 512 * sizeof (short) / sizeof (int) + 272,
172 18 + 512 * sizeof (short) / sizeof (int) + 272,
173 18 + 512 * sizeof (short) / sizeof (int) + 272,
174 18 + 512 * sizeof (short) / sizeof (int) + 272,
175 18 + 512 * sizeof (short) / sizeof (int) + 272,
176 18 + 512 * sizeof (short) / sizeof (int) + 272,
177 18 + 512 * sizeof (short) / sizeof (int) + 272,
178 18 + 512 * sizeof (short) / sizeof (int) + 272,
179 18 + 512 * sizeof (short) / sizeof (int) + 464,
180 18 + 512 * sizeof (short) / sizeof (int) + 480,
181 18 + 512 * sizeof (short) / sizeof (int) + 496,
182 18 + 512 * sizeof (short) / sizeof (int) + 512,
183 18 + 512 * sizeof (short) / sizeof (int) + 528,
184 18 + 512 * sizeof (short) / sizeof (int) + 544,
185 18 + 512 * sizeof (short) / sizeof (int) + 560,
186 -1,
187 18 + 512 * sizeof (short) / sizeof (int) + 576,
188 18 + 512 * sizeof (short) / sizeof (int) + 592,
189 18 + 512 * sizeof (short) / sizeof (int) + 608,
190 18 + 512 * sizeof (short) / sizeof (int) + 624,
191 18 + 512 * sizeof (short) / sizeof (int) + 640,
192 18 + 512 * sizeof (short) / sizeof (int) + 656,
193 18 + 512 * sizeof (short) / sizeof (int) + 672,
194 18 + 512 * sizeof (short) / sizeof (int) + 688,
195 18 + 512 * sizeof (short) / sizeof (int) + 704,
196 18 + 512 * sizeof (short) / sizeof (int) + 720,
197 18 + 512 * sizeof (short) / sizeof (int) + 736,
198 18 + 512 * sizeof (short) / sizeof (int) + 752,
199 -1,
200 -1,
201 18 + 512 * sizeof (short) / sizeof (int) + 768,
202 -1,
203 -1,
204 -1,
205 -1,
206 18 + 512 * sizeof (short) / sizeof (int) + 784,
207 -1,
208 -1,
209 18 + 512 * sizeof (short) / sizeof (int) + 800,
210 -1,
211 -1,
212 -1,
213 -1,
214 -1,
215 -1,
216 -1,
217 -1,
218 -1,
219 -1,
220 -1,
221 -1,
222 -1,
223 -1,
224 -1,
225 -1,
226 -1,
227 -1,
228 -1,
229 -1,
230 -1,
231 18 + 512 * sizeof (short) / sizeof (int) + 816,
232 -1,
233 -1,
234 -1,
235 -1,
236 18 + 512 * sizeof (short) / sizeof (int) + 832,
237 18 + 512 * sizeof (short) / sizeof (int) + 848,
238 18 + 512 * sizeof (short) / sizeof (int) + 864,
239 -1,
240 -1,
241 -1,
242 -1,
243 -1,
244 -1,
245 -1,
246 -1,
247 -1,
248 -1,
249 -1,
250 -1,
251 -1,
252 -1,
253 -1,
254 -1,
255 -1,
256 -1,
257 -1,
258 -1,
259 -1,
260 -1,
261 -1,
262 -1,
263 -1,
264 -1,
265 -1,
266 -1,
267 -1,
268 -1,
269 -1,
270 -1,
271 -1,
272 -1,
273 -1,
274 -1,
275 -1,
276 -1,
277 18 + 512 * sizeof (short) / sizeof (int) + 880,
278 -1,
279 -1,
280 -1,
281 -1,
282 -1,
283 -1,
284 -1,
285 18 + 512 * sizeof (short) / sizeof (int) + 896,
286 18 + 512 * sizeof (short) / sizeof (int) + 912,
287 18 + 512 * sizeof (short) / sizeof (int) + 928,
288 18 + 512 * sizeof (short) / sizeof (int) + 944,
289 -1,
290 18 + 512 * sizeof (short) / sizeof (int) + 960,
291 18 + 512 * sizeof (short) / sizeof (int) + 272,
292 18 + 512 * sizeof (short) / sizeof (int) + 976,
293 -1,
294 -1,
295 18 + 512 * sizeof (short) / sizeof (int) + 992,
296 18 + 512 * sizeof (short) / sizeof (int) + 1008,
297 18 + 512 * sizeof (short) / sizeof (int) + 1024,
298 -1,
299 18 + 512 * sizeof (short) / sizeof (int) + 1040,
300 -1,
301 18 + 512 * sizeof (short) / sizeof (int) + 1056,
302 18 + 512 * sizeof (short) / sizeof (int) + 1072,
303 18 + 512 * sizeof (short) / sizeof (int) + 1088,
304 18 + 512 * sizeof (short) / sizeof (int) + 1104,
305 18 + 512 * sizeof (short) / sizeof (int) + 272,
306 18 + 512 * sizeof (short) / sizeof (int) + 1120,
307 18 + 512 * sizeof (short) / sizeof (int) + 1136,
308 18 + 512 * sizeof (short) / sizeof (int) + 1152,
309 -1,
310 -1,
311 18 + 512 * sizeof (short) / sizeof (int) + 1168,
312 -1,
313 -1,
314 -1,
315 -1,
316 -1,
317 -1,
318 -1,
319 -1,
320 -1,
321 -1,
322 -1,
323 -1,
324 -1,
325 -1,
326 -1,
327 -1,
328 -1,
329 -1,
330 -1,
331 -1,
332 -1,
333 -1,
334 -1,
335 -1,
336 -1,
337 -1,
338 -1,
339 -1,
340 -1,
341 -1,
342 -1,
343 -1,
344 -1,
345 -1,
346 -1,
347 -1,
348 -1,
349 -1,
350 -1,
351 -1,
352 -1,
353 -1,
354 -1,
355 -1,
356 -1,
357 -1,
358 -1,
359 -1,
360 -1,
361 -1,
362 -1,
363 -1,
364 -1,
365 -1,
366 -1,
367 -1,
368 -1,
369 -1,
370 -1,
371 -1,
372 -1,
373 -1,
374 -1,
375 -1,
376 -1,
377 -1,
378 -1,
379 -1,
380 -1,
381 -1,
382 -1,
383 -1,
384 -1,
385 -1,
386 -1,
387 -1,
388 -1,
389 -1,
390 -1,
391 -1,
392 -1,
393 -1,
394 -1,
395 -1,
396 -1,
397 -1,
398 -1,
399 -1,
400 -1,
401 -1,
402 -1,
403 -1,
404 -1,
405 -1,
406 -1,
407 -1,
408 -1,
409 -1,
410 -1,
411 -1,
412 -1,
413 -1,
414 -1,
415 -1,
416 -1,
417 -1,
418 -1,
419 -1,
420 -1,
421 -1,
422 -1,
423 -1,
424 -1,
425 -1,
426 -1,
427 -1,
428 -1,
429 -1,
430 -1,
431 -1,
432 -1,
433 -1,
434 -1,
435 -1,
436 -1,
437 -1,
438 -1,
439 18 + 512 * sizeof (short) / sizeof (int) + 272,
440 18 + 512 * sizeof (short) / sizeof (int) + 272,
441 18 + 512 * sizeof (short) / sizeof (int) + 272,
442 18 + 512 * sizeof (short) / sizeof (int) + 272,
443 18 + 512 * sizeof (short) / sizeof (int) + 272,
444 18 + 512 * sizeof (short) / sizeof (int) + 272,
445 18 + 512 * sizeof (short) / sizeof (int) + 272,
446 18 + 512 * sizeof (short) / sizeof (int) + 272,
447 18 + 512 * sizeof (short) / sizeof (int) + 272,
448 18 + 512 * sizeof (short) / sizeof (int) + 272,
449 18 + 512 * sizeof (short) / sizeof (int) + 272,
450 18 + 512 * sizeof (short) / sizeof (int) + 272,
451 18 + 512 * sizeof (short) / sizeof (int) + 272,
452 18 + 512 * sizeof (short) / sizeof (int) + 272,
453 18 + 512 * sizeof (short) / sizeof (int) + 272,
454 18 + 512 * sizeof (short) / sizeof (int) + 272,
455 18 + 512 * sizeof (short) / sizeof (int) + 272,
456 18 + 512 * sizeof (short) / sizeof (int) + 272,
457 18 + 512 * sizeof (short) / sizeof (int) + 272,
458 18 + 512 * sizeof (short) / sizeof (int) + 272,
459 18 + 512 * sizeof (short) / sizeof (int) + 272,
460 18 + 512 * sizeof (short) / sizeof (int) + 272,
461 18 + 512 * sizeof (short) / sizeof (int) + 272,
462 18 + 512 * sizeof (short) / sizeof (int) + 272,
463 18 + 512 * sizeof (short) / sizeof (int) + 272,
464 18 + 512 * sizeof (short) / sizeof (int) + 272,
465 18 + 512 * sizeof (short) / sizeof (int) + 272,
466 18 + 512 * sizeof (short) / sizeof (int) + 272,
467 18 + 512 * sizeof (short) / sizeof (int) + 272,
468 18 + 512 * sizeof (short) / sizeof (int) + 272,
469 18 + 512 * sizeof (short) / sizeof (int) + 272,
470 18 + 512 * sizeof (short) / sizeof (int) + 272,
471 18 + 512 * sizeof (short) / sizeof (int) + 272,
472 18 + 512 * sizeof (short) / sizeof (int) + 272,
473 18 + 512 * sizeof (short) / sizeof (int) + 272,
474 18 + 512 * sizeof (short) / sizeof (int) + 272,
475 18 + 512 * sizeof (short) / sizeof (int) + 272,
476 18 + 512 * sizeof (short) / sizeof (int) + 272,
477 18 + 512 * sizeof (short) / sizeof (int) + 272,
478 18 + 512 * sizeof (short) / sizeof (int) + 272,
479 18 + 512 * sizeof (short) / sizeof (int) + 272,
480 18 + 512 * sizeof (short) / sizeof (int) + 272,
481 18 + 512 * sizeof (short) / sizeof (int) + 272,
482 18 + 512 * sizeof (short) / sizeof (int) + 272,
483 18 + 512 * sizeof (short) / sizeof (int) + 272,
484 18 + 512 * sizeof (short) / sizeof (int) + 272,
485 18 + 512 * sizeof (short) / sizeof (int) + 272,
486 18 + 512 * sizeof (short) / sizeof (int) + 272,
487 18 + 512 * sizeof (short) / sizeof (int) + 272,
488 18 + 512 * sizeof (short) / sizeof (int) + 272,
489 18 + 512 * sizeof (short) / sizeof (int) + 272,
490 18 + 512 * sizeof (short) / sizeof (int) + 272,
491 18 + 512 * sizeof (short) / sizeof (int) + 272,
492 18 + 512 * sizeof (short) / sizeof (int) + 272,
493 18 + 512 * sizeof (short) / sizeof (int) + 272,
494 18 + 512 * sizeof (short) / sizeof (int) + 272,
495 18 + 512 * sizeof (short) / sizeof (int) + 272,
496 18 + 512 * sizeof (short) / sizeof (int) + 272,
497 18 + 512 * sizeof (short) / sizeof (int) + 272,
498 18 + 512 * sizeof (short) / sizeof (int) + 272,
499 18 + 512 * sizeof (short) / sizeof (int) + 272,
500 18 + 512 * sizeof (short) / sizeof (int) + 272,
501 18 + 512 * sizeof (short) / sizeof (int) + 272,
502 18 + 512 * sizeof (short) / sizeof (int) + 272,
503 18 + 512 * sizeof (short) / sizeof (int) + 272,
504 18 + 512 * sizeof (short) / sizeof (int) + 272,
505 18 + 512 * sizeof (short) / sizeof (int) + 272,
506 18 + 512 * sizeof (short) / sizeof (int) + 272,
507 18 + 512 * sizeof (short) / sizeof (int) + 272,
508 18 + 512 * sizeof (short) / sizeof (int) + 272,
509 18 + 512 * sizeof (short) / sizeof (int) + 272,
510 18 + 512 * sizeof (short) / sizeof (int) + 272,
511 18 + 512 * sizeof (short) / sizeof (int) + 272,
512 18 + 512 * sizeof (short) / sizeof (int) + 272,
513 18 + 512 * sizeof (short) / sizeof (int) + 272,
514 18 + 512 * sizeof (short) / sizeof (int) + 272,
515 18 + 512 * sizeof (short) / sizeof (int) + 272,
516 18 + 512 * sizeof (short) / sizeof (int) + 272,
517 18 + 512 * sizeof (short) / sizeof (int) + 272,
518 18 + 512 * sizeof (short) / sizeof (int) + 272,
519 18 + 512 * sizeof (short) / sizeof (int) + 272,
520 18 + 512 * sizeof (short) / sizeof (int) + 272,
521 18 + 512 * sizeof (short) / sizeof (int) + 272,
522 18 + 512 * sizeof (short) / sizeof (int) + 272,
523 18 + 512 * sizeof (short) / sizeof (int) + 272,
524 18 + 512 * sizeof (short) / sizeof (int) + 272,
525 18 + 512 * sizeof (short) / sizeof (int) + 272,
526 18 + 512 * sizeof (short) / sizeof (int) + 272,
527 18 + 512 * sizeof (short) / sizeof (int) + 272,
528 18 + 512 * sizeof (short) / sizeof (int) + 272,
529 18 + 512 * sizeof (short) / sizeof (int) + 272,
530 18 + 512 * sizeof (short) / sizeof (int) + 272,
531 18 + 512 * sizeof (short) / sizeof (int) + 272,
532 18 + 512 * sizeof (short) / sizeof (int) + 272,
533 18 + 512 * sizeof (short) / sizeof (int) + 272,
534 18 + 512 * sizeof (short) / sizeof (int) + 272,
535 18 + 512 * sizeof (short) / sizeof (int) + 272,
536 18 + 512 * sizeof (short) / sizeof (int) + 272,
537 18 + 512 * sizeof (short) / sizeof (int) + 272,
538 18 + 512 * sizeof (short) / sizeof (int) + 272,
539 18 + 512 * sizeof (short) / sizeof (int) + 272,
540 18 + 512 * sizeof (short) / sizeof (int) + 272,
541 18 + 512 * sizeof (short) / sizeof (int) + 272,
542 18 + 512 * sizeof (short) / sizeof (int) + 272,
543 18 + 512 * sizeof (short) / sizeof (int) + 272,
544 18 + 512 * sizeof (short) / sizeof (int) + 272,
545 18 + 512 * sizeof (short) / sizeof (int) + 272,
546 18 + 512 * sizeof (short) / sizeof (int) + 272,
547 18 + 512 * sizeof (short) / sizeof (int) + 272,
548 18 + 512 * sizeof (short) / sizeof (int) + 272,
549 18 + 512 * sizeof (short) / sizeof (int) + 272,
550 18 + 512 * sizeof (short) / sizeof (int) + 272,
551 18 + 512 * sizeof (short) / sizeof (int) + 272,
552 18 + 512 * sizeof (short) / sizeof (int) + 272,
553 18 + 512 * sizeof (short) / sizeof (int) + 272,
554 18 + 512 * sizeof (short) / sizeof (int) + 272,
555 18 + 512 * sizeof (short) / sizeof (int) + 272,
556 18 + 512 * sizeof (short) / sizeof (int) + 272,
557 18 + 512 * sizeof (short) / sizeof (int) + 272,
558 18 + 512 * sizeof (short) / sizeof (int) + 272,
559 18 + 512 * sizeof (short) / sizeof (int) + 272,
560 18 + 512 * sizeof (short) / sizeof (int) + 272,
561 18 + 512 * sizeof (short) / sizeof (int) + 272,
562 18 + 512 * sizeof (short) / sizeof (int) + 272,
563 18 + 512 * sizeof (short) / sizeof (int) + 272,
564 18 + 512 * sizeof (short) / sizeof (int) + 272,
565 18 + 512 * sizeof (short) / sizeof (int) + 272,
566 18 + 512 * sizeof (short) / sizeof (int) + 1184
567 },
568 {
569 0x00000000U, 0xFC00FFFEU, 0xF8000001U, 0x78000001U,
570 0x00000000U, 0xFBDFFBFFU, 0x00800000U, 0x00800000U,
571 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
572 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
573 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
574 0x00000000U, 0x00000000U, 0xFFFC003CU, 0xFFFFAFE0U,
575 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFDFU, 0x4020FFFFU,
576 0x000000B0U, 0x00000000U, 0x00000000U, 0x00400000U,
577 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
578 0x000003FCU, 0x00000000U, 0x00000000U, 0x00000000U,
579 0x00000000U, 0x00000000U, 0xFC000000U, 0x00000000U,
580 0xFFFEE600U, 0xFFFFFFFFU, 0x000000FFU, 0x00180000U,
581 0xFFFFFFFFU, 0x00000000U, 0xFFFFF800U, 0x00013C00U,
582 0x00000000U, 0x00000000U, 0xFFD00000U, 0x60003F9FU,
583 0x0002BFFFU, 0xFFFF0000U, 0x000007FFU, 0x00000000U,
584 0x00000000U, 0x0001FFC0U, 0x00000000U, 0xE3CFF800U,
585 0xFBC00000U, 0x7FFF3EEFU, 0x4E000000U, 0x00000000U,
586 0xFF830100U, 0x00000000U, 0xFFFFFC00U, 0xFFFFFFFFU,
587 0x0000000FU, 0xDC000000U, 0x00FEFFFFU, 0x0001003CU,
588 0x0000000EU, 0xD0000000U, 0x0080399FU, 0x6FFC000CU,
589 0x0000000EU, 0xD0000000U, 0x00023987U, 0x00630000U,
590 0x0000000EU, 0xD0000000U, 0x00003BBFU, 0xFC03000CU,
591 0x0000000EU, 0xD0000000U, 0x00E0399FU, 0x00FD000CU,
592 0x00000004U, 0xC0000000U, 0x00803DC7U, 0x07FF0000U,
593 0x0000001FU, 0xD0000000U, 0x00603DDFU, 0xFF80000CU,
594 0x0000001EU, 0xD0000000U, 0x00603DDFU, 0x0008000CU,
595 0x0000000FU, 0xD8000000U, 0x7F80BDDFU, 0x03FF000CU,
596 0x0000000EU, 0x00000000U, 0xFF5F8400U, 0x001C0000U,
597 0x00000000U, 0x80008000U, 0x0C008040U, 0x00000000U,
598 0x00000000U, 0x1FF20000U, 0x00007F00U, 0x00000000U,
599 0xFFFFFFFEU, 0xFFFFFC00U, 0x00000000U, 0xFFFE0000U,
600 0xFEFFE0FFU, 0xDFFFFFFFU, 0x07FFDFFFU, 0x00000000U,
601 0x00000000U, 0x7FFFF800U, 0xC3C0FC00U, 0x001E3F9DU,
602 0xFC00BFFCU, 0x00000000U, 0x00000000U, 0x08000000U,
603 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
604 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
605 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
606 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
607 0x00000000U, 0x00000000U, 0xE0000000U, 0x1FFFFFFFU,
608 0x03FF0000U, 0x00000000U, 0x00000000U, 0x00000000U,
609 0x00000001U, 0x00000000U, 0x00000000U, 0x00000000U,
610 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
611 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
612 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
613 0x00000000U, 0x00000000U, 0x00000000U, 0x00006000U,
614 0x18000000U, 0x00000000U, 0x00000000U, 0x00003800U,
615 0x003C0000U, 0x007C0000U, 0x000C0000U, 0x000C0000U,
616 0x00000000U, 0xFFF00000U, 0x2F7FFFFFU, 0x03FF0000U,
617 0x0000FFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
618 0x00000060U, 0x00000200U, 0x00000000U, 0x00000000U,
619 0x00000000U, 0x0FFF0FFFU, 0x00000031U, 0x00000000U,
620 0x00000000U, 0x00000000U, 0xC4000000U, 0xFFFFFFFFU,
621 0xCF800000U, 0x00000000U, 0x7FE00000U, 0x9FFFFFFFU,
622 0x00000000U, 0xFFFF3F7FU, 0x00007FFFU, 0x00000000U,
623 0x0000001FU, 0xFFF00000U, 0xFC00C01FU, 0xFFFFFFFFU,
624 0x00000007U, 0x00003FFEU, 0x00000000U, 0xF00FFFC0U,
625 0x00000000U, 0xF8FFFFF0U, 0x00000000U, 0xC0000000U,
626 0x00000000U, 0x00000000U, 0xFFFF00FFU, 0x039021FFU,
627 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
628 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU,
629 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
630 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
631 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
632 0x00000000U, 0xA0000000U, 0xE000E003U, 0x6000E000U,
633 0xFFFFF880U, 0xFFFFFCFFU, 0x7FFFFFFFU, 0x7FF1FFDFU,
634 0x00007FFFU, 0xFFFFFFFFU, 0xFFFF0001U, 0x0001FFFFU,
635 0xC1D0037BU, 0x0C0040AFU, 0xFFFFBC1FU, 0x00000000U,
636 0xFFFF0E00U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
637 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
638 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
639 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
640 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
641 0xFFFFFFFFU, 0x000003FFU, 0x000007FFU, 0xFFFFFFFFU,
642 0x0FFFFFFFU, 0x00000000U, 0x00000000U, 0xFFFFFC00U,
643 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
644 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
645 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
646 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
647 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFCFFFFFU,
648 0xFFBFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
649 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
650 0x00000000U, 0x00000000U, 0x00000000U, 0xFE0387E0U,
651 0x00000000U, 0x00000000U, 0x00000000U, 0x80010000U,
652 0x00000000U, 0x00000000U, 0x00000000U, 0xFFFFFFFFU,
653 0xFFFFFFFFU, 0xFFFF7FFFU, 0x3FFFFFFFU, 0x00000000U,
654 0xFBFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000FFFFFU,
655 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
656 0xFFFFFFFFU, 0xFFFFFFFFU, 0x003FFFFFU, 0xFFFF0000U,
657 0xFFFFFF1EU, 0xE0C1FC01U, 0x00000000U, 0x00000000U,
658 0x1E000000U, 0x00000001U, 0x00000000U, 0x08000000U,
659 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
660 0xFFFF0000U, 0x00000000U, 0xFFFFFFFFU, 0x0000803FU,
661 0x7FFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
662 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
663 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
664 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
665 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
666 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
667 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
668 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU,
669 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
670 0xFFFF0000U, 0xFFFFFFFFU, 0x0000007FU, 0xC0000000U,
671 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
672 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
673 0x0000E000U, 0x00000000U, 0x00000000U, 0x7FFF8000U,
674 0xC0000000U, 0x00000000U, 0x00000000U, 0x00FF0000U,
675 0x007FFFFFU, 0x00000003U, 0x00000000U, 0x00000000U,
676 0x00000600U, 0x00000000U, 0x00000000U, 0x00000000U,
677 0x00000844U, 0x03FF1FF8U, 0x00000000U, 0x00F00000U,
678 0x00000003U, 0xFFF00000U, 0x0000C03FU, 0x9703FFFFU,
679 0x00000000U, 0x0000FFC0U, 0x800FFF80U, 0x00000000U,
680 0x0000000FU, 0xFFF80000U, 0xC0003FFFU, 0x00000020U,
681 0x00000000U, 0x007FFE00U, 0xF0003008U, 0x3B800000U,
682 0x00000000U, 0xC19D0000U, 0xC0000002U, 0x0063F800U,
683 0x00000000U, 0x00000000U, 0x08000000U, 0x00000C00U,
684 0x00000000U, 0x00000000U, 0x00000000U, 0x00003FF8U,
685 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
686 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
687 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
688 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
689 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
690 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
691 0x40000000U, 0x00000200U, 0x00000000U, 0x00000000U,
692 0x00000000U, 0xFFFC0000U, 0x00000007U, 0x00000000U,
693 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
694 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
695 0x00000000U, 0xC0000000U, 0x0000FFFFU, 0x00000000U,
696 0x00000000U, 0x00000000U, 0x00008000U, 0xF0000000U,
697 0x03FFFFFFU, 0xFFFFFFFFU, 0xFFF7FFFFU, 0x00000F7FU,
698 0x00000000U, 0x00000000U, 0x00000000U, 0x80000000U,
699 0xFC00FFFEU, 0xF8000001U, 0xF8000001U, 0x0000003FU,
700 0x00000000U, 0x00000000U, 0x00000000U, 0x3E007F7FU,
701 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
702 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
703 0xFFFFFF87U, 0xFF8FFFFFU, 0x00000000U, 0xFFE00000U,
704 0x1FFF7FFFU, 0x00000001U, 0xFFFF0000U, 0x3FFFFFFFU,
705 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
706 0x00000000U, 0x00000000U, 0x00000000U, 0x0FFFFFFFU,
707 0x00000000U, 0x0000000FU, 0x00000000U, 0x07C00000U,
708 0x80000000U, 0x00000000U, 0x00010000U, 0x00000000U,
709 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
710 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
711 0x00000000U, 0x00000000U, 0x00000000U, 0x00008000U,
712 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
713 0x00000000U, 0x00000000U, 0xFF800000U, 0xFF800000U,
714 0x00000000U, 0x0000FF80U, 0x00000000U, 0xF8000000U,
715 0x8FC00000U, 0x80000000U, 0x00000000U, 0x00000000U,
716 0x00000000U, 0x30000000U, 0xFFFCFFFFU, 0xFFFFFFFFU,
717 0x0000F06EU, 0x87000000U, 0x01FF01FFU, 0xE0000000U,
718 0xE0000000U, 0x00000000U, 0x00000100U, 0x007FF860U,
719 0x00000000U, 0xFE000000U, 0xFF000000U, 0xFF000000U,
720 0x1E000000U, 0x0000FE00U, 0x00000000U, 0x00000000U,
721 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
722 0x00000000U, 0x00000000U, 0x00000000U, 0xFC000000U,
723 0x00000000U, 0x000000F0U, 0x00000000U, 0x00007E00U,
724 0x0000C000U, 0x00000000U, 0x00000000U, 0x00000000U,
725 0x00000000U, 0x00000000U, 0x00000000U, 0x7FFFFFFFU,
726 0x00000000U, 0x00003800U, 0x00000000U, 0xF0000000U,
727 0xE0000000U, 0x0000007FU, 0x03FFFFC0U, 0x00000000U,
728 0x000003FCU, 0x00000000U, 0x00000FE0U, 0x00000000U,
729 0x00000007U, 0xFF000000U, 0xFFFC3FFFU, 0x8019003FU,
730 0x00000007U, 0xFFFF0000U, 0x00002007U, 0x00000000U,
731 0x00000007U, 0x001FFF80U, 0x0000006FU, 0x00380000U,
732 0x00000007U, 0xFFF80000U, 0xE800FFE1U, 0x001FFFFEU,
733 0x00000000U, 0x7FFFF000U, 0x00000002U, 0x00000000U,
734 0x00000000U, 0x00000200U, 0x80000000U, 0x000007FFU,
735 0x0000000FU, 0xD8000000U, 0x0080399FU, 0x001F1FCCU,
736 0x00000000U, 0xFF000000U, 0x01B5F7A5U, 0x00000006U,
737 0x00000000U, 0xFFE00000U, 0x6C00F87FU, 0x00000000U,
738 0x00000000U, 0xFFFF0000U, 0x0000004FU, 0x00000000U,
739 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
740 0x00000000U, 0xFF3F8000U, 0x30FFFFFFU, 0x00000000U,
741 0x00000000U, 0xFFFF0000U, 0x0000000FU, 0x00001FFFU,
742 0x00000000U, 0x02FFF800U, 0x00000000U, 0x00000000U,
743 0xE0000000U, 0xFC000FFFU, 0x00000000U, 0x00000000U,
744 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
745 0x00000000U, 0x0FFFF000U, 0x00000000U, 0x00000000U,
746 0x00000000U, 0x00000000U, 0x00000000U, 0x0007FC00U,
747 0x00000000U, 0x79BF0000U, 0x0000007DU, 0x00000000U,
748 0x00000000U, 0x00000000U, 0xFCFE0000U, 0x00000015U,
749 0x000007FEU, 0xFBF80000U, 0x0FFE00FFU, 0x00000000U,
750 0xDFFFFC00U, 0x00000007U, 0x00000000U, 0x00000000U,
751 0x000003FFU, 0x00000000U, 0x00000000U, 0x00000000U,
752 0x00000000U, 0x00000000U, 0x00000000U, 0x00000002U,
753 0x00000000U, 0xFF7F8000U, 0xFC00003EU, 0x00031FFFU,
754 0xFFFC0000U, 0x007FFEFFU, 0x00000000U, 0x00000000U,
755 0x00000000U, 0xB47E0000U, 0x000000BFU, 0x00000000U,
756 0x00FB7C00U, 0x00000000U, 0x00000000U, 0x00000000U,
757 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
758 0x00000000U, 0x00000000U, 0x00000000U, 0x01F80000U,
759 0x0000000BU, 0xC7F00000U, 0x0400FFFFU, 0x00000000U,
760 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0x8003FFFFU,
761 0x00000000U, 0x00000000U, 0x00000000U, 0x001F0000U,
762 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
763 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
764 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
765 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
766 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
767 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
768 0x00000000U, 0x00000000U, 0x00000000U, 0x00060000U,
769 0x00000000U, 0xFFFF0000U, 0x003FFF81U, 0x00000000U,
770 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
771 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
772 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
773 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
774 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
775 0xC0000000U, 0x0000FFFFU, 0x00000000U, 0x00000000U,
776 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
777 0x00000000U, 0x00000000U, 0x00000000U, 0x0000C000U,
778 0x00000000U, 0x00000000U, 0x00000000U, 0x003F0000U,
779 0x00000000U, 0xFFFF0000U, 0xF8000030U, 0x00000003U,
780 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
781 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
782 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
783 0x00000000U, 0x00000000U, 0x00000000U, 0x0000E000U,
784 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
785 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
786 0x07FFFFFFU, 0x00000000U, 0x00000000U, 0x00000000U,
787 0x00000000U, 0x00000000U, 0xFFFE8000U, 0xFFFFFFFFU,
788 0x000780FFU, 0x00000000U, 0x00000000U, 0x00030014U,
789 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
790 0xF0000000U, 0x0000000FU, 0x00000000U, 0x00000000U,
791 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
792 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
793 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
794 0xFFFFFFFFU, 0xFFFFFFFFU, 0x003FFFFFU, 0x00000000U,
795 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
796 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
797 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
798 0xFFFFFFFFU, 0x000FFFFFU, 0x00000000U, 0x00000000U,
799 0xFFFFFFFFU, 0xFFFF3FFFU, 0xFFFF007FU, 0xFFFFFFFFU,
800 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000000FU, 0x00000000U,
801 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
802 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x003FFFFFU,
803 0xFFFFFFFFU, 0xFFFFFE7FU, 0xFFFFFFFFU, 0xFFFFFFFFU,
804 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000007FFU,
805 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000003FU, 0x00000000U,
806 0x00000000U, 0x00000000U, 0x000FFFFFU, 0x000FFFFFU,
807 0xFFFFFFFFU, 0xFFFFFFFFU, 0x007FFFFFU, 0x01FFFFFFU,
808 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
809 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
810 0x00000000U, 0x00000000U, 0x08000002U, 0x08000000U,
811 0x00200000U, 0x00200000U, 0x00008000U, 0x00008000U,
812 0x00000200U, 0x00000200U, 0x00000008U, 0x00000000U,
813 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
814 0xF8000FFFU, 0x0000FFFEU, 0x00000000U, 0x00000000U,
815 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
816 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
817 0xF9FFFF7FU, 0x000007DBU, 0x00000000U, 0x00000000U,
818 0x00008000U, 0x00000000U, 0x00000000U, 0x00000000U,
819 0x00000000U, 0x007F0000U, 0x00008000U, 0x00000000U,
820 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
821 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
822 0x00000000U, 0x00004000U, 0x00000000U, 0x8000F000U,
823 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
824 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
825 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
826 0x00000000U, 0x00000000U, 0x00000000U, 0x0000F000U,
827 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
828 0x00000000U, 0x00000000U, 0x00000000U, 0x8000C000U,
829 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
830 0x00000000U, 0x00000000U, 0x007FFF80U, 0x00000000U,
831 0x00000000U, 0x00000000U, 0xC00007F0U, 0x00000000U,
832 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
833 0x00000000U, 0x00000000U, 0x00000000U, 0xFFFE0000U,
834 0xFFFFFFFFU, 0x001FFFFFU, 0x00000000U, 0x00000000U,
835 0xFFFFFFFEU, 0x3FFFFFFFU, 0x00000000U, 0x00000000U,
836 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
837 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
838 0x00000000U, 0x00000000U, 0x00000000U, 0x00030000U,
839 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
840 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
841 0xFFFFFFFFU, 0xFFFF0FFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
842 0x000FFFFFU, 0xFFFE7FFFU, 0xFFFEFFFEU, 0x003FFFFFU,
843 0x0000FFFFU, 0x0000E000U, 0x0000FC00U, 0x0000FC00U,
844 0xFFFFF800U, 0x00003FDFU, 0x00000000U, 0x00000000U,
845 0xFFFF0007U, 0x0FFFFFFFU, 0x000301FFU, 0x0000003FU,
846 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
847 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
848 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
849 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
850 0xFFFFFFFFU, 0xFFFFFFFFU, 0xF0FFFFFFU, 0x1FFF1FFFU,
851 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xF87FFFFFU,
852 0xFFFFFFFFU, 0xFFFFFFFFU, 0x03FFFFFFU, 0x00010FFFU,
853 0xFFFF0FFFU, 0xFFFFFFFFU, 0x03FF00FFU, 0xFFFFFFFFU,
854 0xFFFF00FFU, 0x0FFF3FFFU, 0x00000003U, 0x00000000U,
855 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
856 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
857 0xFFFFFFFFU, 0xFFFFFFFFU, 0x000FFFFFU, 0x1FFF3FFFU,
858 0xFFFF83FFU, 0xFFFFFFFFU, 0x9FFFC07FU, 0x01FF03FFU,
859 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
860 0xFFF7FFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000FFFFU,
861 0x00000002U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
862 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
863 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
864 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000FFFFU,
865 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
866 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
867 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
868 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x3FFFFFFFU
869 }
870};
diff --git a/gl/unictype/ctype_space.c b/gl/unictype/ctype_space.c
new file mode 100644
index 00000000..4c032398
--- /dev/null
+++ b/gl/unictype/ctype_space.c
@@ -0,0 +1,32 @@
1/* ISO C <ctype.h> like properties of Unicode characters.
2 Copyright (C) 2002, 2006-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2002.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include "unictype.h"
22
23#include "bitmap.h"
24
25/* Define u_is_space table. */
26#include "ctype_space.h"
27
28bool
29uc_is_space (ucs4_t uc)
30{
31 return bitmap_lookup (&u_is_space, uc);
32}
diff --git a/gl/unictype/ctype_space.h b/gl/unictype/ctype_space.h
new file mode 100644
index 00000000..93ed2467
--- /dev/null
+++ b/gl/unictype/ctype_space.h
@@ -0,0 +1,184 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* ISO C <ctype.h> like properties of Unicode characters. */
3/* Generated automatically by gen-uni-tables.c for Unicode 16.0.0. */
4
5/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
6
7 This file is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 This file is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19
20#define header_0 16
21#define header_2 9
22#define header_3 127
23#define header_4 15
24static const
25struct
26 {
27 int header[1];
28 int level1[1];
29 short level2[1 << 7];
30 unsigned int level3[4 << 4];
31 }
32u_is_space =
33{
34 { 1 },
35 { 2 * sizeof (int) / sizeof (short) + 0 },
36 {
37 2 + 128 * sizeof (short) / sizeof (int) + 0,
38 -1,
39 -1,
40 -1,
41 -1,
42 -1,
43 -1,
44 -1,
45 -1,
46 -1,
47 -1,
48 2 + 128 * sizeof (short) / sizeof (int) + 16,
49 -1,
50 -1,
51 -1,
52 -1,
53 2 + 128 * sizeof (short) / sizeof (int) + 32,
54 -1,
55 -1,
56 -1,
57 -1,
58 -1,
59 -1,
60 -1,
61 2 + 128 * sizeof (short) / sizeof (int) + 48,
62 -1,
63 -1,
64 -1,
65 -1,
66 -1,
67 -1,
68 -1,
69 -1,
70 -1,
71 -1,
72 -1,
73 -1,
74 -1,
75 -1,
76 -1,
77 -1,
78 -1,
79 -1,
80 -1,
81 -1,
82 -1,
83 -1,
84 -1,
85 -1,
86 -1,
87 -1,
88 -1,
89 -1,
90 -1,
91 -1,
92 -1,
93 -1,
94 -1,
95 -1,
96 -1,
97 -1,
98 -1,
99 -1,
100 -1,
101 -1,
102 -1,
103 -1,
104 -1,
105 -1,
106 -1,
107 -1,
108 -1,
109 -1,
110 -1,
111 -1,
112 -1,
113 -1,
114 -1,
115 -1,
116 -1,
117 -1,
118 -1,
119 -1,
120 -1,
121 -1,
122 -1,
123 -1,
124 -1,
125 -1,
126 -1,
127 -1,
128 -1,
129 -1,
130 -1,
131 -1,
132 -1,
133 -1,
134 -1,
135 -1,
136 -1,
137 -1,
138 -1,
139 -1,
140 -1,
141 -1,
142 -1,
143 -1,
144 -1,
145 -1,
146 -1,
147 -1,
148 -1,
149 -1,
150 -1,
151 -1,
152 -1,
153 -1,
154 -1,
155 -1,
156 -1,
157 -1,
158 -1,
159 -1,
160 -1,
161 -1,
162 -1,
163 -1,
164 -1
165 },
166 {
167 0x00003E00U, 0x00000001U, 0x00000000U, 0x00000000U,
168 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
169 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
170 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
171 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
172 0x00000001U, 0x00000000U, 0x00000000U, 0x00000000U,
173 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
174 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
175 0x0000077FU, 0x00000300U, 0x80000000U, 0x00000000U,
176 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
177 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
178 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
179 0x00000001U, 0x00000000U, 0x00000000U, 0x00000000U,
180 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
181 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
182 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U
183 }
184};
diff --git a/gl/unictype/ctype_upper.c b/gl/unictype/ctype_upper.c
new file mode 100644
index 00000000..af2c3fe6
--- /dev/null
+++ b/gl/unictype/ctype_upper.c
@@ -0,0 +1,32 @@
1/* ISO C <ctype.h> like properties of Unicode characters.
2 Copyright (C) 2002, 2006-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2002.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include "unictype.h"
22
23#include "bitmap.h"
24
25/* Define u_is_upper table. */
26#include "ctype_upper.h"
27
28bool
29uc_is_upper (ucs4_t uc)
30{
31 return bitmap_lookup (&u_is_upper, uc);
32}
diff --git a/gl/unictype/ctype_upper.h b/gl/unictype/ctype_upper.h
new file mode 100644
index 00000000..ef527809
--- /dev/null
+++ b/gl/unictype/ctype_upper.h
@@ -0,0 +1,367 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* ISO C <ctype.h> like properties of Unicode characters. */
3/* Generated automatically by gen-uni-tables.c for Unicode 16.0.0. */
4
5/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
6
7 This file is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 This file is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19
20#define header_0 16
21#define header_2 9
22#define header_3 127
23#define header_4 15
24static const
25struct
26 {
27 int header[1];
28 int level1[2];
29 short level2[2 << 7];
30 unsigned int level3[17 << 4];
31 }
32u_is_upper =
33{
34 { 2 },
35 {
36 3 * sizeof (int) / sizeof (short) + 0,
37 3 * sizeof (int) / sizeof (short) + 128
38 },
39 {
40 3 + 256 * sizeof (short) / sizeof (int) + 0,
41 3 + 256 * sizeof (short) / sizeof (int) + 16,
42 3 + 256 * sizeof (short) / sizeof (int) + 32,
43 -1,
44 -1,
45 -1,
46 -1,
47 -1,
48 3 + 256 * sizeof (short) / sizeof (int) + 48,
49 3 + 256 * sizeof (short) / sizeof (int) + 64,
50 -1,
51 -1,
52 -1,
53 -1,
54 3 + 256 * sizeof (short) / sizeof (int) + 80,
55 3 + 256 * sizeof (short) / sizeof (int) + 96,
56 3 + 256 * sizeof (short) / sizeof (int) + 112,
57 -1,
58 3 + 256 * sizeof (short) / sizeof (int) + 128,
59 -1,
60 -1,
61 -1,
62 3 + 256 * sizeof (short) / sizeof (int) + 144,
63 -1,
64 -1,
65 -1,
66 -1,
67 -1,
68 -1,
69 -1,
70 -1,
71 -1,
72 -1,
73 -1,
74 -1,
75 -1,
76 -1,
77 -1,
78 -1,
79 -1,
80 -1,
81 -1,
82 -1,
83 -1,
84 -1,
85 -1,
86 -1,
87 -1,
88 -1,
89 -1,
90 -1,
91 -1,
92 -1,
93 -1,
94 -1,
95 -1,
96 -1,
97 -1,
98 -1,
99 -1,
100 -1,
101 -1,
102 -1,
103 -1,
104 -1,
105 -1,
106 -1,
107 -1,
108 -1,
109 -1,
110 -1,
111 -1,
112 -1,
113 -1,
114 -1,
115 -1,
116 -1,
117 -1,
118 -1,
119 -1,
120 -1,
121 -1,
122 -1,
123 3 + 256 * sizeof (short) / sizeof (int) + 160,
124 -1,
125 -1,
126 -1,
127 -1,
128 -1,
129 -1,
130 -1,
131 -1,
132 -1,
133 -1,
134 -1,
135 -1,
136 -1,
137 -1,
138 -1,
139 -1,
140 -1,
141 -1,
142 -1,
143 -1,
144 -1,
145 -1,
146 -1,
147 -1,
148 -1,
149 -1,
150 -1,
151 -1,
152 -1,
153 -1,
154 -1,
155 -1,
156 -1,
157 -1,
158 -1,
159 -1,
160 -1,
161 -1,
162 -1,
163 -1,
164 -1,
165 -1,
166 -1,
167 3 + 256 * sizeof (short) / sizeof (int) + 176,
168 -1,
169 -1,
170 3 + 256 * sizeof (short) / sizeof (int) + 192,
171 -1,
172 -1,
173 -1,
174 3 + 256 * sizeof (short) / sizeof (int) + 208,
175 -1,
176 -1,
177 -1,
178 -1,
179 -1,
180 3 + 256 * sizeof (short) / sizeof (int) + 224,
181 -1,
182 -1,
183 -1,
184 -1,
185 -1,
186 -1,
187 -1,
188 -1,
189 -1,
190 -1,
191 -1,
192 -1,
193 -1,
194 -1,
195 -1,
196 -1,
197 -1,
198 -1,
199 -1,
200 -1,
201 -1,
202 -1,
203 -1,
204 -1,
205 -1,
206 -1,
207 -1,
208 -1,
209 -1,
210 -1,
211 -1,
212 -1,
213 -1,
214 -1,
215 -1,
216 -1,
217 -1,
218 -1,
219 -1,
220 -1,
221 -1,
222 -1,
223 3 + 256 * sizeof (short) / sizeof (int) + 240,
224 -1,
225 -1,
226 -1,
227 -1,
228 -1,
229 -1,
230 -1,
231 -1,
232 -1,
233 -1,
234 -1,
235 -1,
236 -1,
237 -1,
238 -1,
239 -1,
240 -1,
241 -1,
242 -1,
243 -1,
244 -1,
245 -1,
246 -1,
247 -1,
248 -1,
249 -1,
250 -1,
251 -1,
252 -1,
253 -1,
254 -1,
255 -1,
256 -1,
257 -1,
258 -1,
259 -1,
260 -1,
261 -1,
262 -1,
263 -1,
264 -1,
265 -1,
266 -1,
267 -1,
268 -1,
269 -1,
270 -1,
271 -1,
272 -1,
273 -1,
274 -1,
275 -1,
276 -1,
277 -1,
278 -1,
279 -1,
280 -1,
281 -1,
282 -1,
283 -1,
284 3 + 256 * sizeof (short) / sizeof (int) + 256,
285 -1,
286 -1,
287 -1,
288 -1,
289 -1,
290 -1,
291 -1,
292 -1,
293 -1,
294 -1,
295 -1
296 },
297 {
298 0x00000000U, 0x00000000U, 0x07FFFFFEU, 0x00000000U,
299 0x00000000U, 0x00000000U, 0x7F7FFFFFU, 0x00000000U,
300 0x55555555U, 0xAA555555U, 0x555554AAU, 0x2B555555U,
301 0xB1DBCED6U, 0x11AED2D5U, 0x4AAAADB0U, 0x55D65555U,
302 0x55555555U, 0x6C055555U, 0x0000557AU, 0x00000000U,
303 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
304 0x00000000U, 0x00000000U, 0x00000000U, 0x80450000U,
305 0xFFFED740U, 0x00000FFBU, 0x55008000U, 0xE6905555U,
306 0xFFFFFFFFU, 0x0000FFFFU, 0x00000000U, 0x55555555U,
307 0x55555401U, 0x55555555U, 0x55552AABU, 0x55555555U,
308 0x55555555U, 0xFFFE5555U, 0x007FFFFFU, 0x00000000U,
309 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
310 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
311 0x00000000U, 0xFFFFFFFFU, 0x000020BFU, 0x00000000U,
312 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
313 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
314 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
315 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
316 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
317 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x003FFFFFU,
318 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
319 0xFFFF0200U, 0xE7FFFFFFU, 0x00000000U, 0x00000000U,
320 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
321 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
322 0x55555555U, 0x55555555U, 0x55555555U, 0x55555555U,
323 0x40155555U, 0x55555555U, 0x55555555U, 0x55555555U,
324 0x3F00FF00U, 0xFF00FF00U, 0xAA003F00U, 0x0000FF00U,
325 0xFF00FF00U, 0x1F00FF00U, 0x0F001F00U, 0x1F001F00U,
326 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
327 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
328 0x00000000U, 0x00040C40U, 0x00000000U, 0x0000FFFFU,
329 0x00000008U, 0x00000000U, 0x00000000U, 0x00000000U,
330 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
331 0x00000000U, 0xFFC00000U, 0x0000FFFFU, 0x00000000U,
332 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
333 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
334 0xFFFFFFFFU, 0x0000FFFFU, 0x00000000U, 0xC025EA9DU,
335 0x55555555U, 0x55555555U, 0x55555555U, 0x00042805U,
336 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
337 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
338 0x00000000U, 0x00000000U, 0x55555555U, 0x00001555U,
339 0x05555555U, 0x00000000U, 0x00000000U, 0x00000000U,
340 0x00000000U, 0x55545554U, 0x55555555U, 0x6A005555U,
341 0x55452855U, 0x555F7D55U, 0x15411AF5U, 0x00200000U,
342 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
343 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
344 0x00000000U, 0x07FFFFFEU, 0x00000000U, 0x00000000U,
345 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
346 0xFFFFFFFFU, 0x000000FFU, 0x00000000U, 0x00000000U,
347 0x00000000U, 0xFFFF0000U, 0x000FFFFFU, 0x00000000U,
348 0x00000000U, 0x00000000U, 0x00000000U, 0xF7FF0000U,
349 0x0037F7FFU, 0x00000000U, 0x00000000U, 0x00000000U,
350 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
351 0xFFFFFFFFU, 0x0007FFFFU, 0x00000000U, 0x00000000U,
352 0x00000000U, 0x00000000U, 0xFFFF0000U, 0x0000003FU,
353 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
354 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
355 0x00000000U, 0xFFFFFFFFU, 0x00000000U, 0x00000000U,
356 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
357 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
358 0x00000000U, 0x00000000U, 0xFFFFFFFFU, 0x00000000U,
359 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
360 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
361 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
362 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
363 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
364 0xFFFFFFFFU, 0x00000003U, 0x00000000U, 0x00000000U,
365 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U
366 }
367};
diff --git a/gl/unictype/ctype_xdigit.c b/gl/unictype/ctype_xdigit.c
new file mode 100644
index 00000000..ee4b2ea4
--- /dev/null
+++ b/gl/unictype/ctype_xdigit.c
@@ -0,0 +1,32 @@
1/* ISO C <ctype.h> like properties of Unicode characters.
2 Copyright (C) 2002, 2006-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2002.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include "unictype.h"
22
23#include "bitmap.h"
24
25/* Define u_is_xdigit table. */
26#include "ctype_xdigit.h"
27
28bool
29uc_is_xdigit (ucs4_t uc)
30{
31 return bitmap_lookup (&u_is_xdigit, uc);
32}
diff --git a/gl/unictype/ctype_xdigit.h b/gl/unictype/ctype_xdigit.h
new file mode 100644
index 00000000..c0b2ac05
--- /dev/null
+++ b/gl/unictype/ctype_xdigit.h
@@ -0,0 +1,172 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* ISO C <ctype.h> like properties of Unicode characters. */
3/* Generated automatically by gen-uni-tables.c for Unicode 16.0.0. */
4
5/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
6
7 This file is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 This file is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19
20#define header_0 16
21#define header_2 9
22#define header_3 127
23#define header_4 15
24static const
25struct
26 {
27 int header[1];
28 int level1[1];
29 short level2[1 << 7];
30 unsigned int level3[1 << 4];
31 }
32u_is_xdigit =
33{
34 { 1 },
35 { 2 * sizeof (int) / sizeof (short) + 0 },
36 {
37 2 + 128 * sizeof (short) / sizeof (int) + 0,
38 -1,
39 -1,
40 -1,
41 -1,
42 -1,
43 -1,
44 -1,
45 -1,
46 -1,
47 -1,
48 -1,
49 -1,
50 -1,
51 -1,
52 -1,
53 -1,
54 -1,
55 -1,
56 -1,
57 -1,
58 -1,
59 -1,
60 -1,
61 -1,
62 -1,
63 -1,
64 -1,
65 -1,
66 -1,
67 -1,
68 -1,
69 -1,
70 -1,
71 -1,
72 -1,
73 -1,
74 -1,
75 -1,
76 -1,
77 -1,
78 -1,
79 -1,
80 -1,
81 -1,
82 -1,
83 -1,
84 -1,
85 -1,
86 -1,
87 -1,
88 -1,
89 -1,
90 -1,
91 -1,
92 -1,
93 -1,
94 -1,
95 -1,
96 -1,
97 -1,
98 -1,
99 -1,
100 -1,
101 -1,
102 -1,
103 -1,
104 -1,
105 -1,
106 -1,
107 -1,
108 -1,
109 -1,
110 -1,
111 -1,
112 -1,
113 -1,
114 -1,
115 -1,
116 -1,
117 -1,
118 -1,
119 -1,
120 -1,
121 -1,
122 -1,
123 -1,
124 -1,
125 -1,
126 -1,
127 -1,
128 -1,
129 -1,
130 -1,
131 -1,
132 -1,
133 -1,
134 -1,
135 -1,
136 -1,
137 -1,
138 -1,
139 -1,
140 -1,
141 -1,
142 -1,
143 -1,
144 -1,
145 -1,
146 -1,
147 -1,
148 -1,
149 -1,
150 -1,
151 -1,
152 -1,
153 -1,
154 -1,
155 -1,
156 -1,
157 -1,
158 -1,
159 -1,
160 -1,
161 -1,
162 -1,
163 -1,
164 -1
165 },
166 {
167 0x00000000U, 0x03FF0000U, 0x0000007EU, 0x0000007EU,
168 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
169 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
170 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U
171 }
172};
diff --git a/gl/uninorm.h b/gl/uninorm.h
new file mode 100644
index 00000000..f6815c49
--- /dev/null
+++ b/gl/uninorm.h
@@ -0,0 +1,256 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* Normalization forms (composition and decomposition) of Unicode strings.
3 Copyright (C) 2001-2002, 2009-2025 Free Software Foundation, Inc.
4 Written by Bruno Haible <bruno@clisp.org>, 2009.
5
6 This file is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
10
11 This file is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18
19#ifndef _UNINORM_H
20#define _UNINORM_H
21
22/* Get size_t. */
23#include <stddef.h>
24
25#include "unitypes.h"
26
27#if 0
28# include <unistring/woe32dll.h>
29#else
30# define LIBUNISTRING_DLL_VARIABLE
31#endif
32
33
34#ifdef __cplusplus
35extern "C" {
36#endif
37
38
39/* Conventions:
40
41 All functions prefixed with u8_ operate on UTF-8 encoded strings.
42 Their unit is an uint8_t (1 byte).
43
44 All functions prefixed with u16_ operate on UTF-16 encoded strings.
45 Their unit is an uint16_t (a 2-byte word).
46
47 All functions prefixed with u32_ operate on UCS-4 encoded strings.
48 Their unit is an uint32_t (a 4-byte word).
49
50 All argument pairs (s, n) denote a Unicode string s[0..n-1] with exactly
51 n units.
52
53 Functions returning a string result take a (resultbuf, lengthp) argument
54 pair. If resultbuf is not NULL and the result fits into *lengthp units,
55 it is put in resultbuf, and resultbuf is returned. Otherwise, a freshly
56 allocated string is returned. In both cases, *lengthp is set to the
57 length (number of units) of the returned string. In case of error,
58 NULL is returned and errno is set. */
59
60
61enum
62{
63 UC_DECOMP_CANONICAL,/* Canonical decomposition. */
64 UC_DECOMP_FONT, /* <font> A font variant (e.g. a blackletter form). */
65 UC_DECOMP_NOBREAK, /* <noBreak> A no-break version of a space or hyphen. */
66 UC_DECOMP_INITIAL, /* <initial> An initial presentation form (Arabic). */
67 UC_DECOMP_MEDIAL, /* <medial> A medial presentation form (Arabic). */
68 UC_DECOMP_FINAL, /* <final> A final presentation form (Arabic). */
69 UC_DECOMP_ISOLATED,/* <isolated> An isolated presentation form (Arabic). */
70 UC_DECOMP_CIRCLE, /* <circle> An encircled form. */
71 UC_DECOMP_SUPER, /* <super> A superscript form. */
72 UC_DECOMP_SUB, /* <sub> A subscript form. */
73 UC_DECOMP_VERTICAL,/* <vertical> A vertical layout presentation form. */
74 UC_DECOMP_WIDE, /* <wide> A wide (or zenkaku) compatibility character. */
75 UC_DECOMP_NARROW, /* <narrow> A narrow (or hankaku) compatibility character. */
76 UC_DECOMP_SMALL, /* <small> A small variant form (CNS compatibility). */
77 UC_DECOMP_SQUARE, /* <square> A CJK squared font variant. */
78 UC_DECOMP_FRACTION,/* <fraction> A vulgar fraction form. */
79 UC_DECOMP_COMPAT /* <compat> Otherwise unspecified compatibility character. */
80};
81
82/* Maximum size of decomposition of a single Unicode character. */
83#define UC_DECOMPOSITION_MAX_LENGTH 32
84
85/* Return the character decomposition mapping of a Unicode character.
86 DECOMPOSITION must point to an array of at least UC_DECOMPOSITION_MAX_LENGTH
87 ucs_t elements.
88 When a decomposition exists, DECOMPOSITION[0..N-1] and *DECOMP_TAG are
89 filled and N is returned. Otherwise -1 is returned. */
90extern int
91 uc_decomposition (ucs4_t uc, int *decomp_tag, ucs4_t *decomposition);
92
93/* Return the canonical character decomposition mapping of a Unicode character.
94 DECOMPOSITION must point to an array of at least UC_DECOMPOSITION_MAX_LENGTH
95 ucs_t elements.
96 When a decomposition exists, DECOMPOSITION[0..N-1] is filled and N is
97 returned. Otherwise -1 is returned. */
98extern int
99 uc_canonical_decomposition (ucs4_t uc, ucs4_t *decomposition);
100
101
102/* Attempt to combine the Unicode characters uc1, uc2.
103 uc1 is known to have canonical combining class 0.
104 Return the combination of uc1 and uc2, if it exists.
105 Return 0 otherwise.
106 Not all decompositions can be recombined using this function. See the
107 Unicode file CompositionExclusions.txt for details. */
108extern ucs4_t
109 uc_composition (ucs4_t uc1, ucs4_t uc2)
110 _UC_ATTRIBUTE_CONST;
111
112
113/* An object of type uninorm_t denotes a Unicode normalization form. */
114struct unicode_normalization_form;
115typedef const struct unicode_normalization_form *uninorm_t;
116
117/* UNINORM_NFD: Normalization form D: canonical decomposition. */
118extern LIBUNISTRING_DLL_VARIABLE const struct unicode_normalization_form uninorm_nfd;
119#define UNINORM_NFD (&uninorm_nfd)
120
121/* UNINORM_NFC: Normalization form C: canonical decomposition, then
122 canonical composition. */
123extern LIBUNISTRING_DLL_VARIABLE const struct unicode_normalization_form uninorm_nfc;
124#define UNINORM_NFC (&uninorm_nfc)
125
126/* UNINORM_NFKD: Normalization form KD: compatibility decomposition. */
127extern LIBUNISTRING_DLL_VARIABLE const struct unicode_normalization_form uninorm_nfkd;
128#define UNINORM_NFKD (&uninorm_nfkd)
129
130/* UNINORM_NFKC: Normalization form KC: compatibility decomposition, then
131 canonical composition. */
132extern LIBUNISTRING_DLL_VARIABLE const struct unicode_normalization_form uninorm_nfkc;
133#define UNINORM_NFKC (&uninorm_nfkc)
134
135/* Test whether a normalization form does compatibility decomposition. */
136#define uninorm_is_compat_decomposing(nf) \
137 ((* (const unsigned int *) (nf) >> 0) & 1)
138
139/* Test whether a normalization form includes canonical composition. */
140#define uninorm_is_composing(nf) \
141 ((* (const unsigned int *) (nf) >> 1) & 1)
142
143/* Return the decomposing variant of a normalization form.
144 This maps NFC,NFD -> NFD and NFKC,NFKD -> NFKD. */
145extern uninorm_t
146 uninorm_decomposing_form (uninorm_t nf)
147 _UC_ATTRIBUTE_PURE;
148
149
150/* Return the specified normalization form of a string. */
151extern uint8_t *
152 u8_normalize (uninorm_t nf, const uint8_t *s, size_t n,
153 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
154extern uint16_t *
155 u16_normalize (uninorm_t nf, const uint16_t *s, size_t n,
156 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
157extern uint32_t *
158 u32_normalize (uninorm_t nf, const uint32_t *s, size_t n,
159 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
160
161
162/* Compare S1 and S2, ignoring differences in normalization.
163 NF must be either UNINORM_NFD or UNINORM_NFKD.
164 If successful, set *RESULTP to -1 if S1 < S2, 0 if S1 = S2, 1 if S1 > S2, and
165 return 0. Upon failure, return -1 with errno set. */
166extern int
167 u8_normcmp (const uint8_t *s1, size_t n1, const uint8_t *s2, size_t n2,
168 uninorm_t nf, int *resultp);
169extern int
170 u16_normcmp (const uint16_t *s1, size_t n1, const uint16_t *s2, size_t n2,
171 uninorm_t nf, int *resultp);
172extern int
173 u32_normcmp (const uint32_t *s1, size_t n1, const uint32_t *s2, size_t n2,
174 uninorm_t nf, int *resultp);
175
176
177/* Converts the string S of length N to a NUL-terminated byte sequence, in such
178 a way that comparing uN_normxfrm (S1) and uN_normxfrm (S2) with uN_cmp2() is
179 equivalent to comparing S1 and S2 with uN_normcoll().
180 NF must be either UNINORM_NFC or UNINORM_NFKC. */
181extern char *
182 u8_normxfrm (const uint8_t *s, size_t n, uninorm_t nf,
183 char *resultbuf, size_t *lengthp);
184extern char *
185 u16_normxfrm (const uint16_t *s, size_t n, uninorm_t nf,
186 char *resultbuf, size_t *lengthp);
187extern char *
188 u32_normxfrm (const uint32_t *s, size_t n, uninorm_t nf,
189 char *resultbuf, size_t *lengthp);
190
191
192/* Compare S1 and S2, ignoring differences in normalization, using the
193 collation rules of the current locale.
194 NF must be either UNINORM_NFC or UNINORM_NFKC.
195 If successful, set *RESULTP to -1 if S1 < S2, 0 if S1 = S2, 1 if S1 > S2, and
196 return 0. Upon failure, return -1 with errno set. */
197extern int
198 u8_normcoll (const uint8_t *s1, size_t n1, const uint8_t *s2, size_t n2,
199 uninorm_t nf, int *resultp);
200extern int
201 u16_normcoll (const uint16_t *s1, size_t n1, const uint16_t *s2, size_t n2,
202 uninorm_t nf, int *resultp);
203extern int
204 u32_normcoll (const uint32_t *s1, size_t n1, const uint32_t *s2, size_t n2,
205 uninorm_t nf, int *resultp);
206
207
208/* Normalization of a stream of Unicode characters.
209
210 A "stream of Unicode characters" is essentially a function that accepts an
211 ucs4_t argument repeatedly, optionally combined with a function that
212 "flushes" the stream. */
213
214/* Data type of a stream of Unicode characters that normalizes its input
215 according to a given normalization form and passes the normalized character
216 sequence to the encapsulated stream of Unicode characters. */
217struct uninorm_filter;
218
219/* Bring data buffered in the filter to its destination, the encapsulated
220 stream, then close and free the filter.
221 Return 0 if successful, or -1 with errno set upon failure. */
222extern int
223 uninorm_filter_free (struct uninorm_filter *filter);
224
225/* Create and return a normalization filter for Unicode characters.
226 The pair (stream_func, stream_data) is the encapsulated stream.
227 stream_func (stream_data, uc) receives the Unicode character uc
228 and returns 0 if successful, or -1 with errno set upon failure.
229 Return the new filter, or NULL with errno set upon failure. */
230extern struct uninorm_filter *
231 uninorm_filter_create (uninorm_t nf,
232 int (*stream_func) (void *stream_data, ucs4_t uc),
233 void *stream_data)
234 _GL_ATTRIBUTE_DEALLOC (uninorm_filter_free, 1);
235
236/* Stuff a Unicode character into a normalizing filter.
237 Return 0 if successful, or -1 with errno set upon failure. */
238extern int
239 uninorm_filter_write (struct uninorm_filter *filter, ucs4_t uc);
240
241/* Bring data buffered in the filter to its destination, the encapsulated
242 stream.
243 Return 0 if successful, or -1 with errno set upon failure.
244 Note! If after calling this function, additional characters are written
245 into the filter, the resulting character sequence in the encapsulated stream
246 will not necessarily be normalized. */
247extern int
248 uninorm_filter_flush (struct uninorm_filter *filter);
249
250
251#ifdef __cplusplus
252}
253#endif
254
255
256#endif /* _UNINORM_H */
diff --git a/gl/uninorm.in.h b/gl/uninorm.in.h
new file mode 100644
index 00000000..76ab32b6
--- /dev/null
+++ b/gl/uninorm.in.h
@@ -0,0 +1,255 @@
1/* Normalization forms (composition and decomposition) of Unicode strings.
2 Copyright (C) 2001-2002, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2009.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#ifndef _UNINORM_H
19#define _UNINORM_H
20
21/* Get size_t. */
22#include <stddef.h>
23
24#include "unitypes.h"
25
26#if @HAVE_UNISTRING_WOE32DLL_H@
27# include <unistring/woe32dll.h>
28#else
29# define LIBUNISTRING_DLL_VARIABLE
30#endif
31
32
33#ifdef __cplusplus
34extern "C" {
35#endif
36
37
38/* Conventions:
39
40 All functions prefixed with u8_ operate on UTF-8 encoded strings.
41 Their unit is an uint8_t (1 byte).
42
43 All functions prefixed with u16_ operate on UTF-16 encoded strings.
44 Their unit is an uint16_t (a 2-byte word).
45
46 All functions prefixed with u32_ operate on UCS-4 encoded strings.
47 Their unit is an uint32_t (a 4-byte word).
48
49 All argument pairs (s, n) denote a Unicode string s[0..n-1] with exactly
50 n units.
51
52 Functions returning a string result take a (resultbuf, lengthp) argument
53 pair. If resultbuf is not NULL and the result fits into *lengthp units,
54 it is put in resultbuf, and resultbuf is returned. Otherwise, a freshly
55 allocated string is returned. In both cases, *lengthp is set to the
56 length (number of units) of the returned string. In case of error,
57 NULL is returned and errno is set. */
58
59
60enum
61{
62 UC_DECOMP_CANONICAL,/* Canonical decomposition. */
63 UC_DECOMP_FONT, /* <font> A font variant (e.g. a blackletter form). */
64 UC_DECOMP_NOBREAK, /* <noBreak> A no-break version of a space or hyphen. */
65 UC_DECOMP_INITIAL, /* <initial> An initial presentation form (Arabic). */
66 UC_DECOMP_MEDIAL, /* <medial> A medial presentation form (Arabic). */
67 UC_DECOMP_FINAL, /* <final> A final presentation form (Arabic). */
68 UC_DECOMP_ISOLATED,/* <isolated> An isolated presentation form (Arabic). */
69 UC_DECOMP_CIRCLE, /* <circle> An encircled form. */
70 UC_DECOMP_SUPER, /* <super> A superscript form. */
71 UC_DECOMP_SUB, /* <sub> A subscript form. */
72 UC_DECOMP_VERTICAL,/* <vertical> A vertical layout presentation form. */
73 UC_DECOMP_WIDE, /* <wide> A wide (or zenkaku) compatibility character. */
74 UC_DECOMP_NARROW, /* <narrow> A narrow (or hankaku) compatibility character. */
75 UC_DECOMP_SMALL, /* <small> A small variant form (CNS compatibility). */
76 UC_DECOMP_SQUARE, /* <square> A CJK squared font variant. */
77 UC_DECOMP_FRACTION,/* <fraction> A vulgar fraction form. */
78 UC_DECOMP_COMPAT /* <compat> Otherwise unspecified compatibility character. */
79};
80
81/* Maximum size of decomposition of a single Unicode character. */
82#define UC_DECOMPOSITION_MAX_LENGTH 32
83
84/* Return the character decomposition mapping of a Unicode character.
85 DECOMPOSITION must point to an array of at least UC_DECOMPOSITION_MAX_LENGTH
86 ucs_t elements.
87 When a decomposition exists, DECOMPOSITION[0..N-1] and *DECOMP_TAG are
88 filled and N is returned. Otherwise -1 is returned. */
89extern int
90 uc_decomposition (ucs4_t uc, int *decomp_tag, ucs4_t *decomposition);
91
92/* Return the canonical character decomposition mapping of a Unicode character.
93 DECOMPOSITION must point to an array of at least UC_DECOMPOSITION_MAX_LENGTH
94 ucs_t elements.
95 When a decomposition exists, DECOMPOSITION[0..N-1] is filled and N is
96 returned. Otherwise -1 is returned. */
97extern int
98 uc_canonical_decomposition (ucs4_t uc, ucs4_t *decomposition);
99
100
101/* Attempt to combine the Unicode characters uc1, uc2.
102 uc1 is known to have canonical combining class 0.
103 Return the combination of uc1 and uc2, if it exists.
104 Return 0 otherwise.
105 Not all decompositions can be recombined using this function. See the
106 Unicode file CompositionExclusions.txt for details. */
107extern ucs4_t
108 uc_composition (ucs4_t uc1, ucs4_t uc2)
109 _UC_ATTRIBUTE_CONST;
110
111
112/* An object of type uninorm_t denotes a Unicode normalization form. */
113struct unicode_normalization_form;
114typedef const struct unicode_normalization_form *uninorm_t;
115
116/* UNINORM_NFD: Normalization form D: canonical decomposition. */
117extern @GNULIB_UNINORM_NFD_DLL_VARIABLE@ const struct unicode_normalization_form uninorm_nfd;
118#define UNINORM_NFD (&uninorm_nfd)
119
120/* UNINORM_NFC: Normalization form C: canonical decomposition, then
121 canonical composition. */
122extern @GNULIB_UNINORM_NFC_DLL_VARIABLE@ const struct unicode_normalization_form uninorm_nfc;
123#define UNINORM_NFC (&uninorm_nfc)
124
125/* UNINORM_NFKD: Normalization form KD: compatibility decomposition. */
126extern @GNULIB_UNINORM_NFKD_DLL_VARIABLE@ const struct unicode_normalization_form uninorm_nfkd;
127#define UNINORM_NFKD (&uninorm_nfkd)
128
129/* UNINORM_NFKC: Normalization form KC: compatibility decomposition, then
130 canonical composition. */
131extern @GNULIB_UNINORM_NFKC_DLL_VARIABLE@ const struct unicode_normalization_form uninorm_nfkc;
132#define UNINORM_NFKC (&uninorm_nfkc)
133
134/* Test whether a normalization form does compatibility decomposition. */
135#define uninorm_is_compat_decomposing(nf) \
136 ((* (const unsigned int *) (nf) >> 0) & 1)
137
138/* Test whether a normalization form includes canonical composition. */
139#define uninorm_is_composing(nf) \
140 ((* (const unsigned int *) (nf) >> 1) & 1)
141
142/* Return the decomposing variant of a normalization form.
143 This maps NFC,NFD -> NFD and NFKC,NFKD -> NFKD. */
144extern uninorm_t
145 uninorm_decomposing_form (uninorm_t nf)
146 _UC_ATTRIBUTE_PURE;
147
148
149/* Return the specified normalization form of a string. */
150extern uint8_t *
151 u8_normalize (uninorm_t nf, const uint8_t *s, size_t n,
152 uint8_t *_UC_RESTRICT resultbuf, size_t *lengthp);
153extern uint16_t *
154 u16_normalize (uninorm_t nf, const uint16_t *s, size_t n,
155 uint16_t *_UC_RESTRICT resultbuf, size_t *lengthp);
156extern uint32_t *
157 u32_normalize (uninorm_t nf, const uint32_t *s, size_t n,
158 uint32_t *_UC_RESTRICT resultbuf, size_t *lengthp);
159
160
161/* Compare S1 and S2, ignoring differences in normalization.
162 NF must be either UNINORM_NFD or UNINORM_NFKD.
163 If successful, set *RESULTP to -1 if S1 < S2, 0 if S1 = S2, 1 if S1 > S2, and
164 return 0. Upon failure, return -1 with errno set. */
165extern int
166 u8_normcmp (const uint8_t *s1, size_t n1, const uint8_t *s2, size_t n2,
167 uninorm_t nf, int *resultp);
168extern int
169 u16_normcmp (const uint16_t *s1, size_t n1, const uint16_t *s2, size_t n2,
170 uninorm_t nf, int *resultp);
171extern int
172 u32_normcmp (const uint32_t *s1, size_t n1, const uint32_t *s2, size_t n2,
173 uninorm_t nf, int *resultp);
174
175
176/* Converts the string S of length N to a NUL-terminated byte sequence, in such
177 a way that comparing uN_normxfrm (S1) and uN_normxfrm (S2) with uN_cmp2() is
178 equivalent to comparing S1 and S2 with uN_normcoll().
179 NF must be either UNINORM_NFC or UNINORM_NFKC. */
180extern char *
181 u8_normxfrm (const uint8_t *s, size_t n, uninorm_t nf,
182 char *resultbuf, size_t *lengthp);
183extern char *
184 u16_normxfrm (const uint16_t *s, size_t n, uninorm_t nf,
185 char *resultbuf, size_t *lengthp);
186extern char *
187 u32_normxfrm (const uint32_t *s, size_t n, uninorm_t nf,
188 char *resultbuf, size_t *lengthp);
189
190
191/* Compare S1 and S2, ignoring differences in normalization, using the
192 collation rules of the current locale.
193 NF must be either UNINORM_NFC or UNINORM_NFKC.
194 If successful, set *RESULTP to -1 if S1 < S2, 0 if S1 = S2, 1 if S1 > S2, and
195 return 0. Upon failure, return -1 with errno set. */
196extern int
197 u8_normcoll (const uint8_t *s1, size_t n1, const uint8_t *s2, size_t n2,
198 uninorm_t nf, int *resultp);
199extern int
200 u16_normcoll (const uint16_t *s1, size_t n1, const uint16_t *s2, size_t n2,
201 uninorm_t nf, int *resultp);
202extern int
203 u32_normcoll (const uint32_t *s1, size_t n1, const uint32_t *s2, size_t n2,
204 uninorm_t nf, int *resultp);
205
206
207/* Normalization of a stream of Unicode characters.
208
209 A "stream of Unicode characters" is essentially a function that accepts an
210 ucs4_t argument repeatedly, optionally combined with a function that
211 "flushes" the stream. */
212
213/* Data type of a stream of Unicode characters that normalizes its input
214 according to a given normalization form and passes the normalized character
215 sequence to the encapsulated stream of Unicode characters. */
216struct uninorm_filter;
217
218/* Bring data buffered in the filter to its destination, the encapsulated
219 stream, then close and free the filter.
220 Return 0 if successful, or -1 with errno set upon failure. */
221extern int
222 uninorm_filter_free (struct uninorm_filter *filter);
223
224/* Create and return a normalization filter for Unicode characters.
225 The pair (stream_func, stream_data) is the encapsulated stream.
226 stream_func (stream_data, uc) receives the Unicode character uc
227 and returns 0 if successful, or -1 with errno set upon failure.
228 Return the new filter, or NULL with errno set upon failure. */
229extern struct uninorm_filter *
230 uninorm_filter_create (uninorm_t nf,
231 int (*stream_func) (void *stream_data, ucs4_t uc),
232 void *stream_data)
233 _GL_ATTRIBUTE_DEALLOC (uninorm_filter_free, 1);
234
235/* Stuff a Unicode character into a normalizing filter.
236 Return 0 if successful, or -1 with errno set upon failure. */
237extern int
238 uninorm_filter_write (struct uninorm_filter *filter, ucs4_t uc);
239
240/* Bring data buffered in the filter to its destination, the encapsulated
241 stream.
242 Return 0 if successful, or -1 with errno set upon failure.
243 Note! If after calling this function, additional characters are written
244 into the filter, the resulting character sequence in the encapsulated stream
245 will not necessarily be normalized. */
246extern int
247 uninorm_filter_flush (struct uninorm_filter *filter);
248
249
250#ifdef __cplusplus
251}
252#endif
253
254
255#endif /* _UNINORM_H */
diff --git a/gl/unistd.c b/gl/unistd.c
index f3b3f7bd..e6625589 100644
--- a/gl/unistd.c
+++ b/gl/unistd.c
@@ -1,6 +1,6 @@
1/* Inline functions for <unistd.h>. 1/* Inline functions for <unistd.h>.
2 2
3 Copyright (C) 2012-2024 Free Software Foundation, Inc. 3 Copyright (C) 2012-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -15,8 +15,8 @@
15 You should have received a copy of the GNU Lesser General Public License 15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 17
18#define _GL_UNISTD_INLINE _GL_EXTERN_INLINE
18#include <config.h> 19#include <config.h>
19 20
20#define _GL_UNISTD_INLINE _GL_EXTERN_INLINE
21#include <unistd.h> 21#include <unistd.h>
22typedef int dummy; 22typedef int dummy;
diff --git a/gl/unistd.in.h b/gl/unistd.in.h
index b4129663..9f057d30 100644
--- a/gl/unistd.in.h
+++ b/gl/unistd.in.h
@@ -1,5 +1,5 @@
1/* Substitute for and wrapper around <unistd.h>. 1/* Substitute for and wrapper around <unistd.h>.
2 Copyright (C) 2003-2024 Free Software Foundation, Inc. 2 Copyright (C) 2003-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -69,8 +69,8 @@
69#if !defined _@GUARD_PREFIX@_UNISTD_H && !defined _GL_INCLUDING_WINSOCK2_H 69#if !defined _@GUARD_PREFIX@_UNISTD_H && !defined _GL_INCLUDING_WINSOCK2_H
70#define _@GUARD_PREFIX@_UNISTD_H 70#define _@GUARD_PREFIX@_UNISTD_H
71 71
72/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, GNULIB_POSIXCHECK, 72/* This file uses _GL_ATTRIBUTE_NODISCARD, _GL_INLINE_HEADER_BEGIN, _GL_INLINE,
73 HAVE_RAW_DECL_*. */ 73 GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
74#if !_GL_CONFIG_H_INCLUDED 74#if !_GL_CONFIG_H_INCLUDED
75 #error "Please include config.h first." 75 #error "Please include config.h first."
76#endif 76#endif
@@ -95,12 +95,24 @@
95# include <stdio.h> 95# include <stdio.h>
96#endif 96#endif
97 97
98/* Native Windows platforms declare _chdir, _getcwd, _rmdir in
99 <io.h> and/or <direct.h>, not in <unistd.h>.
100 They also declare _access(), _chmod(), _close(), _dup(), _dup2(), _isatty(),
101 _lseek(), _read(), _unlink(), _write() in <io.h>. */
102#if defined _WIN32 && !defined __CYGWIN__
103# include <io.h>
104# include <direct.h>
105#endif
106
107/* FreeBSD 14.0, NetBSD 10.0, OpenBSD 7.5, Solaris 11.4, and glibc 2.41
108 do not define O_CLOEXEC in <unistd.h>. */
98/* Cygwin 1.7.1 and Android 4.3 declare unlinkat in <fcntl.h>, not in 109/* Cygwin 1.7.1 and Android 4.3 declare unlinkat in <fcntl.h>, not in
99 <unistd.h>. */ 110 <unistd.h>. */
100/* But avoid namespace pollution on glibc systems. */ 111/* But avoid namespace pollution on glibc systems. */
101#if (@GNULIB_UNLINKAT@ || defined GNULIB_POSIXCHECK) \ 112#if ! defined O_CLOEXEC \
102 && (defined __CYGWIN__ || defined __ANDROID__) \ 113 || ((@GNULIB_UNLINKAT@ || defined GNULIB_POSIXCHECK) \
103 && ! defined __GLIBC__ 114 && (defined __CYGWIN__ || defined __ANDROID__) \
115 && ! defined __GLIBC__)
104# include <fcntl.h> 116# include <fcntl.h>
105#endif 117#endif
106 118
@@ -117,15 +129,6 @@
117# undef __need_system_stdlib_h 129# undef __need_system_stdlib_h
118#endif 130#endif
119 131
120/* Native Windows platforms declare _chdir, _getcwd, _rmdir in
121 <io.h> and/or <direct.h>, not in <unistd.h>.
122 They also declare _access(), _chmod(), _close(), _dup(), _dup2(), _isatty(),
123 _lseek(), _read(), _unlink(), _write() in <io.h>. */
124#if defined _WIN32 && !defined __CYGWIN__
125# include <io.h>
126# include <direct.h>
127#endif
128
129/* Native Windows platforms declare _execl*, _execv* in <process.h>. */ 132/* Native Windows platforms declare _execl*, _execv* in <process.h>. */
130#if defined _WIN32 && !defined __CYGWIN__ 133#if defined _WIN32 && !defined __CYGWIN__
131# include <process.h> 134# include <process.h>
@@ -159,8 +162,9 @@
159#endif 162#endif
160 163
161/* MSVC defines off_t in <sys/types.h>. 164/* MSVC defines off_t in <sys/types.h>.
162 May also define off_t to a 64-bit type on native Windows. */ 165 May also define off_t to a 64-bit type on native Windows.
163/* Get off_t, ssize_t, mode_t. */ 166 Also defines off64_t on macOS, NetBSD, OpenBSD, MSVC, Cygwin, Haiku. */
167/* Get off_t, off64_t, ssize_t, mode_t. */
164#include <sys/types.h> 168#include <sys/types.h>
165 169
166/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ 170/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
@@ -180,6 +184,9 @@ _GL_INLINE_HEADER_BEGIN
180#ifndef _GL_UNISTD_INLINE 184#ifndef _GL_UNISTD_INLINE
181# define _GL_UNISTD_INLINE _GL_INLINE 185# define _GL_UNISTD_INLINE _GL_INLINE
182#endif 186#endif
187#ifndef _GL_GETPAGESIZE_INLINE
188# define _GL_GETPAGESIZE_INLINE _GL_INLINE
189#endif
183 190
184/* Hide some function declarations from <winsock2.h>. */ 191/* Hide some function declarations from <winsock2.h>. */
185 192
@@ -286,7 +293,7 @@ _GL_INLINE_HEADER_BEGIN
286# undef access 293# undef access
287# define access rpl_access 294# define access rpl_access
288# endif 295# endif
289_GL_FUNCDECL_RPL (access, int, (const char *file, int mode) 296_GL_FUNCDECL_RPL (access, int, (const char *file, int mode),
290 _GL_ARG_NONNULL ((1))); 297 _GL_ARG_NONNULL ((1)));
291_GL_CXXALIAS_RPL (access, int, (const char *file, int mode)); 298_GL_CXXALIAS_RPL (access, int, (const char *file, int mode));
292# elif defined _WIN32 && !defined __CYGWIN__ 299# elif defined _WIN32 && !defined __CYGWIN__
@@ -339,7 +346,7 @@ _GL_CXXALIASWARN (chdir);
339#elif defined GNULIB_POSIXCHECK 346#elif defined GNULIB_POSIXCHECK
340# undef chdir 347# undef chdir
341# if HAVE_RAW_DECL_CHDIR 348# if HAVE_RAW_DECL_CHDIR
342_GL_WARN_ON_USE (chown, "chdir is not always in <unistd.h> - " 349_GL_WARN_ON_USE (chdir, "chdir is not always in <unistd.h> - "
343 "use gnulib module chdir for portability"); 350 "use gnulib module chdir for portability");
344# endif 351# endif
345#elif @GNULIB_MDA_CHDIR@ 352#elif @GNULIB_MDA_CHDIR@
@@ -370,13 +377,13 @@ _GL_CXXALIASWARN (chdir);
370# undef chown 377# undef chown
371# define chown rpl_chown 378# define chown rpl_chown
372# endif 379# endif
373_GL_FUNCDECL_RPL (chown, int, (const char *file, uid_t uid, gid_t gid) 380_GL_FUNCDECL_RPL (chown, int, (const char *file, uid_t uid, gid_t gid),
374 _GL_ARG_NONNULL ((1))); 381 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
375_GL_CXXALIAS_RPL (chown, int, (const char *file, uid_t uid, gid_t gid)); 382_GL_CXXALIAS_RPL (chown, int, (const char *file, uid_t uid, gid_t gid));
376# else 383# else
377# if !@HAVE_CHOWN@ 384# if !@HAVE_CHOWN@
378_GL_FUNCDECL_SYS (chown, int, (const char *file, uid_t uid, gid_t gid) 385_GL_FUNCDECL_SYS (chown, int, (const char *file, uid_t uid, gid_t gid),
379 _GL_ARG_NONNULL ((1))); 386 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
380# endif 387# endif
381_GL_CXXALIAS_SYS (chown, int, (const char *file, uid_t uid, gid_t gid)); 388_GL_CXXALIAS_SYS (chown, int, (const char *file, uid_t uid, gid_t gid));
382# endif 389# endif
@@ -398,7 +405,7 @@ _GL_WARN_ON_USE (chown, "chown fails to follow symlinks on some systems and "
398# undef close 405# undef close
399# define close rpl_close 406# define close rpl_close
400# endif 407# endif
401_GL_FUNCDECL_RPL (close, int, (int fd)); 408_GL_FUNCDECL_RPL (close, int, (int fd), );
402_GL_CXXALIAS_RPL (close, int, (int fd)); 409_GL_CXXALIAS_RPL (close, int, (int fd));
403# elif defined _WIN32 && !defined __CYGWIN__ 410# elif defined _WIN32 && !defined __CYGWIN__
404# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 411# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -411,8 +418,10 @@ _GL_CXXALIAS_SYS (close, int, (int fd));
411# endif 418# endif
412_GL_CXXALIASWARN (close); 419_GL_CXXALIASWARN (close);
413#elif @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@ 420#elif @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@
414# undef close 421# if !GNULIB_CLOSE
415# define close close_used_without_requesting_gnulib_module_close 422# undef close
423# define close close_used_without_requesting_gnulib_module_close
424# endif
416#elif defined GNULIB_POSIXCHECK 425#elif defined GNULIB_POSIXCHECK
417# undef close 426# undef close
418/* Assume close is always declared. */ 427/* Assume close is always declared. */
@@ -443,7 +452,7 @@ _GL_CXXALIASWARN (close);
443# endif 452# endif
444_GL_FUNCDECL_RPL (copy_file_range, ssize_t, (int ifd, off_t *ipos, 453_GL_FUNCDECL_RPL (copy_file_range, ssize_t, (int ifd, off_t *ipos,
445 int ofd, off_t *opos, 454 int ofd, off_t *opos,
446 size_t len, unsigned flags)); 455 size_t len, unsigned flags), );
447_GL_CXXALIAS_RPL (copy_file_range, ssize_t, (int ifd, off_t *ipos, 456_GL_CXXALIAS_RPL (copy_file_range, ssize_t, (int ifd, off_t *ipos,
448 int ofd, off_t *opos, 457 int ofd, off_t *opos,
449 size_t len, unsigned flags)); 458 size_t len, unsigned flags));
@@ -451,13 +460,15 @@ _GL_CXXALIAS_RPL (copy_file_range, ssize_t, (int ifd, off_t *ipos,
451# if !@HAVE_COPY_FILE_RANGE@ 460# if !@HAVE_COPY_FILE_RANGE@
452_GL_FUNCDECL_SYS (copy_file_range, ssize_t, (int ifd, off_t *ipos, 461_GL_FUNCDECL_SYS (copy_file_range, ssize_t, (int ifd, off_t *ipos,
453 int ofd, off_t *opos, 462 int ofd, off_t *opos,
454 size_t len, unsigned flags)); 463 size_t len, unsigned flags), );
455# endif 464# endif
456_GL_CXXALIAS_SYS (copy_file_range, ssize_t, (int ifd, off_t *ipos, 465_GL_CXXALIAS_SYS (copy_file_range, ssize_t, (int ifd, off_t *ipos,
457 int ofd, off_t *opos, 466 int ofd, off_t *opos,
458 size_t len, unsigned flags)); 467 size_t len, unsigned flags));
459# endif 468# endif
469# if __GLIBC__ >= 2
460_GL_CXXALIASWARN (copy_file_range); 470_GL_CXXALIASWARN (copy_file_range);
471# endif
461#elif defined GNULIB_POSIXCHECK 472#elif defined GNULIB_POSIXCHECK
462# undef copy_file_range 473# undef copy_file_range
463# if HAVE_RAW_DECL_COPY_FILE_RANGE 474# if HAVE_RAW_DECL_COPY_FILE_RANGE
@@ -473,7 +484,7 @@ _GL_WARN_ON_USE (copy_file_range,
473# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 484# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
474# define dup rpl_dup 485# define dup rpl_dup
475# endif 486# endif
476_GL_FUNCDECL_RPL (dup, int, (int oldfd)); 487_GL_FUNCDECL_RPL (dup, int, (int oldfd), _GL_ATTRIBUTE_NODISCARD);
477_GL_CXXALIAS_RPL (dup, int, (int oldfd)); 488_GL_CXXALIAS_RPL (dup, int, (int oldfd));
478# elif defined _WIN32 && !defined __CYGWIN__ 489# elif defined _WIN32 && !defined __CYGWIN__
479# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 490# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -518,7 +529,7 @@ _GL_CXXALIASWARN (dup);
518# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 529# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
519# define dup2 rpl_dup2 530# define dup2 rpl_dup2
520# endif 531# endif
521_GL_FUNCDECL_RPL (dup2, int, (int oldfd, int newfd)); 532_GL_FUNCDECL_RPL (dup2, int, (int oldfd, int newfd), );
522_GL_CXXALIAS_RPL (dup2, int, (int oldfd, int newfd)); 533_GL_CXXALIAS_RPL (dup2, int, (int oldfd, int newfd));
523# elif defined _WIN32 && !defined __CYGWIN__ 534# elif defined _WIN32 && !defined __CYGWIN__
524# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 535# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -567,11 +578,11 @@ _GL_CXXALIASWARN (dup2);
567# undef dup3 578# undef dup3
568# define dup3 rpl_dup3 579# define dup3 rpl_dup3
569# endif 580# endif
570_GL_FUNCDECL_RPL (dup3, int, (int oldfd, int newfd, int flags)); 581_GL_FUNCDECL_RPL (dup3, int, (int oldfd, int newfd, int flags), );
571_GL_CXXALIAS_RPL (dup3, int, (int oldfd, int newfd, int flags)); 582_GL_CXXALIAS_RPL (dup3, int, (int oldfd, int newfd, int flags));
572# else 583# else
573# if !@HAVE_DUP3@ 584# if !@HAVE_DUP3@
574_GL_FUNCDECL_SYS (dup3, int, (int oldfd, int newfd, int flags)); 585_GL_FUNCDECL_SYS (dup3, int, (int oldfd, int newfd, int flags), );
575# endif 586# endif
576_GL_CXXALIAS_SYS (dup3, int, (int oldfd, int newfd, int flags)); 587_GL_CXXALIAS_SYS (dup3, int, (int oldfd, int newfd, int flags));
577# endif 588# endif
@@ -636,7 +647,7 @@ rpl_environ (void)
636/* Like access(), except that it uses the effective user id and group id of 647/* Like access(), except that it uses the effective user id and group id of
637 the current process. */ 648 the current process. */
638# if !@HAVE_EUIDACCESS@ 649# if !@HAVE_EUIDACCESS@
639_GL_FUNCDECL_SYS (euidaccess, int, (const char *filename, int mode) 650_GL_FUNCDECL_SYS (euidaccess, int, (const char *filename, int mode),
640 _GL_ARG_NONNULL ((1))); 651 _GL_ARG_NONNULL ((1)));
641# endif 652# endif
642_GL_CXXALIAS_SYS (euidaccess, int, (const char *filename, int mode)); 653_GL_CXXALIAS_SYS (euidaccess, int, (const char *filename, int mode));
@@ -661,7 +672,7 @@ _GL_WARN_ON_USE (euidaccess, "euidaccess is unportable - "
661# undef execl 672# undef execl
662# define execl rpl_execl 673# define execl rpl_execl
663# endif 674# endif
664_GL_FUNCDECL_RPL (execl, int, (const char *program, const char *arg, ...) 675_GL_FUNCDECL_RPL (execl, int, (const char *program, const char *arg, ...),
665 _GL_ARG_NONNULL ((1))); 676 _GL_ARG_NONNULL ((1)));
666_GL_CXXALIAS_RPL (execl, int, (const char *program, const char *arg, ...)); 677_GL_CXXALIAS_RPL (execl, int, (const char *program, const char *arg, ...));
667# else 678# else
@@ -696,7 +707,7 @@ _GL_CXXALIASWARN (execl);
696# undef execle 707# undef execle
697# define execle rpl_execle 708# define execle rpl_execle
698# endif 709# endif
699_GL_FUNCDECL_RPL (execle, int, (const char *program, const char *arg, ...) 710_GL_FUNCDECL_RPL (execle, int, (const char *program, const char *arg, ...),
700 _GL_ARG_NONNULL ((1))); 711 _GL_ARG_NONNULL ((1)));
701_GL_CXXALIAS_RPL (execle, int, (const char *program, const char *arg, ...)); 712_GL_CXXALIAS_RPL (execle, int, (const char *program, const char *arg, ...));
702# else 713# else
@@ -732,7 +743,7 @@ _GL_CXXALIASWARN (execle);
732# undef execlp 743# undef execlp
733# define execlp rpl_execlp 744# define execlp rpl_execlp
734# endif 745# endif
735_GL_FUNCDECL_RPL (execlp, int, (const char *program, const char *arg, ...) 746_GL_FUNCDECL_RPL (execlp, int, (const char *program, const char *arg, ...),
736 _GL_ARG_NONNULL ((1))); 747 _GL_ARG_NONNULL ((1)));
737_GL_CXXALIAS_RPL (execlp, int, (const char *program, const char *arg, ...)); 748_GL_CXXALIAS_RPL (execlp, int, (const char *program, const char *arg, ...));
738# else 749# else
@@ -769,7 +780,7 @@ _GL_CXXALIASWARN (execlp);
769# undef execv 780# undef execv
770# define execv rpl_execv 781# define execv rpl_execv
771# endif 782# endif
772_GL_FUNCDECL_RPL (execv, int, (const char *program, char * const *argv) 783_GL_FUNCDECL_RPL (execv, int, (const char *program, char * const *argv),
773 _GL_ARG_NONNULL ((1, 2))); 784 _GL_ARG_NONNULL ((1, 2)));
774_GL_CXXALIAS_RPL (execv, int, (const char *program, char * const *argv)); 785_GL_CXXALIAS_RPL (execv, int, (const char *program, char * const *argv));
775# else 786# else
@@ -806,7 +817,7 @@ _GL_CXXALIASWARN (execv);
806# define execve rpl_execve 817# define execve rpl_execve
807# endif 818# endif
808_GL_FUNCDECL_RPL (execve, int, 819_GL_FUNCDECL_RPL (execve, int,
809 (const char *program, char * const *argv, char * const *env) 820 (const char *program, char * const *argv, char * const *env),
810 _GL_ARG_NONNULL ((1, 2))); 821 _GL_ARG_NONNULL ((1, 2)));
811_GL_CXXALIAS_RPL (execve, int, 822_GL_CXXALIAS_RPL (execve, int,
812 (const char *program, char * const *argv, char * const *env)); 823 (const char *program, char * const *argv, char * const *env));
@@ -846,7 +857,7 @@ _GL_CXXALIASWARN (execve);
846# undef execvp 857# undef execvp
847# define execvp rpl_execvp 858# define execvp rpl_execvp
848# endif 859# endif
849_GL_FUNCDECL_RPL (execvp, int, (const char *program, char * const *argv) 860_GL_FUNCDECL_RPL (execvp, int, (const char *program, char * const *argv),
850 _GL_ARG_NONNULL ((1, 2))); 861 _GL_ARG_NONNULL ((1, 2)));
851_GL_CXXALIAS_RPL (execvp, int, (const char *program, char * const *argv)); 862_GL_CXXALIAS_RPL (execvp, int, (const char *program, char * const *argv));
852# else 863# else
@@ -883,14 +894,14 @@ _GL_CXXALIASWARN (execvp);
883# define execvpe rpl_execvpe 894# define execvpe rpl_execvpe
884# endif 895# endif
885_GL_FUNCDECL_RPL (execvpe, int, 896_GL_FUNCDECL_RPL (execvpe, int,
886 (const char *program, char * const *argv, char * const *env) 897 (const char *program, char * const *argv, char * const *env),
887 _GL_ARG_NONNULL ((1, 2))); 898 _GL_ARG_NONNULL ((1, 2)));
888_GL_CXXALIAS_RPL (execvpe, int, 899_GL_CXXALIAS_RPL (execvpe, int,
889 (const char *program, char * const *argv, char * const *env)); 900 (const char *program, char * const *argv, char * const *env));
890# else 901# else
891# if !@HAVE_DECL_EXECVPE@ 902# if !@HAVE_DECL_EXECVPE@
892_GL_FUNCDECL_SYS (execvpe, int, 903_GL_FUNCDECL_SYS (execvpe, int,
893 (const char *program, char * const *argv, char * const *env) 904 (const char *program, char * const *argv, char * const *env),
894 _GL_ARG_NONNULL ((1, 2))); 905 _GL_ARG_NONNULL ((1, 2)));
895# endif 906# endif
896_GL_CXXALIAS_SYS (execvpe, int, 907_GL_CXXALIAS_SYS (execvpe, int,
@@ -921,7 +932,7 @@ _GL_CXXALIAS_MDA_CAST (execvpe, intptr_t,
921# elif @HAVE_EXECVPE@ 932# elif @HAVE_EXECVPE@
922# if !@HAVE_DECL_EXECVPE@ 933# if !@HAVE_DECL_EXECVPE@
923_GL_FUNCDECL_SYS (execvpe, int, 934_GL_FUNCDECL_SYS (execvpe, int,
924 (const char *program, char * const *argv, char * const *env) 935 (const char *program, char * const *argv, char * const *env),
925 _GL_ARG_NONNULL ((1, 2))); 936 _GL_ARG_NONNULL ((1, 2)));
926# endif 937# endif
927_GL_CXXALIAS_SYS (execvpe, int, 938_GL_CXXALIAS_SYS (execvpe, int,
@@ -940,15 +951,15 @@ _GL_CXXALIASWARN (execvpe);
940# define faccessat rpl_faccessat 951# define faccessat rpl_faccessat
941# endif 952# endif
942_GL_FUNCDECL_RPL (faccessat, int, 953_GL_FUNCDECL_RPL (faccessat, int,
943 (int fd, char const *name, int mode, int flag) 954 (int fd, char const *name, int mode, int flag),
944 _GL_ARG_NONNULL ((2))); 955 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD);
945_GL_CXXALIAS_RPL (faccessat, int, 956_GL_CXXALIAS_RPL (faccessat, int,
946 (int fd, char const *name, int mode, int flag)); 957 (int fd, char const *name, int mode, int flag));
947# else 958# else
948# if !@HAVE_FACCESSAT@ 959# if !@HAVE_FACCESSAT@
949_GL_FUNCDECL_SYS (faccessat, int, 960_GL_FUNCDECL_SYS (faccessat, int,
950 (int fd, char const *file, int mode, int flag) 961 (int fd, char const *file, int mode, int flag),
951 _GL_ARG_NONNULL ((2))); 962 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD);
952# endif 963# endif
953_GL_CXXALIAS_SYS (faccessat, int, 964_GL_CXXALIAS_SYS (faccessat, int,
954 (int fd, char const *file, int mode, int flag)); 965 (int fd, char const *file, int mode, int flag));
@@ -976,11 +987,11 @@ _GL_WARN_ON_USE (faccessat, "faccessat is not portable - "
976# undef fchdir 987# undef fchdir
977# define fchdir rpl_fchdir 988# define fchdir rpl_fchdir
978# endif 989# endif
979_GL_FUNCDECL_RPL (fchdir, int, (int /*fd*/)); 990_GL_FUNCDECL_RPL (fchdir, int, (int /*fd*/), _GL_ATTRIBUTE_NODISCARD);
980_GL_CXXALIAS_RPL (fchdir, int, (int /*fd*/)); 991_GL_CXXALIAS_RPL (fchdir, int, (int /*fd*/));
981# else 992# else
982# if !@HAVE_FCHDIR@ || !@HAVE_DECL_FCHDIR@ 993# if !@HAVE_FCHDIR@ || !@HAVE_DECL_FCHDIR@
983_GL_FUNCDECL_SYS (fchdir, int, (int /*fd*/)); 994_GL_FUNCDECL_SYS (fchdir, int, (int /*fd*/), _GL_ATTRIBUTE_NODISCARD);
984# endif 995# endif
985_GL_CXXALIAS_SYS (fchdir, int, (int /*fd*/)); 996_GL_CXXALIAS_SYS (fchdir, int, (int /*fd*/));
986# endif 997# endif
@@ -1009,15 +1020,15 @@ _GL_WARN_ON_USE (fchdir, "fchdir is unportable - "
1009# define fchownat rpl_fchownat 1020# define fchownat rpl_fchownat
1010# endif 1021# endif
1011_GL_FUNCDECL_RPL (fchownat, int, (int fd, char const *file, 1022_GL_FUNCDECL_RPL (fchownat, int, (int fd, char const *file,
1012 uid_t owner, gid_t group, int flag) 1023 uid_t owner, gid_t group, int flag),
1013 _GL_ARG_NONNULL ((2))); 1024 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD);
1014_GL_CXXALIAS_RPL (fchownat, int, (int fd, char const *file, 1025_GL_CXXALIAS_RPL (fchownat, int, (int fd, char const *file,
1015 uid_t owner, gid_t group, int flag)); 1026 uid_t owner, gid_t group, int flag));
1016# else 1027# else
1017# if !@HAVE_FCHOWNAT@ 1028# if !@HAVE_FCHOWNAT@
1018_GL_FUNCDECL_SYS (fchownat, int, (int fd, char const *file, 1029_GL_FUNCDECL_SYS (fchownat, int, (int fd, char const *file,
1019 uid_t owner, gid_t group, int flag) 1030 uid_t owner, gid_t group, int flag),
1020 _GL_ARG_NONNULL ((2))); 1031 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD);
1021# endif 1032# endif
1022_GL_CXXALIAS_SYS (fchownat, int, (int fd, char const *file, 1033_GL_CXXALIAS_SYS (fchownat, int, (int fd, char const *file,
1023 uid_t owner, gid_t group, int flag)); 1034 uid_t owner, gid_t group, int flag));
@@ -1042,11 +1053,11 @@ _GL_WARN_ON_USE (fchownat, "fchownat is not portable - "
1042# undef fdatasync 1053# undef fdatasync
1043# define fdatasync rpl_fdatasync 1054# define fdatasync rpl_fdatasync
1044# endif 1055# endif
1045_GL_FUNCDECL_RPL (fdatasync, int, (int fd)); 1056_GL_FUNCDECL_RPL (fdatasync, int, (int fd), );
1046_GL_CXXALIAS_RPL (fdatasync, int, (int fd)); 1057_GL_CXXALIAS_RPL (fdatasync, int, (int fd));
1047# else 1058# else
1048# if !@HAVE_FDATASYNC@|| !@HAVE_DECL_FDATASYNC@ 1059# if !@HAVE_FDATASYNC@|| !@HAVE_DECL_FDATASYNC@
1049_GL_FUNCDECL_SYS (fdatasync, int, (int fd)); 1060_GL_FUNCDECL_SYS (fdatasync, int, (int fd), );
1050# endif 1061# endif
1051_GL_CXXALIAS_SYS (fdatasync, int, (int fd)); 1062_GL_CXXALIAS_SYS (fdatasync, int, (int fd));
1052# endif 1063# endif
@@ -1068,7 +1079,7 @@ _GL_WARN_ON_USE (fdatasync, "fdatasync is unportable - "
1068 See POSIX:2008 specification 1079 See POSIX:2008 specification
1069 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html>. */ 1080 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html>. */
1070# if !@HAVE_FSYNC@ 1081# if !@HAVE_FSYNC@
1071_GL_FUNCDECL_SYS (fsync, int, (int fd)); 1082_GL_FUNCDECL_SYS (fsync, int, (int fd), );
1072# endif 1083# endif
1073_GL_CXXALIAS_SYS (fsync, int, (int fd)); 1084_GL_CXXALIAS_SYS (fsync, int, (int fd));
1074_GL_CXXALIASWARN (fsync); 1085_GL_CXXALIASWARN (fsync);
@@ -1091,13 +1102,17 @@ _GL_WARN_ON_USE (fsync, "fsync is unportable - "
1091# undef ftruncate 1102# undef ftruncate
1092# define ftruncate rpl_ftruncate 1103# define ftruncate rpl_ftruncate
1093# endif 1104# endif
1094_GL_FUNCDECL_RPL (ftruncate, int, (int fd, off_t length)); 1105_GL_FUNCDECL_RPL (ftruncate, int,
1095_GL_CXXALIAS_RPL (ftruncate, int, (int fd, off_t length)); 1106 (int fd, off_t length), _GL_ATTRIBUTE_NODISCARD);
1107_GL_CXXALIAS_RPL (ftruncate, int,
1108 (int fd, off_t length));
1096# else 1109# else
1097# if !@HAVE_FTRUNCATE@ 1110# if !@HAVE_FTRUNCATE@
1098_GL_FUNCDECL_SYS (ftruncate, int, (int fd, off_t length)); 1111_GL_FUNCDECL_SYS (ftruncate, int,
1112 (int fd, off_t length), _GL_ATTRIBUTE_NODISCARD);
1099# endif 1113# endif
1100_GL_CXXALIAS_SYS (ftruncate, int, (int fd, off_t length)); 1114_GL_CXXALIAS_SYS (ftruncate, int,
1115 (int fd, off_t length));
1101# endif 1116# endif
1102# if __GLIBC__ >= 2 1117# if __GLIBC__ >= 2
1103_GL_CXXALIASWARN (ftruncate); 1118_GL_CXXALIASWARN (ftruncate);
@@ -1126,7 +1141,8 @@ _GL_WARN_ON_USE (ftruncate, "ftruncate is unportable - "
1126# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1141# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1127# define getcwd rpl_getcwd 1142# define getcwd rpl_getcwd
1128# endif 1143# endif
1129_GL_FUNCDECL_RPL (getcwd, char *, (char *buf, size_t size)); 1144_GL_FUNCDECL_RPL (getcwd, char *, (char *buf, size_t size),
1145 _GL_ATTRIBUTE_NODISCARD);
1130_GL_CXXALIAS_RPL (getcwd, char *, (char *buf, size_t size)); 1146_GL_CXXALIAS_RPL (getcwd, char *, (char *buf, size_t size));
1131# elif defined _WIN32 && !defined __CYGWIN__ 1147# elif defined _WIN32 && !defined __CYGWIN__
1132# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1148# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -1181,15 +1197,19 @@ _GL_CXXALIASWARN (getcwd);
1181# undef getdomainname 1197# undef getdomainname
1182# define getdomainname rpl_getdomainname 1198# define getdomainname rpl_getdomainname
1183# endif 1199# endif
1184_GL_FUNCDECL_RPL (getdomainname, int, (char *name, size_t len) 1200_GL_FUNCDECL_RPL (getdomainname, int,
1185 _GL_ARG_NONNULL ((1))); 1201 (char *name, size_t len),
1186_GL_CXXALIAS_RPL (getdomainname, int, (char *name, size_t len)); 1202 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
1203_GL_CXXALIAS_RPL (getdomainname, int,
1204 (char *name, size_t len));
1187# else 1205# else
1188# if !@HAVE_DECL_GETDOMAINNAME@ 1206# if !@HAVE_DECL_GETDOMAINNAME@
1189_GL_FUNCDECL_SYS (getdomainname, int, (char *name, size_t len) 1207_GL_FUNCDECL_SYS (getdomainname, int,
1190 _GL_ARG_NONNULL ((1))); 1208 (char *name, size_t len),
1209 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
1191# endif 1210# endif
1192_GL_CXXALIAS_SYS (getdomainname, int, (char *name, size_t len)); 1211_GL_CXXALIAS_SYS (getdomainname, int,
1212 (char *name, size_t len));
1193# endif 1213# endif
1194# if __GLIBC__ >= 2 1214# if __GLIBC__ >= 2
1195_GL_CXXALIASWARN (getdomainname); 1215_GL_CXXALIASWARN (getdomainname);
@@ -1211,11 +1231,11 @@ _GL_WARN_ON_USE (getdomainname, "getdomainname is unportable - "
1211# undef getdtablesize 1231# undef getdtablesize
1212# define getdtablesize rpl_getdtablesize 1232# define getdtablesize rpl_getdtablesize
1213# endif 1233# endif
1214_GL_FUNCDECL_RPL (getdtablesize, int, (void)); 1234_GL_FUNCDECL_RPL (getdtablesize, int, (void), );
1215_GL_CXXALIAS_RPL (getdtablesize, int, (void)); 1235_GL_CXXALIAS_RPL (getdtablesize, int, (void));
1216# else 1236# else
1217# if !@HAVE_GETDTABLESIZE@ 1237# if !@HAVE_GETDTABLESIZE@
1218_GL_FUNCDECL_SYS (getdtablesize, int, (void)); 1238_GL_FUNCDECL_SYS (getdtablesize, int, (void), );
1219# endif 1239# endif
1220/* Need to cast, because on AIX, the parameter list is 1240/* Need to cast, because on AIX, the parameter list is
1221 (...). */ 1241 (...). */
@@ -1238,13 +1258,17 @@ _GL_WARN_ON_USE (getdtablesize, "getdtablesize is unportable - "
1238# undef getentropy 1258# undef getentropy
1239# define getentropy rpl_getentropy 1259# define getentropy rpl_getentropy
1240# endif 1260# endif
1241_GL_FUNCDECL_RPL (getentropy, int, (void *buffer, size_t length)); 1261_GL_FUNCDECL_RPL (getentropy, int,
1242_GL_CXXALIAS_RPL (getentropy, int, (void *buffer, size_t length)); 1262 (void *buffer, size_t length), _GL_ATTRIBUTE_NODISCARD);
1263_GL_CXXALIAS_RPL (getentropy, int,
1264 (void *buffer, size_t length));
1243# else 1265# else
1244# if !@HAVE_GETENTROPY@ 1266# if !@HAVE_GETENTROPY@
1245_GL_FUNCDECL_SYS (getentropy, int, (void *buffer, size_t length)); 1267_GL_FUNCDECL_SYS (getentropy, int,
1268 (void *buffer, size_t length), _GL_ATTRIBUTE_NODISCARD);
1246# endif 1269# endif
1247_GL_CXXALIAS_SYS (getentropy, int, (void *buffer, size_t length)); 1270_GL_CXXALIAS_SYS (getentropy, int,
1271 (void *buffer, size_t length));
1248# endif 1272# endif
1249# if __GLIBC__ >= 2 1273# if __GLIBC__ >= 2
1250_GL_CXXALIASWARN (getentropy); 1274_GL_CXXALIASWARN (getentropy);
@@ -1269,13 +1293,17 @@ _GL_WARN_ON_USE (getentropy, "getentropy is unportable - "
1269# undef getgroups 1293# undef getgroups
1270# define getgroups rpl_getgroups 1294# define getgroups rpl_getgroups
1271# endif 1295# endif
1272_GL_FUNCDECL_RPL (getgroups, int, (int n, gid_t *groups)); 1296_GL_FUNCDECL_RPL (getgroups, int,
1273_GL_CXXALIAS_RPL (getgroups, int, (int n, gid_t *groups)); 1297 (int n, gid_t *groups), _GL_ATTRIBUTE_NODISCARD);
1298_GL_CXXALIAS_RPL (getgroups, int,
1299 (int n, gid_t *groups));
1274# else 1300# else
1275# if !@HAVE_GETGROUPS@ 1301# if !@HAVE_GETGROUPS@
1276_GL_FUNCDECL_SYS (getgroups, int, (int n, gid_t *groups)); 1302_GL_FUNCDECL_SYS (getgroups, int,
1303 (int n, gid_t *groups), _GL_ATTRIBUTE_NODISCARD);
1277# endif 1304# endif
1278_GL_CXXALIAS_SYS (getgroups, int, (int n, gid_t *groups)); 1305_GL_CXXALIAS_SYS (getgroups, int,
1306 (int n, gid_t *groups));
1279# endif 1307# endif
1280_GL_CXXALIASWARN (getgroups); 1308_GL_CXXALIASWARN (getgroups);
1281#elif defined GNULIB_POSIXCHECK 1309#elif defined GNULIB_POSIXCHECK
@@ -1300,12 +1328,12 @@ _GL_WARN_ON_USE (getgroups, "getgroups is unportable - "
1300# undef gethostname 1328# undef gethostname
1301# define gethostname rpl_gethostname 1329# define gethostname rpl_gethostname
1302# endif 1330# endif
1303_GL_FUNCDECL_RPL (gethostname, int, (char *name, size_t len) 1331_GL_FUNCDECL_RPL (gethostname, int, (char *name, size_t len),
1304 _GL_ARG_NONNULL ((1))); 1332 _GL_ARG_NONNULL ((1)));
1305_GL_CXXALIAS_RPL (gethostname, int, (char *name, size_t len)); 1333_GL_CXXALIAS_RPL (gethostname, int, (char *name, size_t len));
1306# else 1334# else
1307# if !@HAVE_GETHOSTNAME@ 1335# if !@HAVE_GETHOSTNAME@
1308_GL_FUNCDECL_SYS (gethostname, int, (char *name, size_t len) 1336_GL_FUNCDECL_SYS (gethostname, int, (char *name, size_t len),
1309 _GL_ARG_NONNULL ((1))); 1337 _GL_ARG_NONNULL ((1)));
1310# endif 1338# endif
1311/* Need to cast, because on Solaris 10 and OSF/1 5.1 systems, the second 1339/* Need to cast, because on Solaris 10 and OSF/1 5.1 systems, the second
@@ -1315,8 +1343,10 @@ _GL_CXXALIAS_SYS_CAST (gethostname, int, (char *name, size_t len));
1315# endif 1343# endif
1316_GL_CXXALIASWARN (gethostname); 1344_GL_CXXALIASWARN (gethostname);
1317#elif @UNISTD_H_HAVE_WINSOCK2_H@ 1345#elif @UNISTD_H_HAVE_WINSOCK2_H@
1318# undef gethostname 1346# if !GNULIB_GETHOSTNAME
1319# define gethostname gethostname_used_without_requesting_gnulib_module_gethostname 1347# undef gethostname
1348# define gethostname gethostname_used_without_requesting_gnulib_module_gethostname
1349# endif
1320#elif defined GNULIB_POSIXCHECK 1350#elif defined GNULIB_POSIXCHECK
1321# undef gethostname 1351# undef gethostname
1322# if HAVE_RAW_DECL_GETHOSTNAME 1352# if HAVE_RAW_DECL_GETHOSTNAME
@@ -1337,11 +1367,21 @@ _GL_WARN_ON_USE (gethostname, "gethostname is unportable - "
1337 ${LOGNAME-$USER} on Unix platforms, 1367 ${LOGNAME-$USER} on Unix platforms,
1338 $USERNAME on native Windows platforms. 1368 $USERNAME on native Windows platforms.
1339 */ 1369 */
1340# if !@HAVE_DECL_GETLOGIN@ 1370# if @REPLACE_GETLOGIN@
1341_GL_FUNCDECL_SYS (getlogin, char *, (void)); 1371# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1342# endif 1372# define getlogin rpl_getlogin
1373# endif
1374_GL_FUNCDECL_RPL (getlogin, char *, (void), );
1375_GL_CXXALIAS_RPL (getlogin, char *, (void));
1376# else
1377# if !@HAVE_DECL_GETLOGIN@
1378_GL_FUNCDECL_SYS (getlogin, char *, (void), );
1379# endif
1343_GL_CXXALIAS_SYS (getlogin, char *, (void)); 1380_GL_CXXALIAS_SYS (getlogin, char *, (void));
1381# endif
1382# if __GLIBC__ >= 2
1344_GL_CXXALIASWARN (getlogin); 1383_GL_CXXALIASWARN (getlogin);
1384# endif
1345#elif defined GNULIB_POSIXCHECK 1385#elif defined GNULIB_POSIXCHECK
1346# undef getlogin 1386# undef getlogin
1347# if HAVE_RAW_DECL_GETLOGIN 1387# if HAVE_RAW_DECL_GETLOGIN
@@ -1370,12 +1410,12 @@ _GL_WARN_ON_USE (getlogin, "getlogin is unportable - "
1370# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1410# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1371# define getlogin_r rpl_getlogin_r 1411# define getlogin_r rpl_getlogin_r
1372# endif 1412# endif
1373_GL_FUNCDECL_RPL (getlogin_r, int, (char *name, size_t size) 1413_GL_FUNCDECL_RPL (getlogin_r, int, (char *name, size_t size),
1374 _GL_ARG_NONNULL ((1))); 1414 _GL_ARG_NONNULL ((1)));
1375_GL_CXXALIAS_RPL (getlogin_r, int, (char *name, size_t size)); 1415_GL_CXXALIAS_RPL (getlogin_r, int, (char *name, size_t size));
1376# else 1416# else
1377# if !@HAVE_DECL_GETLOGIN_R@ 1417# if !@HAVE_DECL_GETLOGIN_R@
1378_GL_FUNCDECL_SYS (getlogin_r, int, (char *name, size_t size) 1418_GL_FUNCDECL_SYS (getlogin_r, int, (char *name, size_t size),
1379 _GL_ARG_NONNULL ((1))); 1419 _GL_ARG_NONNULL ((1)));
1380# endif 1420# endif
1381/* Need to cast, because on Solaris 10 systems, the second argument is 1421/* Need to cast, because on Solaris 10 systems, the second argument is
@@ -1399,13 +1439,13 @@ _GL_WARN_ON_USE (getlogin_r, "getlogin_r is unportable - "
1399# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1439# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1400# define getpagesize rpl_getpagesize 1440# define getpagesize rpl_getpagesize
1401# endif 1441# endif
1402_GL_FUNCDECL_RPL (getpagesize, int, (void)); 1442_GL_FUNCDECL_RPL (getpagesize, int, (void), );
1403_GL_CXXALIAS_RPL (getpagesize, int, (void)); 1443_GL_CXXALIAS_RPL (getpagesize, int, (void));
1404# else 1444# else
1405/* On HP-UX, getpagesize exists, but it is not declared in <unistd.h> even if 1445/* On HP-UX, getpagesize exists, but it is not declared in <unistd.h> even if
1406 the compiler options -D_HPUX_SOURCE -D_XOPEN_SOURCE=600 are used. */ 1446 the compiler options -D_HPUX_SOURCE -D_XOPEN_SOURCE=600 are used. */
1407# if defined __hpux 1447# if defined __hpux
1408_GL_FUNCDECL_SYS (getpagesize, int, (void)); 1448_GL_FUNCDECL_SYS (getpagesize, int, (void), );
1409# endif 1449# endif
1410# if !@HAVE_GETPAGESIZE@ 1450# if !@HAVE_GETPAGESIZE@
1411# if !defined getpagesize 1451# if !defined getpagesize
@@ -1456,7 +1496,7 @@ _GL_FUNCDECL_SYS (getpagesize, int, (void));
1456# define getpagesize() _gl_getpagesize () 1496# define getpagesize() _gl_getpagesize ()
1457# else 1497# else
1458# if !GNULIB_defined_getpagesize_function 1498# if !GNULIB_defined_getpagesize_function
1459_GL_UNISTD_INLINE int 1499_GL_GETPAGESIZE_INLINE int
1460getpagesize () 1500getpagesize ()
1461{ 1501{
1462 return _gl_getpagesize (); 1502 return _gl_getpagesize ();
@@ -1492,12 +1532,12 @@ _GL_WARN_ON_USE (getpagesize, "getpagesize is unportable - "
1492# undef getpass 1532# undef getpass
1493# define getpass rpl_getpass 1533# define getpass rpl_getpass
1494# endif 1534# endif
1495_GL_FUNCDECL_RPL (getpass, char *, (const char *prompt) 1535_GL_FUNCDECL_RPL (getpass, char *, (const char *prompt),
1496 _GL_ARG_NONNULL ((1))); 1536 _GL_ARG_NONNULL ((1)));
1497_GL_CXXALIAS_RPL (getpass, char *, (const char *prompt)); 1537_GL_CXXALIAS_RPL (getpass, char *, (const char *prompt));
1498# else 1538# else
1499# if !@HAVE_GETPASS@ 1539# if !@HAVE_GETPASS@
1500_GL_FUNCDECL_SYS (getpass, char *, (const char *prompt) 1540_GL_FUNCDECL_SYS (getpass, char *, (const char *prompt),
1501 _GL_ARG_NONNULL ((1))); 1541 _GL_ARG_NONNULL ((1)));
1502# endif 1542# endif
1503_GL_CXXALIAS_SYS (getpass, char *, (const char *prompt)); 1543_GL_CXXALIAS_SYS (getpass, char *, (const char *prompt));
@@ -1530,12 +1570,21 @@ _GL_CXXALIASWARN (getpid);
1530 1570
1531 1571
1532#if @GNULIB_GETUSERSHELL@ 1572#if @GNULIB_GETUSERSHELL@
1573# if @REPLACE_GETUSERSHELL@
1533/* Return the next valid login shell on the system, or NULL when the end of 1574/* Return the next valid login shell on the system, or NULL when the end of
1534 the list has been reached. */ 1575 the list has been reached. */
1535# if !@HAVE_DECL_GETUSERSHELL@ 1576# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1536_GL_FUNCDECL_SYS (getusershell, char *, (void)); 1577# undef getusershell
1537# endif 1578# define getusershell rpl_getusershell
1579# endif
1580_GL_FUNCDECL_RPL (getusershell, char *, (void), );
1581_GL_CXXALIAS_RPL (getusershell, char *, (void));
1582# else
1583# if !@HAVE_DECL_GETUSERSHELL@
1584_GL_FUNCDECL_SYS (getusershell, char *, (void), );
1585# endif
1538_GL_CXXALIAS_SYS (getusershell, char *, (void)); 1586_GL_CXXALIAS_SYS (getusershell, char *, (void));
1587# endif
1539_GL_CXXALIASWARN (getusershell); 1588_GL_CXXALIASWARN (getusershell);
1540#elif defined GNULIB_POSIXCHECK 1589#elif defined GNULIB_POSIXCHECK
1541# undef getusershell 1590# undef getusershell
@@ -1547,10 +1596,19 @@ _GL_WARN_ON_USE (getusershell, "getusershell is unportable - "
1547 1596
1548#if @GNULIB_GETUSERSHELL@ 1597#if @GNULIB_GETUSERSHELL@
1549/* Rewind to pointer that is advanced at each getusershell() call. */ 1598/* Rewind to pointer that is advanced at each getusershell() call. */
1550# if !@HAVE_DECL_GETUSERSHELL@ 1599# if @REPLACE_GETUSERSHELL@
1551_GL_FUNCDECL_SYS (setusershell, void, (void)); 1600# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1552# endif 1601# undef setusershell
1602# define setusershell rpl_setusershell
1603# endif
1604_GL_FUNCDECL_RPL (setusershell, void, (void), );
1605_GL_CXXALIAS_RPL (setusershell, void, (void));
1606# else
1607# if !@HAVE_DECL_GETUSERSHELL@
1608_GL_FUNCDECL_SYS (setusershell, void, (void), );
1609# endif
1553_GL_CXXALIAS_SYS (setusershell, void, (void)); 1610_GL_CXXALIAS_SYS (setusershell, void, (void));
1611# endif
1554_GL_CXXALIASWARN (setusershell); 1612_GL_CXXALIASWARN (setusershell);
1555#elif defined GNULIB_POSIXCHECK 1613#elif defined GNULIB_POSIXCHECK
1556# undef setusershell 1614# undef setusershell
@@ -1563,10 +1621,19 @@ _GL_WARN_ON_USE (setusershell, "setusershell is unportable - "
1563#if @GNULIB_GETUSERSHELL@ 1621#if @GNULIB_GETUSERSHELL@
1564/* Free the pointer that is advanced at each getusershell() call and 1622/* Free the pointer that is advanced at each getusershell() call and
1565 associated resources. */ 1623 associated resources. */
1566# if !@HAVE_DECL_GETUSERSHELL@ 1624# if @REPLACE_GETUSERSHELL@
1567_GL_FUNCDECL_SYS (endusershell, void, (void)); 1625# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1568# endif 1626# undef endusershell
1627# define endusershell rpl_endusershell
1628# endif
1629_GL_FUNCDECL_RPL (endusershell, void, (void), );
1630_GL_CXXALIAS_RPL (endusershell, void, (void));
1631# else
1632# if !@HAVE_DECL_GETUSERSHELL@
1633_GL_FUNCDECL_SYS (endusershell, void, (void), );
1634# endif
1569_GL_CXXALIAS_SYS (endusershell, void, (void)); 1635_GL_CXXALIAS_SYS (endusershell, void, (void));
1636# endif
1570_GL_CXXALIASWARN (endusershell); 1637_GL_CXXALIASWARN (endusershell);
1571#elif defined GNULIB_POSIXCHECK 1638#elif defined GNULIB_POSIXCHECK
1572# undef endusershell 1639# undef endusershell
@@ -1580,7 +1647,7 @@ _GL_WARN_ON_USE (endusershell, "endusershell is unportable - "
1580#if @GNULIB_GROUP_MEMBER@ 1647#if @GNULIB_GROUP_MEMBER@
1581/* Determine whether group id is in calling user's group list. */ 1648/* Determine whether group id is in calling user's group list. */
1582# if !@HAVE_GROUP_MEMBER@ 1649# if !@HAVE_GROUP_MEMBER@
1583_GL_FUNCDECL_SYS (group_member, int, (gid_t gid)); 1650_GL_FUNCDECL_SYS (group_member, int, (gid_t gid), );
1584# endif 1651# endif
1585_GL_CXXALIAS_SYS (group_member, int, (gid_t gid)); 1652_GL_CXXALIAS_SYS (group_member, int, (gid_t gid));
1586_GL_CXXALIASWARN (group_member); 1653_GL_CXXALIASWARN (group_member);
@@ -1600,7 +1667,7 @@ _GL_WARN_ON_USE (group_member, "group_member is unportable - "
1600# define isatty rpl_isatty 1667# define isatty rpl_isatty
1601# endif 1668# endif
1602# define GNULIB_defined_isatty 1 1669# define GNULIB_defined_isatty 1
1603_GL_FUNCDECL_RPL (isatty, int, (int fd)); 1670_GL_FUNCDECL_RPL (isatty, int, (int fd), );
1604_GL_CXXALIAS_RPL (isatty, int, (int fd)); 1671_GL_CXXALIAS_RPL (isatty, int, (int fd));
1605# elif defined _WIN32 && !defined __CYGWIN__ 1672# elif defined _WIN32 && !defined __CYGWIN__
1606# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1673# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -1646,13 +1713,13 @@ _GL_CXXALIASWARN (isatty);
1646# undef lchown 1713# undef lchown
1647# define lchown rpl_lchown 1714# define lchown rpl_lchown
1648# endif 1715# endif
1649_GL_FUNCDECL_RPL (lchown, int, (char const *file, uid_t owner, gid_t group) 1716_GL_FUNCDECL_RPL (lchown, int, (char const *file, uid_t owner, gid_t group),
1650 _GL_ARG_NONNULL ((1))); 1717 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
1651_GL_CXXALIAS_RPL (lchown, int, (char const *file, uid_t owner, gid_t group)); 1718_GL_CXXALIAS_RPL (lchown, int, (char const *file, uid_t owner, gid_t group));
1652# else 1719# else
1653# if !@HAVE_LCHOWN@ 1720# if !@HAVE_LCHOWN@
1654_GL_FUNCDECL_SYS (lchown, int, (char const *file, uid_t owner, gid_t group) 1721_GL_FUNCDECL_SYS (lchown, int, (char const *file, uid_t owner, gid_t group),
1655 _GL_ARG_NONNULL ((1))); 1722 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
1656# endif 1723# endif
1657_GL_CXXALIAS_SYS (lchown, int, (char const *file, uid_t owner, gid_t group)); 1724_GL_CXXALIAS_SYS (lchown, int, (char const *file, uid_t owner, gid_t group));
1658# endif 1725# endif
@@ -1675,13 +1742,13 @@ _GL_WARN_ON_USE (lchown, "lchown is unportable to pre-POSIX.1-2001 systems - "
1675# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1742# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1676# define link rpl_link 1743# define link rpl_link
1677# endif 1744# endif
1678_GL_FUNCDECL_RPL (link, int, (const char *path1, const char *path2) 1745_GL_FUNCDECL_RPL (link, int, (const char *path1, const char *path2),
1679 _GL_ARG_NONNULL ((1, 2))); 1746 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_NODISCARD);
1680_GL_CXXALIAS_RPL (link, int, (const char *path1, const char *path2)); 1747_GL_CXXALIAS_RPL (link, int, (const char *path1, const char *path2));
1681# else 1748# else
1682# if !@HAVE_LINK@ 1749# if !@HAVE_LINK@
1683_GL_FUNCDECL_SYS (link, int, (const char *path1, const char *path2) 1750_GL_FUNCDECL_SYS (link, int, (const char *path1, const char *path2),
1684 _GL_ARG_NONNULL ((1, 2))); 1751 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_NODISCARD);
1685# endif 1752# endif
1686_GL_CXXALIAS_SYS (link, int, (const char *path1, const char *path2)); 1753_GL_CXXALIAS_SYS (link, int, (const char *path1, const char *path2));
1687# endif 1754# endif
@@ -1706,8 +1773,8 @@ _GL_WARN_ON_USE (link, "link is unportable - "
1706# endif 1773# endif
1707_GL_FUNCDECL_RPL (linkat, int, 1774_GL_FUNCDECL_RPL (linkat, int,
1708 (int fd1, const char *path1, int fd2, const char *path2, 1775 (int fd1, const char *path1, int fd2, const char *path2,
1709 int flag) 1776 int flag),
1710 _GL_ARG_NONNULL ((2, 4))); 1777 _GL_ARG_NONNULL ((2, 4)) _GL_ATTRIBUTE_NODISCARD);
1711_GL_CXXALIAS_RPL (linkat, int, 1778_GL_CXXALIAS_RPL (linkat, int,
1712 (int fd1, const char *path1, int fd2, const char *path2, 1779 (int fd1, const char *path1, int fd2, const char *path2,
1713 int flag)); 1780 int flag));
@@ -1715,8 +1782,8 @@ _GL_CXXALIAS_RPL (linkat, int,
1715# if !@HAVE_LINKAT@ 1782# if !@HAVE_LINKAT@
1716_GL_FUNCDECL_SYS (linkat, int, 1783_GL_FUNCDECL_SYS (linkat, int,
1717 (int fd1, const char *path1, int fd2, const char *path2, 1784 (int fd1, const char *path1, int fd2, const char *path2,
1718 int flag) 1785 int flag),
1719 _GL_ARG_NONNULL ((2, 4))); 1786 _GL_ARG_NONNULL ((2, 4)) _GL_ATTRIBUTE_NODISCARD);
1720# endif 1787# endif
1721_GL_CXXALIAS_SYS (linkat, int, 1788_GL_CXXALIAS_SYS (linkat, int,
1722 (int fd1, const char *path1, int fd2, const char *path2, 1789 (int fd1, const char *path1, int fd2, const char *path2,
@@ -1743,7 +1810,7 @@ _GL_WARN_ON_USE (linkat, "linkat is unportable - "
1743# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1810# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1744# define lseek rpl_lseek 1811# define lseek rpl_lseek
1745# endif 1812# endif
1746_GL_FUNCDECL_RPL (lseek, off_t, (int fd, off_t offset, int whence)); 1813_GL_FUNCDECL_RPL (lseek, off_t, (int fd, off_t offset, int whence), );
1747_GL_CXXALIAS_RPL (lseek, off_t, (int fd, off_t offset, int whence)); 1814_GL_CXXALIAS_RPL (lseek, off_t, (int fd, off_t offset, int whence));
1748# elif defined _WIN32 && !defined __CYGWIN__ 1815# elif defined _WIN32 && !defined __CYGWIN__
1749# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1816# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -1783,7 +1850,8 @@ _GL_CXXALIASWARN (lseek);
1783 Store the read-end as fd[0] and the write-end as fd[1]. 1850 Store the read-end as fd[0] and the write-end as fd[1].
1784 Return 0 upon success, or -1 with errno set upon failure. */ 1851 Return 0 upon success, or -1 with errno set upon failure. */
1785# if !@HAVE_PIPE@ 1852# if !@HAVE_PIPE@
1786_GL_FUNCDECL_SYS (pipe, int, (int fd[2]) _GL_ARG_NONNULL ((1))); 1853_GL_FUNCDECL_SYS (pipe, int, (int fd[2]),
1854 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
1787# endif 1855# endif
1788_GL_CXXALIAS_SYS (pipe, int, (int fd[2])); 1856_GL_CXXALIAS_SYS (pipe, int, (int fd[2]));
1789_GL_CXXALIASWARN (pipe); 1857_GL_CXXALIASWARN (pipe);
@@ -1810,10 +1878,12 @@ _GL_WARN_ON_USE (pipe, "pipe is unportable - "
1810# undef pipe2 1878# undef pipe2
1811# define pipe2 rpl_pipe2 1879# define pipe2 rpl_pipe2
1812# endif 1880# endif
1813_GL_FUNCDECL_RPL (pipe2, int, (int fd[2], int flags) _GL_ARG_NONNULL ((1))); 1881_GL_FUNCDECL_RPL (pipe2, int, (int fd[2], int flags),
1882 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
1814_GL_CXXALIAS_RPL (pipe2, int, (int fd[2], int flags)); 1883_GL_CXXALIAS_RPL (pipe2, int, (int fd[2], int flags));
1815# else 1884# else
1816_GL_FUNCDECL_SYS (pipe2, int, (int fd[2], int flags) _GL_ARG_NONNULL ((1))); 1885_GL_FUNCDECL_SYS (pipe2, int, (int fd[2], int flags),
1886 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
1817_GL_CXXALIAS_SYS (pipe2, int, (int fd[2], int flags)); 1887_GL_CXXALIAS_SYS (pipe2, int, (int fd[2], int flags));
1818# endif 1888# endif
1819# if __GLIBC__ >= 2 1889# if __GLIBC__ >= 2
@@ -1840,15 +1910,15 @@ _GL_WARN_ON_USE (pipe2, "pipe2 is unportable - "
1840# define pread rpl_pread 1910# define pread rpl_pread
1841# endif 1911# endif
1842_GL_FUNCDECL_RPL (pread, ssize_t, 1912_GL_FUNCDECL_RPL (pread, ssize_t,
1843 (int fd, void *buf, size_t bufsize, off_t offset) 1913 (int fd, void *buf, size_t bufsize, off_t offset),
1844 _GL_ARG_NONNULL ((2))); 1914 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD);
1845_GL_CXXALIAS_RPL (pread, ssize_t, 1915_GL_CXXALIAS_RPL (pread, ssize_t,
1846 (int fd, void *buf, size_t bufsize, off_t offset)); 1916 (int fd, void *buf, size_t bufsize, off_t offset));
1847# else 1917# else
1848# if !@HAVE_PREAD@ 1918# if !@HAVE_PREAD@
1849_GL_FUNCDECL_SYS (pread, ssize_t, 1919_GL_FUNCDECL_SYS (pread, ssize_t,
1850 (int fd, void *buf, size_t bufsize, off_t offset) 1920 (int fd, void *buf, size_t bufsize, off_t offset),
1851 _GL_ARG_NONNULL ((2))); 1921 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD);
1852# endif 1922# endif
1853_GL_CXXALIAS_SYS (pread, ssize_t, 1923_GL_CXXALIAS_SYS (pread, ssize_t,
1854 (int fd, void *buf, size_t bufsize, off_t offset)); 1924 (int fd, void *buf, size_t bufsize, off_t offset));
@@ -1877,15 +1947,15 @@ _GL_WARN_ON_USE (pread, "pread is unportable - "
1877# define pwrite rpl_pwrite 1947# define pwrite rpl_pwrite
1878# endif 1948# endif
1879_GL_FUNCDECL_RPL (pwrite, ssize_t, 1949_GL_FUNCDECL_RPL (pwrite, ssize_t,
1880 (int fd, const void *buf, size_t bufsize, off_t offset) 1950 (int fd, const void *buf, size_t bufsize, off_t offset),
1881 _GL_ARG_NONNULL ((2))); 1951 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD);
1882_GL_CXXALIAS_RPL (pwrite, ssize_t, 1952_GL_CXXALIAS_RPL (pwrite, ssize_t,
1883 (int fd, const void *buf, size_t bufsize, off_t offset)); 1953 (int fd, const void *buf, size_t bufsize, off_t offset));
1884# else 1954# else
1885# if !@HAVE_PWRITE@ 1955# if !@HAVE_PWRITE@
1886_GL_FUNCDECL_SYS (pwrite, ssize_t, 1956_GL_FUNCDECL_SYS (pwrite, ssize_t,
1887 (int fd, const void *buf, size_t bufsize, off_t offset) 1957 (int fd, const void *buf, size_t bufsize, off_t offset),
1888 _GL_ARG_NONNULL ((2))); 1958 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD);
1889# endif 1959# endif
1890_GL_CXXALIAS_SYS (pwrite, ssize_t, 1960_GL_CXXALIAS_SYS (pwrite, ssize_t,
1891 (int fd, const void *buf, size_t bufsize, off_t offset)); 1961 (int fd, const void *buf, size_t bufsize, off_t offset));
@@ -1911,8 +1981,9 @@ _GL_WARN_ON_USE (pwrite, "pwrite is unportable - "
1911# undef read 1981# undef read
1912# define read rpl_read 1982# define read rpl_read
1913# endif 1983# endif
1914_GL_FUNCDECL_RPL (read, ssize_t, (int fd, void *buf, size_t count) 1984
1915 _GL_ARG_NONNULL ((2))); 1985_GL_FUNCDECL_RPL (read, ssize_t, (int fd, void *buf, size_t count),
1986 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD);
1916_GL_CXXALIAS_RPL (read, ssize_t, (int fd, void *buf, size_t count)); 1987_GL_CXXALIAS_RPL (read, ssize_t, (int fd, void *buf, size_t count));
1917# elif defined _WIN32 && !defined __CYGWIN__ 1988# elif defined _WIN32 && !defined __CYGWIN__
1918# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1989# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -1933,11 +2004,7 @@ _GL_CXXALIASWARN (read);
1933# undef read 2004# undef read
1934# define read _read 2005# define read _read
1935# endif 2006# endif
1936# ifdef __MINGW32__ 2007_GL_CXXALIAS_MDA_CAST (read, ssize_t, (int fd, void *buf, unsigned int count));
1937_GL_CXXALIAS_MDA (read, int, (int fd, void *buf, unsigned int count));
1938# else
1939_GL_CXXALIAS_MDA (read, ssize_t, (int fd, void *buf, unsigned int count));
1940# endif
1941# else 2008# else
1942_GL_CXXALIAS_SYS (read, ssize_t, (int fd, void *buf, size_t count)); 2009_GL_CXXALIAS_SYS (read, ssize_t, (int fd, void *buf, size_t count));
1943# endif 2010# endif
@@ -1957,8 +2024,8 @@ _GL_CXXALIASWARN (read);
1957# endif 2024# endif
1958_GL_FUNCDECL_RPL (readlink, ssize_t, 2025_GL_FUNCDECL_RPL (readlink, ssize_t,
1959 (const char *restrict file, 2026 (const char *restrict file,
1960 char *restrict buf, size_t bufsize) 2027 char *restrict buf, size_t bufsize),
1961 _GL_ARG_NONNULL ((1, 2))); 2028 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_NODISCARD);
1962_GL_CXXALIAS_RPL (readlink, ssize_t, 2029_GL_CXXALIAS_RPL (readlink, ssize_t,
1963 (const char *restrict file, 2030 (const char *restrict file,
1964 char *restrict buf, size_t bufsize)); 2031 char *restrict buf, size_t bufsize));
@@ -1966,8 +2033,8 @@ _GL_CXXALIAS_RPL (readlink, ssize_t,
1966# if !@HAVE_READLINK@ 2033# if !@HAVE_READLINK@
1967_GL_FUNCDECL_SYS (readlink, ssize_t, 2034_GL_FUNCDECL_SYS (readlink, ssize_t,
1968 (const char *restrict file, 2035 (const char *restrict file,
1969 char *restrict buf, size_t bufsize) 2036 char *restrict buf, size_t bufsize),
1970 _GL_ARG_NONNULL ((1, 2))); 2037 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_NODISCARD);
1971# endif 2038# endif
1972_GL_CXXALIAS_SYS (readlink, ssize_t, 2039_GL_CXXALIAS_SYS (readlink, ssize_t,
1973 (const char *restrict file, 2040 (const char *restrict file,
@@ -1990,8 +2057,8 @@ _GL_WARN_ON_USE (readlink, "readlink is unportable - "
1990# endif 2057# endif
1991_GL_FUNCDECL_RPL (readlinkat, ssize_t, 2058_GL_FUNCDECL_RPL (readlinkat, ssize_t,
1992 (int fd, char const *restrict file, 2059 (int fd, char const *restrict file,
1993 char *restrict buf, size_t len) 2060 char *restrict buf, size_t len),
1994 _GL_ARG_NONNULL ((2, 3))); 2061 _GL_ARG_NONNULL ((2, 3)) _GL_ATTRIBUTE_NODISCARD);
1995_GL_CXXALIAS_RPL (readlinkat, ssize_t, 2062_GL_CXXALIAS_RPL (readlinkat, ssize_t,
1996 (int fd, char const *restrict file, 2063 (int fd, char const *restrict file,
1997 char *restrict buf, size_t len)); 2064 char *restrict buf, size_t len));
@@ -1999,8 +2066,8 @@ _GL_CXXALIAS_RPL (readlinkat, ssize_t,
1999# if !@HAVE_READLINKAT@ 2066# if !@HAVE_READLINKAT@
2000_GL_FUNCDECL_SYS (readlinkat, ssize_t, 2067_GL_FUNCDECL_SYS (readlinkat, ssize_t,
2001 (int fd, char const *restrict file, 2068 (int fd, char const *restrict file,
2002 char *restrict buf, size_t len) 2069 char *restrict buf, size_t len),
2003 _GL_ARG_NONNULL ((2, 3))); 2070 _GL_ARG_NONNULL ((2, 3)) _GL_ATTRIBUTE_NODISCARD);
2004# endif 2071# endif
2005_GL_CXXALIAS_SYS (readlinkat, ssize_t, 2072_GL_CXXALIAS_SYS (readlinkat, ssize_t,
2006 (int fd, char const *restrict file, 2073 (int fd, char const *restrict file,
@@ -2024,7 +2091,7 @@ _GL_WARN_ON_USE (readlinkat, "readlinkat is not portable - "
2024# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 2091# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2025# define rmdir rpl_rmdir 2092# define rmdir rpl_rmdir
2026# endif 2093# endif
2027_GL_FUNCDECL_RPL (rmdir, int, (char const *name) _GL_ARG_NONNULL ((1))); 2094_GL_FUNCDECL_RPL (rmdir, int, (char const *name), _GL_ARG_NONNULL ((1)));
2028_GL_CXXALIAS_RPL (rmdir, int, (char const *name)); 2095_GL_CXXALIAS_RPL (rmdir, int, (char const *name));
2029# elif defined _WIN32 && !defined __CYGWIN__ 2096# elif defined _WIN32 && !defined __CYGWIN__
2030# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 2097# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -2073,18 +2140,22 @@ _GL_CXXALIASWARN (rmdir);
2073# undef sethostname 2140# undef sethostname
2074# define sethostname rpl_sethostname 2141# define sethostname rpl_sethostname
2075# endif 2142# endif
2076_GL_FUNCDECL_RPL (sethostname, int, (const char *name, size_t len) 2143_GL_FUNCDECL_RPL (sethostname, int,
2077 _GL_ARG_NONNULL ((1))); 2144 (const char *name, size_t len),
2078_GL_CXXALIAS_RPL (sethostname, int, (const char *name, size_t len)); 2145 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
2146_GL_CXXALIAS_RPL (sethostname, int,
2147 (const char *name, size_t len));
2079# else 2148# else
2080# if !@HAVE_SETHOSTNAME@ || !@HAVE_DECL_SETHOSTNAME@ 2149# if !@HAVE_SETHOSTNAME@ || !@HAVE_DECL_SETHOSTNAME@
2081_GL_FUNCDECL_SYS (sethostname, int, (const char *name, size_t len) 2150_GL_FUNCDECL_SYS (sethostname, int,
2082 _GL_ARG_NONNULL ((1))); 2151 (const char *name, size_t len),
2152 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
2083# endif 2153# endif
2084/* Need to cast, because on Solaris 11 2011-10, Mac OS X 10.5, IRIX 6.5 2154/* Need to cast, because on Solaris 11 2011-10, Mac OS X 10.5, IRIX 6.5
2085 and FreeBSD 6.4 the second parameter is int. On Solaris 11 2155 and FreeBSD 6.4 the second parameter is int. On Solaris 11
2086 2011-10, the first parameter is not const. */ 2156 2011-10, the first parameter is not const. */
2087_GL_CXXALIAS_SYS_CAST (sethostname, int, (const char *name, size_t len)); 2157_GL_CXXALIAS_SYS_CAST (sethostname, int,
2158 (const char *name, size_t len));
2088# endif 2159# endif
2089# if __GLIBC__ >= 2 2160# if __GLIBC__ >= 2
2090_GL_CXXALIASWARN (sethostname); 2161_GL_CXXALIASWARN (sethostname);
@@ -2108,11 +2179,11 @@ _GL_WARN_ON_USE (sethostname, "sethostname is unportable - "
2108# undef sleep 2179# undef sleep
2109# define sleep rpl_sleep 2180# define sleep rpl_sleep
2110# endif 2181# endif
2111_GL_FUNCDECL_RPL (sleep, unsigned int, (unsigned int n)); 2182_GL_FUNCDECL_RPL (sleep, unsigned int, (unsigned int n), );
2112_GL_CXXALIAS_RPL (sleep, unsigned int, (unsigned int n)); 2183_GL_CXXALIAS_RPL (sleep, unsigned int, (unsigned int n));
2113# else 2184# else
2114# if !@HAVE_SLEEP@ 2185# if !@HAVE_SLEEP@
2115_GL_FUNCDECL_SYS (sleep, unsigned int, (unsigned int n)); 2186_GL_FUNCDECL_SYS (sleep, unsigned int, (unsigned int n), );
2116# endif 2187# endif
2117_GL_CXXALIAS_SYS (sleep, unsigned int, (unsigned int n)); 2188_GL_CXXALIAS_SYS (sleep, unsigned int, (unsigned int n));
2118# endif 2189# endif
@@ -2157,15 +2228,19 @@ _GL_CXXALIASWARN (swab);
2157# undef symlink 2228# undef symlink
2158# define symlink rpl_symlink 2229# define symlink rpl_symlink
2159# endif 2230# endif
2160_GL_FUNCDECL_RPL (symlink, int, (char const *contents, char const *file) 2231_GL_FUNCDECL_RPL (symlink, int,
2161 _GL_ARG_NONNULL ((1, 2))); 2232 (char const *contents, char const *file),
2162_GL_CXXALIAS_RPL (symlink, int, (char const *contents, char const *file)); 2233 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_NODISCARD);
2234_GL_CXXALIAS_RPL (symlink, int,
2235 (char const *contents, char const *file));
2163# else 2236# else
2164# if !@HAVE_SYMLINK@ 2237# if !@HAVE_SYMLINK@
2165_GL_FUNCDECL_SYS (symlink, int, (char const *contents, char const *file) 2238_GL_FUNCDECL_SYS (symlink, int,
2166 _GL_ARG_NONNULL ((1, 2))); 2239 (char const *contents, char const *file),
2240 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_NODISCARD);
2167# endif 2241# endif
2168_GL_CXXALIAS_SYS (symlink, int, (char const *contents, char const *file)); 2242_GL_CXXALIAS_SYS (symlink, int,
2243 (char const *contents, char const *file));
2169# endif 2244# endif
2170_GL_CXXALIASWARN (symlink); 2245_GL_CXXALIASWARN (symlink);
2171#elif defined GNULIB_POSIXCHECK 2246#elif defined GNULIB_POSIXCHECK
@@ -2184,15 +2259,15 @@ _GL_WARN_ON_USE (symlink, "symlink is not portable - "
2184# define symlinkat rpl_symlinkat 2259# define symlinkat rpl_symlinkat
2185# endif 2260# endif
2186_GL_FUNCDECL_RPL (symlinkat, int, 2261_GL_FUNCDECL_RPL (symlinkat, int,
2187 (char const *contents, int fd, char const *file) 2262 (char const *contents, int fd, char const *file),
2188 _GL_ARG_NONNULL ((1, 3))); 2263 _GL_ARG_NONNULL ((1, 3)) _GL_ATTRIBUTE_NODISCARD);
2189_GL_CXXALIAS_RPL (symlinkat, int, 2264_GL_CXXALIAS_RPL (symlinkat, int,
2190 (char const *contents, int fd, char const *file)); 2265 (char const *contents, int fd, char const *file));
2191# else 2266# else
2192# if !@HAVE_SYMLINKAT@ 2267# if !@HAVE_SYMLINKAT@
2193_GL_FUNCDECL_SYS (symlinkat, int, 2268_GL_FUNCDECL_SYS (symlinkat, int,
2194 (char const *contents, int fd, char const *file) 2269 (char const *contents, int fd, char const *file),
2195 _GL_ARG_NONNULL ((1, 3))); 2270 _GL_ARG_NONNULL ((1, 3)) _GL_ATTRIBUTE_NODISCARD);
2196# endif 2271# endif
2197_GL_CXXALIAS_SYS (symlinkat, int, 2272_GL_CXXALIAS_SYS (symlinkat, int,
2198 (char const *contents, int fd, char const *file)); 2273 (char const *contents, int fd, char const *file));
@@ -2219,13 +2294,13 @@ _GL_WARN_ON_USE (symlinkat, "symlinkat is not portable - "
2219# undef truncate 2294# undef truncate
2220# define truncate rpl_truncate 2295# define truncate rpl_truncate
2221# endif 2296# endif
2222_GL_FUNCDECL_RPL (truncate, int, (const char *filename, off_t length) 2297_GL_FUNCDECL_RPL (truncate, int, (const char *filename, off_t length),
2223 _GL_ARG_NONNULL ((1))); 2298 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
2224_GL_CXXALIAS_RPL (truncate, int, (const char *filename, off_t length)); 2299_GL_CXXALIAS_RPL (truncate, int, (const char *filename, off_t length));
2225# else 2300# else
2226# if !@HAVE_DECL_TRUNCATE@ 2301# if !@HAVE_DECL_TRUNCATE@
2227_GL_FUNCDECL_SYS (truncate, int, (const char *filename, off_t length) 2302_GL_FUNCDECL_SYS (truncate, int, (const char *filename, off_t length),
2228 _GL_ARG_NONNULL ((1))); 2303 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NODISCARD);
2229# endif 2304# endif
2230_GL_CXXALIAS_SYS (truncate, int, (const char *filename, off_t length)); 2305_GL_CXXALIAS_SYS (truncate, int, (const char *filename, off_t length));
2231# endif 2306# endif
@@ -2250,13 +2325,15 @@ _GL_WARN_ON_USE (truncate, "truncate is unportable - "
2250# define ttyname_r rpl_ttyname_r 2325# define ttyname_r rpl_ttyname_r
2251# endif 2326# endif
2252_GL_FUNCDECL_RPL (ttyname_r, int, 2327_GL_FUNCDECL_RPL (ttyname_r, int,
2253 (int fd, char *buf, size_t buflen) _GL_ARG_NONNULL ((2))); 2328 (int fd, char *buf, size_t buflen),
2329 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD);
2254_GL_CXXALIAS_RPL (ttyname_r, int, 2330_GL_CXXALIAS_RPL (ttyname_r, int,
2255 (int fd, char *buf, size_t buflen)); 2331 (int fd, char *buf, size_t buflen));
2256# else 2332# else
2257# if !@HAVE_DECL_TTYNAME_R@ 2333# if !@HAVE_DECL_TTYNAME_R@
2258_GL_FUNCDECL_SYS (ttyname_r, int, 2334_GL_FUNCDECL_SYS (ttyname_r, int,
2259 (int fd, char *buf, size_t buflen) _GL_ARG_NONNULL ((2))); 2335 (int fd, char *buf, size_t buflen),
2336 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD);
2260# endif 2337# endif
2261_GL_CXXALIAS_SYS (ttyname_r, int, 2338_GL_CXXALIAS_SYS (ttyname_r, int,
2262 (int fd, char *buf, size_t buflen)); 2339 (int fd, char *buf, size_t buflen));
@@ -2279,7 +2356,7 @@ _GL_WARN_ON_USE (ttyname_r, "ttyname_r is not portable - "
2279# undef unlink 2356# undef unlink
2280# define unlink rpl_unlink 2357# define unlink rpl_unlink
2281# endif 2358# endif
2282_GL_FUNCDECL_RPL (unlink, int, (char const *file) _GL_ARG_NONNULL ((1))); 2359_GL_FUNCDECL_RPL (unlink, int, (char const *file), _GL_ARG_NONNULL ((1)));
2283_GL_CXXALIAS_RPL (unlink, int, (char const *file)); 2360_GL_CXXALIAS_RPL (unlink, int, (char const *file));
2284# elif defined _WIN32 && !defined __CYGWIN__ 2361# elif defined _WIN32 && !defined __CYGWIN__
2285# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 2362# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -2320,12 +2397,12 @@ _GL_CXXALIASWARN (unlink);
2320# undef unlinkat 2397# undef unlinkat
2321# define unlinkat rpl_unlinkat 2398# define unlinkat rpl_unlinkat
2322# endif 2399# endif
2323_GL_FUNCDECL_RPL (unlinkat, int, (int fd, char const *file, int flag) 2400_GL_FUNCDECL_RPL (unlinkat, int, (int fd, char const *file, int flag),
2324 _GL_ARG_NONNULL ((2))); 2401 _GL_ARG_NONNULL ((2)));
2325_GL_CXXALIAS_RPL (unlinkat, int, (int fd, char const *file, int flag)); 2402_GL_CXXALIAS_RPL (unlinkat, int, (int fd, char const *file, int flag));
2326# else 2403# else
2327# if !@HAVE_UNLINKAT@ 2404# if !@HAVE_UNLINKAT@
2328_GL_FUNCDECL_SYS (unlinkat, int, (int fd, char const *file, int flag) 2405_GL_FUNCDECL_SYS (unlinkat, int, (int fd, char const *file, int flag),
2329 _GL_ARG_NONNULL ((2))); 2406 _GL_ARG_NONNULL ((2)));
2330# endif 2407# endif
2331_GL_CXXALIAS_SYS (unlinkat, int, (int fd, char const *file, int flag)); 2408_GL_CXXALIAS_SYS (unlinkat, int, (int fd, char const *file, int flag));
@@ -2343,18 +2420,18 @@ _GL_WARN_ON_USE (unlinkat, "unlinkat is not portable - "
2343#if @GNULIB_USLEEP@ 2420#if @GNULIB_USLEEP@
2344/* Pause the execution of the current thread for N microseconds. 2421/* Pause the execution of the current thread for N microseconds.
2345 Returns 0 on completion, or -1 on range error. 2422 Returns 0 on completion, or -1 on range error.
2346 See the POSIX:2001 specification 2423 See the POSIX.1-2004 specification
2347 <https://pubs.opengroup.org/onlinepubs/009695399/functions/usleep.html>. */ 2424 <https://pubs.opengroup.org/onlinepubs/009695399/functions/usleep.html>. */
2348# if @REPLACE_USLEEP@ 2425# if @REPLACE_USLEEP@
2349# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 2426# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2350# undef usleep 2427# undef usleep
2351# define usleep rpl_usleep 2428# define usleep rpl_usleep
2352# endif 2429# endif
2353_GL_FUNCDECL_RPL (usleep, int, (useconds_t n)); 2430_GL_FUNCDECL_RPL (usleep, int, (useconds_t n), );
2354_GL_CXXALIAS_RPL (usleep, int, (useconds_t n)); 2431_GL_CXXALIAS_RPL (usleep, int, (useconds_t n));
2355# else 2432# else
2356# if !@HAVE_USLEEP@ 2433# if !@HAVE_USLEEP@
2357_GL_FUNCDECL_SYS (usleep, int, (useconds_t n)); 2434_GL_FUNCDECL_SYS (usleep, int, (useconds_t n), );
2358# endif 2435# endif
2359/* Need to cast, because on Haiku, the first parameter is 2436/* Need to cast, because on Haiku, the first parameter is
2360 unsigned int n. */ 2437 unsigned int n. */
@@ -2379,17 +2456,21 @@ _GL_WARN_ON_USE (usleep, "usleep is unportable - "
2379# undef write 2456# undef write
2380# define write rpl_write 2457# define write rpl_write
2381# endif 2458# endif
2382_GL_FUNCDECL_RPL (write, ssize_t, (int fd, const void *buf, size_t count) 2459_GL_FUNCDECL_RPL (write, ssize_t,
2383 _GL_ARG_NONNULL ((2))); 2460 (int fd, const void *buf, size_t count),
2384_GL_CXXALIAS_RPL (write, ssize_t, (int fd, const void *buf, size_t count)); 2461 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD);
2462_GL_CXXALIAS_RPL (write, ssize_t,
2463 (int fd, const void *buf, size_t count));
2385# elif defined _WIN32 && !defined __CYGWIN__ 2464# elif defined _WIN32 && !defined __CYGWIN__
2386# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 2465# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2387# undef write 2466# undef write
2388# define write _write 2467# define write _write
2389# endif 2468# endif
2390_GL_CXXALIAS_MDA (write, ssize_t, (int fd, const void *buf, size_t count)); 2469_GL_CXXALIAS_MDA (write, ssize_t,
2470 (int fd, const void *buf, size_t count));
2391# else 2471# else
2392_GL_CXXALIAS_SYS (write, ssize_t, (int fd, const void *buf, size_t count)); 2472_GL_CXXALIAS_SYS (write, ssize_t,
2473 (int fd, const void *buf, size_t count));
2393# endif 2474# endif
2394_GL_CXXALIASWARN (write); 2475_GL_CXXALIASWARN (write);
2395#elif @GNULIB_MDA_WRITE@ 2476#elif @GNULIB_MDA_WRITE@
@@ -2401,13 +2482,11 @@ _GL_CXXALIASWARN (write);
2401# undef write 2482# undef write
2402# define write _write 2483# define write _write
2403# endif 2484# endif
2404# ifdef __MINGW32__ 2485_GL_CXXALIAS_MDA_CAST (write, ssize_t,
2405_GL_CXXALIAS_MDA (write, int, (int fd, const void *buf, unsigned int count)); 2486 (int fd, const void *buf, unsigned int count));
2406# else
2407_GL_CXXALIAS_MDA (write, ssize_t, (int fd, const void *buf, unsigned int count));
2408# endif
2409# else 2487# else
2410_GL_CXXALIAS_SYS (write, ssize_t, (int fd, const void *buf, size_t count)); 2488_GL_CXXALIAS_SYS (write, ssize_t,
2489 (int fd, const void *buf, size_t count));
2411# endif 2490# endif
2412_GL_CXXALIASWARN (write); 2491_GL_CXXALIASWARN (write);
2413#endif 2492#endif
diff --git a/gl/unitypes.h b/gl/unitypes.h
new file mode 100644
index 00000000..83a91750
--- /dev/null
+++ b/gl/unitypes.h
@@ -0,0 +1,72 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* Elementary types and macros for the GNU UniString library.
3 Copyright (C) 2002, 2005-2006, 2009-2025 Free Software Foundation, Inc.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#ifndef _UNITYPES_H
19#define _UNITYPES_H
20
21/* Get uint8_t, uint16_t, uint32_t. */
22#include <stdint.h>
23
24#ifdef __cplusplus
25extern "C" {
26#endif
27
28
29/* Type representing a Unicode character. */
30typedef uint32_t ucs4_t;
31
32/* Attribute of a function whose result depends only on the arguments
33 (not pointers!) and which has no side effects. */
34#ifndef _UC_ATTRIBUTE_CONST
35# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) || defined __clang__
36# define _UC_ATTRIBUTE_CONST __attribute__ ((__const__))
37# else
38# define _UC_ATTRIBUTE_CONST
39# endif
40#endif
41
42/* Attribute of a function whose result depends only on the arguments
43 (possibly pointers) and global memory, and which has no side effects. */
44#ifndef _UC_ATTRIBUTE_PURE
45# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) || defined __clang__
46# define _UC_ATTRIBUTE_PURE __attribute__ ((__pure__))
47# else
48# define _UC_ATTRIBUTE_PURE
49# endif
50#endif
51
52/* Qualifier in a function declaration, that asserts that the caller must
53 pass a pointer to a different object in the specified pointer argument
54 than in the other pointer arguments. */
55#ifndef _UC_RESTRICT
56# if defined __restrict \
57 || 2 < __GNUC__ + (95 <= __GNUC_MINOR__) \
58 || __clang_major__ >= 3
59# define _UC_RESTRICT __restrict
60# elif 199901L <= __STDC_VERSION__ || defined restrict
61# define _UC_RESTRICT restrict
62# else
63# define _UC_RESTRICT
64# endif
65#endif
66
67
68#ifdef __cplusplus
69}
70#endif
71
72#endif /* _UNITYPES_H */
diff --git a/gl/unitypes.in.h b/gl/unitypes.in.h
new file mode 100644
index 00000000..776d90e9
--- /dev/null
+++ b/gl/unitypes.in.h
@@ -0,0 +1,71 @@
1/* Elementary types and macros for the GNU UniString library.
2 Copyright (C) 2002, 2005-2006, 2009-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#ifndef _UNITYPES_H
18#define _UNITYPES_H
19
20/* Get uint8_t, uint16_t, uint32_t. */
21#include <stdint.h>
22
23#ifdef __cplusplus
24extern "C" {
25#endif
26
27
28/* Type representing a Unicode character. */
29typedef uint32_t ucs4_t;
30
31/* Attribute of a function whose result depends only on the arguments
32 (not pointers!) and which has no side effects. */
33#ifndef _UC_ATTRIBUTE_CONST
34# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) || defined __clang__
35# define _UC_ATTRIBUTE_CONST __attribute__ ((__const__))
36# else
37# define _UC_ATTRIBUTE_CONST
38# endif
39#endif
40
41/* Attribute of a function whose result depends only on the arguments
42 (possibly pointers) and global memory, and which has no side effects. */
43#ifndef _UC_ATTRIBUTE_PURE
44# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) || defined __clang__
45# define _UC_ATTRIBUTE_PURE __attribute__ ((__pure__))
46# else
47# define _UC_ATTRIBUTE_PURE
48# endif
49#endif
50
51/* Qualifier in a function declaration, that asserts that the caller must
52 pass a pointer to a different object in the specified pointer argument
53 than in the other pointer arguments. */
54#ifndef _UC_RESTRICT
55# if defined __restrict \
56 || 2 < __GNUC__ + (95 <= __GNUC_MINOR__) \
57 || __clang_major__ >= 3
58# define _UC_RESTRICT __restrict
59# elif 199901L <= __STDC_VERSION__ || defined restrict
60# define _UC_RESTRICT restrict
61# else
62# define _UC_RESTRICT
63# endif
64#endif
65
66
67#ifdef __cplusplus
68}
69#endif
70
71#endif /* _UNITYPES_H */
diff --git a/gl/uniwidth.h b/gl/uniwidth.h
new file mode 100644
index 00000000..b88df2bf
--- /dev/null
+++ b/gl/uniwidth.h
@@ -0,0 +1,73 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* Display width functions.
3 Copyright (C) 2001-2002, 2005, 2007, 2009-2025 Free Software Foundation,
4 Inc.
5
6 This file is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
10
11 This file is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18
19#ifndef _UNIWIDTH_H
20#define _UNIWIDTH_H
21
22#include "unitypes.h"
23
24/* Get size_t. */
25#include <stddef.h>
26
27/* Get locale_charset() declaration. */
28#include "localcharset.h"
29
30#ifdef __cplusplus
31extern "C" {
32#endif
33
34
35/* Display width. */
36
37/* These functions are locale dependent. The encoding argument identifies
38 the encoding (e.g. "ISO-8859-2" for Polish). */
39
40/* Determine number of column positions required for UC. */
41extern int
42 uc_width (ucs4_t uc, const char *encoding)
43 _UC_ATTRIBUTE_PURE;
44
45/* Determine number of column positions required for first N units
46 (or fewer if S ends before this) in S. */
47extern int
48 u8_width (const uint8_t *s, size_t n, const char *encoding)
49 _UC_ATTRIBUTE_PURE;
50extern int
51 u16_width (const uint16_t *s, size_t n, const char *encoding)
52 _UC_ATTRIBUTE_PURE;
53extern int
54 u32_width (const uint32_t *s, size_t n, const char *encoding)
55 _UC_ATTRIBUTE_PURE;
56
57/* Determine number of column positions required for S. */
58extern int
59 u8_strwidth (const uint8_t *s, const char *encoding)
60 _UC_ATTRIBUTE_PURE;
61extern int
62 u16_strwidth (const uint16_t *s, const char *encoding)
63 _UC_ATTRIBUTE_PURE;
64extern int
65 u32_strwidth (const uint32_t *s, const char *encoding)
66 _UC_ATTRIBUTE_PURE;
67
68
69#ifdef __cplusplus
70}
71#endif
72
73#endif /* _UNIWIDTH_H */
diff --git a/gl/uniwidth.in.h b/gl/uniwidth.in.h
new file mode 100644
index 00000000..49c7ce05
--- /dev/null
+++ b/gl/uniwidth.in.h
@@ -0,0 +1,72 @@
1/* Display width functions.
2 Copyright (C) 2001-2002, 2005, 2007, 2009-2025 Free Software Foundation,
3 Inc.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#ifndef _UNIWIDTH_H
19#define _UNIWIDTH_H
20
21#include "unitypes.h"
22
23/* Get size_t. */
24#include <stddef.h>
25
26/* Get locale_charset() declaration. */
27#include "localcharset.h"
28
29#ifdef __cplusplus
30extern "C" {
31#endif
32
33
34/* Display width. */
35
36/* These functions are locale dependent. The encoding argument identifies
37 the encoding (e.g. "ISO-8859-2" for Polish). */
38
39/* Determine number of column positions required for UC. */
40extern int
41 uc_width (ucs4_t uc, const char *encoding)
42 _UC_ATTRIBUTE_PURE;
43
44/* Determine number of column positions required for first N units
45 (or fewer if S ends before this) in S. */
46extern int
47 u8_width (const uint8_t *s, size_t n, const char *encoding)
48 _UC_ATTRIBUTE_PURE;
49extern int
50 u16_width (const uint16_t *s, size_t n, const char *encoding)
51 _UC_ATTRIBUTE_PURE;
52extern int
53 u32_width (const uint32_t *s, size_t n, const char *encoding)
54 _UC_ATTRIBUTE_PURE;
55
56/* Determine number of column positions required for S. */
57extern int
58 u8_strwidth (const uint8_t *s, const char *encoding)
59 _UC_ATTRIBUTE_PURE;
60extern int
61 u16_strwidth (const uint16_t *s, const char *encoding)
62 _UC_ATTRIBUTE_PURE;
63extern int
64 u32_strwidth (const uint32_t *s, const char *encoding)
65 _UC_ATTRIBUTE_PURE;
66
67
68#ifdef __cplusplus
69}
70#endif
71
72#endif /* _UNIWIDTH_H */
diff --git a/gl/uniwidth/.deps/.dirstamp b/gl/uniwidth/.deps/.dirstamp
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gl/uniwidth/.deps/.dirstamp
diff --git a/gl/uniwidth/.deps/libgnu_a-width.Po b/gl/uniwidth/.deps/libgnu_a-width.Po
new file mode 100644
index 00000000..f3f0e3fd
--- /dev/null
+++ b/gl/uniwidth/.deps/libgnu_a-width.Po
@@ -0,0 +1,60 @@
1uniwidth/libgnu_a-width.o: uniwidth/width.c /usr/include/stdc-predef.h \
2 ../config.h uniwidth.h unitypes.h \
3 /usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h /usr/include/stdint.h \
4 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
5 /usr/include/features.h /usr/include/features-time64.h \
6 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
7 /usr/include/x86_64-linux-gnu/bits/timesize.h \
8 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
9 /usr/include/x86_64-linux-gnu/bits/long-double.h \
10 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
11 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
12 /usr/include/x86_64-linux-gnu/bits/types.h \
13 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
14 /usr/include/x86_64-linux-gnu/bits/time64.h \
15 /usr/include/x86_64-linux-gnu/bits/wchar.h \
16 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h \
17 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
18 /usr/include/x86_64-linux-gnu/bits/stdint-least.h stddef.h \
19 /usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h localcharset.h \
20 uniwidth/cjk.h streq.h string.h /usr/include/string.h \
21 /usr/include/x86_64-linux-gnu/bits/types/locale_t.h \
22 /usr/include/x86_64-linux-gnu/bits/types/__locale_t.h strings.h \
23 /usr/include/strings.h uniwidth/width0.h uniwidth/width2.h \
24 unictype/bitmap.h
25/usr/include/stdc-predef.h:
26../config.h:
27uniwidth.h:
28unitypes.h:
29/usr/lib/gcc/x86_64-linux-gnu/15/include/stdint.h:
30/usr/include/stdint.h:
31/usr/include/x86_64-linux-gnu/bits/libc-header-start.h:
32/usr/include/features.h:
33/usr/include/features-time64.h:
34/usr/include/x86_64-linux-gnu/bits/wordsize.h:
35/usr/include/x86_64-linux-gnu/bits/timesize.h:
36/usr/include/x86_64-linux-gnu/sys/cdefs.h:
37/usr/include/x86_64-linux-gnu/bits/long-double.h:
38/usr/include/x86_64-linux-gnu/gnu/stubs.h:
39/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
40/usr/include/x86_64-linux-gnu/bits/types.h:
41/usr/include/x86_64-linux-gnu/bits/typesizes.h:
42/usr/include/x86_64-linux-gnu/bits/time64.h:
43/usr/include/x86_64-linux-gnu/bits/wchar.h:
44/usr/include/x86_64-linux-gnu/bits/stdint-intn.h:
45/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h:
46/usr/include/x86_64-linux-gnu/bits/stdint-least.h:
47stddef.h:
48/usr/lib/gcc/x86_64-linux-gnu/15/include/stddef.h:
49localcharset.h:
50uniwidth/cjk.h:
51streq.h:
52string.h:
53/usr/include/string.h:
54/usr/include/x86_64-linux-gnu/bits/types/locale_t.h:
55/usr/include/x86_64-linux-gnu/bits/types/__locale_t.h:
56strings.h:
57/usr/include/strings.h:
58uniwidth/width0.h:
59uniwidth/width2.h:
60unictype/bitmap.h:
diff --git a/gl/uniwidth/.dirstamp b/gl/uniwidth/.dirstamp
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gl/uniwidth/.dirstamp
diff --git a/gl/uniwidth/cjk.h b/gl/uniwidth/cjk.h
new file mode 100644
index 00000000..af41f637
--- /dev/null
+++ b/gl/uniwidth/cjk.h
@@ -0,0 +1,37 @@
1/* Test for CJK encoding.
2 Copyright (C) 2001-2002, 2005-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2002.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include "streq.h"
19
20static int
21is_cjk_encoding (const char *encoding)
22{
23 if (0
24 /* Legacy Japanese encodings */
25 || STREQ_OPT (encoding, "EUC-JP", 'E', 'U', 'C', '-', 'J', 'P', 0, 0, 0)
26 /* Legacy Chinese encodings */
27 || STREQ_OPT (encoding, "GB2312", 'G', 'B', '2', '3', '1', '2', 0, 0, 0)
28 || STREQ_OPT (encoding, "GBK", 'G', 'B', 'K', 0, 0, 0, 0, 0, 0)
29 || STREQ_OPT (encoding, "EUC-TW", 'E', 'U', 'C', '-', 'T', 'W', 0, 0, 0)
30 || STREQ_OPT (encoding, "BIG5", 'B', 'I', 'G', '5', 0, 0, 0, 0, 0)
31 /* Legacy Korean encodings */
32 || STREQ_OPT (encoding, "EUC-KR", 'E', 'U', 'C', '-', 'K', 'R', 0, 0, 0)
33 || STREQ_OPT (encoding, "CP949", 'C', 'P', '9', '4', '9', 0, 0, 0, 0)
34 || STREQ_OPT (encoding, "JOHAB", 'J', 'O', 'H', 'A', 'B', 0, 0, 0, 0))
35 return 1;
36 return 0;
37}
diff --git a/gl/uniwidth/width.c b/gl/uniwidth/width.c
new file mode 100644
index 00000000..c99a74cb
--- /dev/null
+++ b/gl/uniwidth/width.c
@@ -0,0 +1,95 @@
1/* Determine display width of Unicode character.
2 Copyright (C) 2001-2002, 2006-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2002.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include "uniwidth.h"
22
23#include "cjk.h"
24
25/* The non-spacing attribute table consists of:
26 * Non-spacing characters; generated from PropList.txt or
27 "grep '^[^;]*;[^;]*;[^;]*;[^;]*;NSM;' UnicodeData.txt"
28 * Format control characters; generated from
29 "grep '^[^;]*;[^;]*;Cf;' UnicodeData.txt"
30 * Zero width characters; generated from
31 "grep '^[^;]*;ZERO WIDTH ' UnicodeData.txt"
32 * Hangul Jamo characters that have conjoining behaviour:
33 - jungseong = syllable-middle vowels
34 - jongseong = syllable-final consonants
35 Rationale:
36 1) These characters act like combining characters. They have no
37 equivalent in legacy character sets. Therefore the EastAsianWidth.txt
38 file does not really matter for them; UAX #11 East Asian Width
39 <https://www.unicode.org/reports/tr11/> makes it clear that it focus
40 is on compatibility with traditional Japanese layout.
41 By contrast, the same glyphs without conjoining behaviour are available
42 in the U+3130..U+318F block, and these characters are mapped to legacy
43 character sets, and traditional Japanese layout matters for them.
44 2) glibc does the same thing, see
45 <https://sourceware.org/bugzilla/show_bug.cgi?id=21750>
46 <https://sourceware.org/bugzilla/show_bug.cgi?id=26120>
47 */
48#include "uniwidth/width0.h"
49
50#include "uniwidth/width2.h"
51#include "unictype/bitmap.h"
52
53#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
54
55
56/* Determine number of column positions required for UC. */
57int
58uc_width (ucs4_t uc, const char *encoding)
59{
60 /* Test for non-spacing or control character. */
61 if ((uc >> 9) < SIZEOF (nonspacing_table_ind))
62 {
63 int ind = nonspacing_table_ind[uc >> 9];
64 if (ind >= 0)
65 if ((nonspacing_table_data[64*ind + ((uc >> 3) & 63)] >> (uc & 7)) & 1)
66 {
67 if (uc > 0 && uc < 0xa0)
68 return -1;
69 else
70 return 0;
71 }
72 }
73 else if ((uc >> 9) == (0xe0000 >> 9))
74 {
75 if (uc >= 0xe0100)
76 {
77 if (uc <= 0xe01ef)
78 return 0;
79 }
80 else
81 {
82 if (uc >= 0xe0020 ? uc <= 0xe007f : uc == 0xe0001)
83 return 0;
84 }
85 }
86 /* Test for double-width character. */
87 if (bitmap_lookup (&u_width2, uc))
88 return 2;
89 /* In ancient CJK encodings, Cyrillic and most other characters are
90 double-width as well. */
91 if (uc >= 0x00A1 && uc < 0xFF61 && uc != 0x20A9
92 && is_cjk_encoding (encoding))
93 return 2;
94 return 1;
95}
diff --git a/gl/uniwidth/width0.h b/gl/uniwidth/width0.h
new file mode 100644
index 00000000..2edbe240
--- /dev/null
+++ b/gl/uniwidth/width0.h
@@ -0,0 +1,495 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* Table of non-spacing or control characters. */
3/* Generated automatically by gen-uni-tables.c for Unicode 16.0.0. */
4
5/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
6
7 This file is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 This file is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19
20static const unsigned char nonspacing_table_data[49*64] = {
21 /* 0x0000-0x01ff */
22 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0x0000-0x003f */
23 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* 0x0040-0x007f */
24 0xff, 0xff, 0xff, 0xff, 0x00, 0x20, 0x00, 0x00, /* 0x0080-0x00bf */
25 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00c0-0x00ff */
26 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0100-0x013f */
27 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0140-0x017f */
28 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0180-0x01bf */
29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01c0-0x01ff */
30 /* 0x0200-0x03ff */
31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0200-0x023f */
32 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0240-0x027f */
33 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0280-0x02bf */
34 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02c0-0x02ff */
35 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x0300-0x033f */
36 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, /* 0x0340-0x037f */
37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0380-0x03bf */
38 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x03c0-0x03ff */
39 /* 0x0400-0x05ff */
40 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0400-0x043f */
41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0440-0x047f */
42 0xf8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0480-0x04bf */
43 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04c0-0x04ff */
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0500-0x053f */
45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0540-0x057f */
46 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xbf, /* 0x0580-0x05bf */
47 0xb6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x05c0-0x05ff */
48 /* 0x0600-0x07ff */
49 0x00, 0x00, 0xff, 0x17, 0x00, 0x00, 0x00, 0x00, /* 0x0600-0x063f */
50 0x00, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, /* 0x0640-0x067f */
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0680-0x06bf */
52 0x00, 0x00, 0xc0, 0x9f, 0x9f, 0x3d, 0x00, 0x00, /* 0x06c0-0x06ff */
53 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, /* 0x0700-0x073f */
54 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0740-0x077f */
55 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, /* 0x0780-0x07bf */
56 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x20, /* 0x07c0-0x07ff */
57 /* 0x0800-0x09ff */
58 0x00, 0x00, 0xc0, 0xfb, 0xef, 0x3e, 0x00, 0x00, /* 0x0800-0x083f */
59 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, /* 0x0840-0x087f */
60 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0x0880-0x08bf */
61 0x00, 0xfc, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, /* 0x08c0-0x08ff */
62 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, /* 0x0900-0x093f */
63 0xfe, 0x21, 0xfe, 0x00, 0x0c, 0x00, 0x00, 0x00, /* 0x0940-0x097f */
64 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, /* 0x0980-0x09bf */
65 0x1e, 0x20, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x40, /* 0x09c0-0x09ff */
66 /* 0x0a00-0x0bff */
67 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, /* 0x0a00-0x0a3f */
68 0x86, 0x39, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, /* 0x0a40-0x0a7f */
69 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, /* 0x0a80-0x0abf */
70 0xbe, 0x21, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xfc, /* 0x0ac0-0x0aff */
71 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, /* 0x0b00-0x0b3f */
72 0x1e, 0x20, 0x60, 0x00, 0x0c, 0x00, 0x00, 0x00, /* 0x0b40-0x0b7f */
73 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0b80-0x0bbf */
74 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0bc0-0x0bff */
75 /* 0x0c00-0x0dff */
76 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, /* 0x0c00-0x0c3f */
77 0xc1, 0x3d, 0x60, 0x00, 0x0c, 0x00, 0x00, 0x00, /* 0x0c40-0x0c7f */
78 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, /* 0x0c80-0x0cbf */
79 0x00, 0x30, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, /* 0x0cc0-0x0cff */
80 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, /* 0x0d00-0x0d3f */
81 0x1e, 0x20, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, /* 0x0d40-0x0d7f */
82 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0d80-0x0dbf */
83 0x00, 0x04, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0dc0-0x0dff */
84 /* 0x0e00-0x0fff */
85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x07, /* 0x0e00-0x0e3f */
86 0x80, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0e40-0x0e7f */
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x1f, /* 0x0e80-0x0ebf */
88 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0ec0-0x0eff */
89 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xa0, 0x02, /* 0x0f00-0x0f3f */
90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, /* 0x0f40-0x0f7f */
91 0xdf, 0xe0, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x1f, /* 0x0f80-0x0fbf */
92 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0fc0-0x0fff */
93 /* 0x1000-0x11ff */
94 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xfd, 0x66, /* 0x1000-0x103f */
95 0x00, 0x00, 0x00, 0xc3, 0x01, 0x00, 0x1e, 0x00, /* 0x1040-0x107f */
96 0x64, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, /* 0x1080-0x10bf */
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10c0-0x10ff */
98 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1100-0x113f */
99 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, /* 0x1140-0x117f */
100 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x1180-0x11bf */
101 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x11c0-0x11ff */
102 /* 0x1200-0x13ff */
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1200-0x123f */
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1240-0x127f */
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1280-0x12bf */
106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x12c0-0x12ff */
107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1300-0x133f */
108 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, /* 0x1340-0x137f */
109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1380-0x13bf */
110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x13c0-0x13ff */
111 /* 0x1600-0x17ff */
112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1600-0x163f */
113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1640-0x167f */
114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1680-0x16bf */
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16c0-0x16ff */
116 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, /* 0x1700-0x173f */
117 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, /* 0x1740-0x177f */
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x3f, /* 0x1780-0x17bf */
119 0x40, 0xfe, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x00, /* 0x17c0-0x17ff */
120 /* 0x1800-0x19ff */
121 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1800-0x183f */
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1840-0x187f */
123 0x60, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, /* 0x1880-0x18bf */
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18c0-0x18ff */
125 0x00, 0x00, 0x00, 0x00, 0x87, 0x01, 0x04, 0x0e, /* 0x1900-0x193f */
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1940-0x197f */
127 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1980-0x19bf */
128 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x19c0-0x19ff */
129 /* 0x1a00-0x1bff */
130 0x00, 0x00, 0x80, 0x09, 0x00, 0x00, 0x00, 0x00, /* 0x1a00-0x1a3f */
131 0x00, 0x00, 0x40, 0x7f, 0xe5, 0x1f, 0xf8, 0x9f, /* 0x1a40-0x1a7f */
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* 0x1a80-0x1abf */
133 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1ac0-0x1aff */
134 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x17, /* 0x1b00-0x1b3f */
135 0x04, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x00, /* 0x1b40-0x1b7f */
136 0x03, 0x00, 0x00, 0x00, 0x3c, 0x3b, 0x00, 0x00, /* 0x1b80-0x1bbf */
137 0x00, 0x00, 0x00, 0x00, 0x40, 0xa3, 0x03, 0x00, /* 0x1bc0-0x1bff */
138 /* 0x1c00-0x1dff */
139 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xcf, 0x00, /* 0x1c00-0x1c3f */
140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1c40-0x1c7f */
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1c80-0x1cbf */
142 0x00, 0x00, 0xf7, 0xff, 0xfd, 0x21, 0x10, 0x03, /* 0x1cc0-0x1cff */
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d00-0x1d3f */
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d40-0x1d7f */
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d80-0x1dbf */
146 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x1dc0-0x1dff */
147 /* 0x2000-0x21ff */
148 0x00, 0xf8, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, /* 0x2000-0x203f */
149 0x00, 0x00, 0x00, 0x00, 0xdf, 0xff, 0x00, 0x00, /* 0x2040-0x207f */
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2080-0x20bf */
151 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, /* 0x20c0-0x20ff */
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2100-0x213f */
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2140-0x217f */
154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2180-0x21bf */
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x21c0-0x21ff */
156 /* 0x2c00-0x2dff */
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2c00-0x2c3f */
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2c40-0x2c7f */
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2c80-0x2cbf */
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, /* 0x2cc0-0x2cff */
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2d00-0x2d3f */
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* 0x2d40-0x2d7f */
163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2d80-0x2dbf */
164 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, /* 0x2dc0-0x2dff */
165 /* 0x3000-0x31ff */
166 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, /* 0x3000-0x303f */
167 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3040-0x307f */
168 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, /* 0x3080-0x30bf */
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30c0-0x30ff */
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3100-0x313f */
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3140-0x317f */
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3180-0x31bf */
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x31c0-0x31ff */
174 /* 0xa600-0xa7ff */
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa600-0xa63f */
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf7, 0x3f, /* 0xa640-0xa67f */
177 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, /* 0xa680-0xa6bf */
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, /* 0xa6c0-0xa6ff */
179 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa700-0xa73f */
180 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa740-0xa77f */
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa780-0xa7bf */
182 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa7c0-0xa7ff */
183 /* 0xa800-0xa9ff */
184 0x44, 0x08, 0x00, 0x00, 0x60, 0x10, 0x00, 0x00, /* 0xa800-0xa83f */
185 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa840-0xa87f */
186 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa880-0xa8bf */
187 0x30, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x80, /* 0xa8c0-0xa8ff */
188 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, /* 0xa900-0xa93f */
189 0x80, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa940-0xa97f */
190 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x33, /* 0xa980-0xa9bf */
191 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, /* 0xa9c0-0xa9ff */
192 /* 0xaa00-0xabff */
193 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x66, 0x00, /* 0xaa00-0xaa3f */
194 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, /* 0xaa40-0xaa7f */
195 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0xc1, /* 0xaa80-0xaabf */
196 0x02, 0x00, 0x00, 0x00, 0x00, 0x30, 0x40, 0x00, /* 0xaac0-0xaaff */
197 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xab00-0xab3f */
198 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xab40-0xab7f */
199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xab80-0xabbf */
200 0x00, 0x00, 0x00, 0x00, 0x20, 0x21, 0x00, 0x00, /* 0xabc0-0xabff */
201 /* 0xd600-0xd7ff */
202 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd600-0xd63f */
203 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd640-0xd67f */
204 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd680-0xd6bf */
205 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd6c0-0xd6ff */
206 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd700-0xd73f */
207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd740-0xd77f */
208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* 0xd780-0xd7bf */
209 0x7f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, /* 0xd7c0-0xd7ff */
210 /* 0xfa00-0xfbff */
211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xfa00-0xfa3f */
212 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xfa40-0xfa7f */
213 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xfa80-0xfabf */
214 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xfac0-0xfaff */
215 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, /* 0xfb00-0xfb3f */
216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xfb40-0xfb7f */
217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xfb80-0xfbbf */
218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xfbc0-0xfbff */
219 /* 0xfe00-0xffff */
220 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, /* 0xfe00-0xfe3f */
221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xfe40-0xfe7f */
222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xfe80-0xfebf */
223 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* 0xfec0-0xfeff */
224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xff00-0xff3f */
225 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xff40-0xff7f */
226 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xff80-0xffbf */
227 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, /* 0xffc0-0xffff */
228 /* 0x10000-0x101ff */
229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10000-0x1003f */
230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10040-0x1007f */
231 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10080-0x100bf */
232 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x100c0-0x100ff */
233 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10100-0x1013f */
234 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10140-0x1017f */
235 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10180-0x101bf */
236 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, /* 0x101c0-0x101ff */
237 /* 0x10200-0x103ff */
238 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10200-0x1023f */
239 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10240-0x1027f */
240 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10280-0x102bf */
241 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* 0x102c0-0x102ff */
242 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10300-0x1033f */
243 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, /* 0x10340-0x1037f */
244 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10380-0x103bf */
245 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x103c0-0x103ff */
246 /* 0x10a00-0x10bff */
247 0x6e, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, /* 0x10a00-0x10a3f */
248 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10a40-0x10a7f */
249 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10a80-0x10abf */
250 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, /* 0x10ac0-0x10aff */
251 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10b00-0x10b3f */
252 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10b40-0x10b7f */
253 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10b80-0x10bbf */
254 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10bc0-0x10bff */
255 /* 0x10c00-0x10dff */
256 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10c00-0x10c3f */
257 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10c40-0x10c7f */
258 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10c80-0x10cbf */
259 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10cc0-0x10cff */
260 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, /* 0x10d00-0x10d3f */
261 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, /* 0x10d40-0x10d7f */
262 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10d80-0x10dbf */
263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10dc0-0x10dff */
264 /* 0x10e00-0x10fff */
265 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10e00-0x10e3f */
266 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10e40-0x10e7f */
267 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, /* 0x10e80-0x10ebf */
268 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, /* 0x10ec0-0x10eff */
269 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10f00-0x10f3f */
270 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10f40-0x10f7f */
271 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10f80-0x10fbf */
272 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10fc0-0x10fff */
273 /* 0x11000-0x111ff */
274 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* 0x11000-0x1103f */
275 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x80, /* 0x11040-0x1107f */
276 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x06, /* 0x11080-0x110bf */
277 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x110c0-0x110ff */
278 0x07, 0x00, 0x00, 0x00, 0x80, 0xef, 0x1f, 0x00, /* 0x11100-0x1113f */
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, /* 0x11140-0x1117f */
280 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f, /* 0x11180-0x111bf */
281 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x111c0-0x111ff */
282 /* 0x11200-0x113ff */
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xd3, 0x40, /* 0x11200-0x1123f */
284 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11240-0x1127f */
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11280-0x112bf */
286 0x00, 0x00, 0x00, 0x80, 0xf8, 0x07, 0x00, 0x00, /* 0x112c0-0x112ff */
287 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, /* 0x11300-0x1133f */
288 0x01, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x1f, 0x00, /* 0x11340-0x1137f */
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, /* 0x11380-0x113bf */
290 0x01, 0x40, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, /* 0x113c0-0x113ff */
291 /* 0x11400-0x115ff */
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* 0x11400-0x1143f */
293 0x5c, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, /* 0x11440-0x1147f */
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x85, /* 0x11480-0x114bf */
295 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x114c0-0x114ff */
296 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11500-0x1153f */
297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11540-0x1157f */
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xb0, /* 0x11580-0x115bf */
299 0x01, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, /* 0x115c0-0x115ff */
300 /* 0x11600-0x117ff */
301 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa7, /* 0x11600-0x1163f */
302 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11640-0x1167f */
303 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xbf, 0x00, /* 0x11680-0x116bf */
304 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x116c0-0x116ff */
305 0x00, 0x00, 0x00, 0xa0, 0xbc, 0x0f, 0x00, 0x00, /* 0x11700-0x1173f */
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11740-0x1177f */
307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11780-0x117bf */
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x117c0-0x117ff */
309 /* 0x11800-0x119ff */
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x06, /* 0x11800-0x1183f */
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11840-0x1187f */
312 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11880-0x118bf */
313 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x118c0-0x118ff */
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, /* 0x11900-0x1193f */
315 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11940-0x1197f */
316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11980-0x119bf */
317 0x00, 0x00, 0xf0, 0x0c, 0x01, 0x00, 0x00, 0x00, /* 0x119c0-0x119ff */
318 /* 0x11a00-0x11bff */
319 0x7e, 0x06, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x79, /* 0x11a00-0x11a3f */
320 0x80, 0x00, 0x7e, 0x0e, 0x00, 0x00, 0x00, 0x00, /* 0x11a40-0x11a7f */
321 0x00, 0xfc, 0x7f, 0x03, 0x00, 0x00, 0x00, 0x00, /* 0x11a80-0x11abf */
322 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11ac0-0x11aff */
323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11b00-0x11b3f */
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11b40-0x11b7f */
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11b80-0x11bbf */
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11bc0-0x11bff */
327 /* 0x11c00-0x11dff */
328 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x3f, /* 0x11c00-0x11c3f */
329 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11c40-0x11c7f */
330 0x00, 0x00, 0xfc, 0xff, 0xff, 0xfc, 0x6d, 0x00, /* 0x11c80-0x11cbf */
331 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11cc0-0x11cff */
332 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xb4, /* 0x11d00-0x11d3f */
333 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11d40-0x11d7f */
334 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11d80-0x11dbf */
335 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11dc0-0x11dff */
336 /* 0x11e00-0x11fff */
337 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11e00-0x11e3f */
338 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11e40-0x11e7f */
339 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11e80-0x11ebf */
340 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, /* 0x11ec0-0x11eff */
341 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, /* 0x11f00-0x11f3f */
342 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, /* 0x11f40-0x11f7f */
343 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11f80-0x11fbf */
344 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x11fc0-0x11fff */
345 /* 0x13400-0x135ff */
346 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* 0x13400-0x1343f */
347 0x81, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x13440-0x1347f */
348 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x13480-0x134bf */
349 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x134c0-0x134ff */
350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x13500-0x1353f */
351 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x13540-0x1357f */
352 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x13580-0x135bf */
353 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x135c0-0x135ff */
354 /* 0x16000-0x161ff */
355 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16000-0x1603f */
356 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16040-0x1607f */
357 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16080-0x160bf */
358 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x160c0-0x160ff */
359 0x00, 0x00, 0x00, 0xc0, 0xff, 0xe3, 0x00, 0x00, /* 0x16100-0x1613f */
360 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16140-0x1617f */
361 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16180-0x161bf */
362 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x161c0-0x161ff */
363 /* 0x16a00-0x16bff */
364 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16a00-0x16a3f */
365 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16a40-0x16a7f */
366 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16a80-0x16abf */
367 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, /* 0x16ac0-0x16aff */
368 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, /* 0x16b00-0x16b3f */
369 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16b40-0x16b7f */
370 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16b80-0x16bbf */
371 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16bc0-0x16bff */
372 /* 0x16e00-0x16fff */
373 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16e00-0x16e3f */
374 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16e40-0x16e7f */
375 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16e80-0x16ebf */
376 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16ec0-0x16eff */
377 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16f00-0x16f3f */
378 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16f40-0x16f7f */
379 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x16f80-0x16fbf */
380 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, /* 0x16fc0-0x16fff */
381 /* 0x1bc00-0x1bdff */
382 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1bc00-0x1bc3f */
383 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1bc40-0x1bc7f */
384 0x00, 0x00, 0x00, 0x60, 0x0f, 0x00, 0x00, 0x00, /* 0x1bc80-0x1bcbf */
385 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1bcc0-0x1bcff */
386 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1bd00-0x1bd3f */
387 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1bd40-0x1bd7f */
388 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1bd80-0x1bdbf */
389 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1bdc0-0x1bdff */
390 /* 0x1ce00-0x1cfff */
391 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1ce00-0x1ce3f */
392 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1ce40-0x1ce7f */
393 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1ce80-0x1cebf */
394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1cec0-0x1ceff */
395 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, /* 0x1cf00-0x1cf3f */
396 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1cf40-0x1cf7f */
397 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1cf80-0x1cfbf */
398 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1cfc0-0x1cfff */
399 /* 0x1d000-0x1d1ff */
400 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d000-0x1d03f */
401 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d040-0x1d07f */
402 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d080-0x1d0bf */
403 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d0c0-0x1d0ff */
404 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d100-0x1d13f */
405 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0xf8, 0xff, /* 0x1d140-0x1d17f */
406 0xe7, 0x0f, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, /* 0x1d180-0x1d1bf */
407 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d1c0-0x1d1ff */
408 /* 0x1d200-0x1d3ff */
409 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d200-0x1d23f */
410 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d240-0x1d27f */
411 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d280-0x1d2bf */
412 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d2c0-0x1d2ff */
413 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d300-0x1d33f */
414 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d340-0x1d37f */
415 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d380-0x1d3bf */
416 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1d3c0-0x1d3ff */
417 /* 0x1da00-0x1dbff */
418 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xf8, /* 0x1da00-0x1da3f */
419 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x20, 0x00, /* 0x1da40-0x1da7f */
420 0x10, 0x00, 0x00, 0xf8, 0xfe, 0xff, 0x00, 0x00, /* 0x1da80-0x1dabf */
421 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1dac0-0x1daff */
422 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1db00-0x1db3f */
423 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1db40-0x1db7f */
424 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1db80-0x1dbbf */
425 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1dbc0-0x1dbff */
426 /* 0x1e000-0x1e1ff */
427 0x7f, 0xff, 0xff, 0xf9, 0xdb, 0x07, 0x00, 0x00, /* 0x1e000-0x1e03f */
428 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e040-0x1e07f */
429 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e080-0x1e0bf */
430 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e0c0-0x1e0ff */
431 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, /* 0x1e100-0x1e13f */
432 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e140-0x1e17f */
433 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e180-0x1e1bf */
434 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e1c0-0x1e1ff */
435 /* 0x1e200-0x1e3ff */
436 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e200-0x1e23f */
437 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e240-0x1e27f */
438 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, /* 0x1e280-0x1e2bf */
439 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, /* 0x1e2c0-0x1e2ff */
440 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e300-0x1e33f */
441 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e340-0x1e37f */
442 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e380-0x1e3bf */
443 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e3c0-0x1e3ff */
444 /* 0x1e400-0x1e5ff */
445 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e400-0x1e43f */
446 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e440-0x1e47f */
447 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e480-0x1e4bf */
448 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, /* 0x1e4c0-0x1e4ff */
449 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e500-0x1e53f */
450 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e540-0x1e57f */
451 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e580-0x1e5bf */
452 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0x1e5c0-0x1e5ff */
453 /* 0x1e800-0x1e9ff */
454 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e800-0x1e83f */
455 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e840-0x1e87f */
456 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e880-0x1e8bf */
457 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e8c0-0x1e8ff */
458 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e900-0x1e93f */
459 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e940-0x1e97f */
460 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1e980-0x1e9bf */
461 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0x1e9c0-0x1e9ff */
462};
463static const signed char nonspacing_table_ind[248] = {
464 0, 1, 2, 3, 4, 5, 6, 7, /* 0x0000-0x0fff */
465 8, 9, -1, 10, 11, 12, 13, -1, /* 0x1000-0x1fff */
466 14, -1, -1, -1, -1, -1, 15, -1, /* 0x2000-0x2fff */
467 16, -1, -1, -1, -1, -1, -1, -1, /* 0x3000-0x3fff */
468 -1, -1, -1, -1, -1, -1, -1, -1, /* 0x4000-0x4fff */
469 -1, -1, -1, -1, -1, -1, -1, -1, /* 0x5000-0x5fff */
470 -1, -1, -1, -1, -1, -1, -1, -1, /* 0x6000-0x6fff */
471 -1, -1, -1, -1, -1, -1, -1, -1, /* 0x7000-0x7fff */
472 -1, -1, -1, -1, -1, -1, -1, -1, /* 0x8000-0x8fff */
473 -1, -1, -1, -1, -1, -1, -1, -1, /* 0x9000-0x9fff */
474 -1, -1, -1, 17, 18, 19, -1, -1, /* 0xa000-0xafff */
475 -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb000-0xbfff */
476 -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc000-0xcfff */
477 -1, -1, -1, 20, -1, -1, -1, -1, /* 0xd000-0xdfff */
478 -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe000-0xefff */
479 -1, -1, -1, -1, -1, 21, -1, 22, /* 0xf000-0xffff */
480 23, 24, -1, -1, -1, 25, 26, 27, /* 0x10000-0x10fff */
481 28, 29, 30, 31, 32, 33, 34, 35, /* 0x11000-0x11fff */
482 -1, -1, -1, -1, -1, -1, -1, -1, /* 0x12000-0x12fff */
483 -1, -1, 36, -1, -1, -1, -1, -1, /* 0x13000-0x13fff */
484 -1, -1, -1, -1, -1, -1, -1, -1, /* 0x14000-0x14fff */
485 -1, -1, -1, -1, -1, -1, -1, -1, /* 0x15000-0x15fff */
486 37, -1, -1, -1, -1, 38, -1, 39, /* 0x16000-0x16fff */
487 -1, -1, -1, -1, -1, -1, -1, -1, /* 0x17000-0x17fff */
488 -1, -1, -1, -1, -1, -1, -1, -1, /* 0x18000-0x18fff */
489 -1, -1, -1, -1, -1, -1, -1, -1, /* 0x19000-0x19fff */
490 -1, -1, -1, -1, -1, -1, -1, -1, /* 0x1a000-0x1afff */
491 -1, -1, -1, -1, -1, -1, 40, -1, /* 0x1b000-0x1bfff */
492 -1, -1, -1, -1, -1, -1, -1, 41, /* 0x1c000-0x1cfff */
493 42, 43, -1, -1, -1, 44, -1, -1, /* 0x1d000-0x1dfff */
494 45, 46, 47, -1, 48, -1, -1, -1 /* 0x1e000-0x1efff */
495};
diff --git a/gl/uniwidth/width2.h b/gl/uniwidth/width2.h
new file mode 100644
index 00000000..f919989b
--- /dev/null
+++ b/gl/uniwidth/width2.h
@@ -0,0 +1,541 @@
1/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2/* Width 2 property of Unicode characters. */
3/* Generated automatically by gen-uni-tables.c for Unicode 16.0.0. */
4
5/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
6
7 This file is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 This file is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19
20#define header_0 16
21#define header_2 9
22#define header_3 127
23#define header_4 15
24static const
25struct
26 {
27 int header[1];
28 int level1[4];
29 short level2[3 << 7];
30 unsigned int level3[28 << 4];
31 }
32u_width2 =
33{
34 { 4 },
35 {
36 5 * sizeof (int) / sizeof (short) + 0,
37 5 * sizeof (int) / sizeof (short) + 128,
38 5 * sizeof (int) / sizeof (short) + 256,
39 5 * sizeof (int) / sizeof (short) + 256
40 },
41 {
42 -1,
43 -1,
44 -1,
45 -1,
46 -1,
47 -1,
48 -1,
49 -1,
50 5 + 384 * sizeof (short) / sizeof (int) + 0,
51 -1,
52 -1,
53 -1,
54 -1,
55 -1,
56 -1,
57 -1,
58 -1,
59 5 + 384 * sizeof (short) / sizeof (int) + 16,
60 5 + 384 * sizeof (short) / sizeof (int) + 32,
61 5 + 384 * sizeof (short) / sizeof (int) + 48,
62 -1,
63 5 + 384 * sizeof (short) / sizeof (int) + 64,
64 -1,
65 5 + 384 * sizeof (short) / sizeof (int) + 80,
66 5 + 384 * sizeof (short) / sizeof (int) + 96,
67 5 + 384 * sizeof (short) / sizeof (int) + 112,
68 5 + 384 * sizeof (short) / sizeof (int) + 128,
69 5 + 384 * sizeof (short) / sizeof (int) + 128,
70 5 + 384 * sizeof (short) / sizeof (int) + 128,
71 5 + 384 * sizeof (short) / sizeof (int) + 128,
72 5 + 384 * sizeof (short) / sizeof (int) + 128,
73 5 + 384 * sizeof (short) / sizeof (int) + 128,
74 5 + 384 * sizeof (short) / sizeof (int) + 128,
75 5 + 384 * sizeof (short) / sizeof (int) + 128,
76 5 + 384 * sizeof (short) / sizeof (int) + 128,
77 5 + 384 * sizeof (short) / sizeof (int) + 128,
78 5 + 384 * sizeof (short) / sizeof (int) + 128,
79 5 + 384 * sizeof (short) / sizeof (int) + 128,
80 5 + 384 * sizeof (short) / sizeof (int) + 144,
81 5 + 384 * sizeof (short) / sizeof (int) + 128,
82 5 + 384 * sizeof (short) / sizeof (int) + 128,
83 5 + 384 * sizeof (short) / sizeof (int) + 128,
84 5 + 384 * sizeof (short) / sizeof (int) + 128,
85 5 + 384 * sizeof (short) / sizeof (int) + 128,
86 5 + 384 * sizeof (short) / sizeof (int) + 128,
87 5 + 384 * sizeof (short) / sizeof (int) + 128,
88 5 + 384 * sizeof (short) / sizeof (int) + 128,
89 5 + 384 * sizeof (short) / sizeof (int) + 128,
90 5 + 384 * sizeof (short) / sizeof (int) + 128,
91 5 + 384 * sizeof (short) / sizeof (int) + 128,
92 5 + 384 * sizeof (short) / sizeof (int) + 128,
93 5 + 384 * sizeof (short) / sizeof (int) + 128,
94 5 + 384 * sizeof (short) / sizeof (int) + 128,
95 5 + 384 * sizeof (short) / sizeof (int) + 128,
96 5 + 384 * sizeof (short) / sizeof (int) + 128,
97 5 + 384 * sizeof (short) / sizeof (int) + 128,
98 5 + 384 * sizeof (short) / sizeof (int) + 128,
99 5 + 384 * sizeof (short) / sizeof (int) + 128,
100 5 + 384 * sizeof (short) / sizeof (int) + 128,
101 5 + 384 * sizeof (short) / sizeof (int) + 128,
102 5 + 384 * sizeof (short) / sizeof (int) + 128,
103 5 + 384 * sizeof (short) / sizeof (int) + 128,
104 5 + 384 * sizeof (short) / sizeof (int) + 128,
105 5 + 384 * sizeof (short) / sizeof (int) + 128,
106 5 + 384 * sizeof (short) / sizeof (int) + 128,
107 5 + 384 * sizeof (short) / sizeof (int) + 128,
108 5 + 384 * sizeof (short) / sizeof (int) + 128,
109 5 + 384 * sizeof (short) / sizeof (int) + 128,
110 5 + 384 * sizeof (short) / sizeof (int) + 128,
111 5 + 384 * sizeof (short) / sizeof (int) + 128,
112 5 + 384 * sizeof (short) / sizeof (int) + 128,
113 5 + 384 * sizeof (short) / sizeof (int) + 128,
114 5 + 384 * sizeof (short) / sizeof (int) + 128,
115 5 + 384 * sizeof (short) / sizeof (int) + 128,
116 5 + 384 * sizeof (short) / sizeof (int) + 128,
117 5 + 384 * sizeof (short) / sizeof (int) + 128,
118 5 + 384 * sizeof (short) / sizeof (int) + 128,
119 5 + 384 * sizeof (short) / sizeof (int) + 128,
120 5 + 384 * sizeof (short) / sizeof (int) + 128,
121 5 + 384 * sizeof (short) / sizeof (int) + 128,
122 5 + 384 * sizeof (short) / sizeof (int) + 128,
123 5 + 384 * sizeof (short) / sizeof (int) + 128,
124 5 + 384 * sizeof (short) / sizeof (int) + 160,
125 -1,
126 5 + 384 * sizeof (short) / sizeof (int) + 176,
127 -1,
128 5 + 384 * sizeof (short) / sizeof (int) + 128,
129 5 + 384 * sizeof (short) / sizeof (int) + 128,
130 5 + 384 * sizeof (short) / sizeof (int) + 128,
131 5 + 384 * sizeof (short) / sizeof (int) + 128,
132 5 + 384 * sizeof (short) / sizeof (int) + 128,
133 5 + 384 * sizeof (short) / sizeof (int) + 128,
134 5 + 384 * sizeof (short) / sizeof (int) + 128,
135 5 + 384 * sizeof (short) / sizeof (int) + 128,
136 5 + 384 * sizeof (short) / sizeof (int) + 128,
137 5 + 384 * sizeof (short) / sizeof (int) + 128,
138 5 + 384 * sizeof (short) / sizeof (int) + 128,
139 5 + 384 * sizeof (short) / sizeof (int) + 128,
140 5 + 384 * sizeof (short) / sizeof (int) + 128,
141 5 + 384 * sizeof (short) / sizeof (int) + 128,
142 5 + 384 * sizeof (short) / sizeof (int) + 128,
143 5 + 384 * sizeof (short) / sizeof (int) + 128,
144 5 + 384 * sizeof (short) / sizeof (int) + 128,
145 5 + 384 * sizeof (short) / sizeof (int) + 128,
146 5 + 384 * sizeof (short) / sizeof (int) + 128,
147 5 + 384 * sizeof (short) / sizeof (int) + 128,
148 5 + 384 * sizeof (short) / sizeof (int) + 128,
149 5 + 384 * sizeof (short) / sizeof (int) + 192,
150 -1,
151 -1,
152 -1,
153 -1,
154 -1,
155 -1,
156 -1,
157 -1,
158 -1,
159 -1,
160 -1,
161 -1,
162 -1,
163 -1,
164 -1,
165 -1,
166 5 + 384 * sizeof (short) / sizeof (int) + 208,
167 5 + 384 * sizeof (short) / sizeof (int) + 224,
168 -1,
169 5 + 384 * sizeof (short) / sizeof (int) + 240,
170 -1,
171 -1,
172 -1,
173 -1,
174 -1,
175 -1,
176 -1,
177 -1,
178 -1,
179 -1,
180 -1,
181 -1,
182 -1,
183 -1,
184 -1,
185 -1,
186 -1,
187 -1,
188 -1,
189 -1,
190 -1,
191 -1,
192 -1,
193 -1,
194 -1,
195 -1,
196 -1,
197 -1,
198 -1,
199 -1,
200 -1,
201 -1,
202 -1,
203 -1,
204 -1,
205 -1,
206 -1,
207 -1,
208 -1,
209 -1,
210 -1,
211 -1,
212 -1,
213 -1,
214 -1,
215 -1,
216 -1,
217 -1,
218 -1,
219 -1,
220 -1,
221 -1,
222 -1,
223 -1,
224 -1,
225 5 + 384 * sizeof (short) / sizeof (int) + 256,
226 5 + 384 * sizeof (short) / sizeof (int) + 128,
227 5 + 384 * sizeof (short) / sizeof (int) + 128,
228 5 + 384 * sizeof (short) / sizeof (int) + 128,
229 5 + 384 * sizeof (short) / sizeof (int) + 128,
230 5 + 384 * sizeof (short) / sizeof (int) + 128,
231 5 + 384 * sizeof (short) / sizeof (int) + 128,
232 5 + 384 * sizeof (short) / sizeof (int) + 128,
233 5 + 384 * sizeof (short) / sizeof (int) + 128,
234 5 + 384 * sizeof (short) / sizeof (int) + 128,
235 5 + 384 * sizeof (short) / sizeof (int) + 128,
236 5 + 384 * sizeof (short) / sizeof (int) + 128,
237 5 + 384 * sizeof (short) / sizeof (int) + 272,
238 5 + 384 * sizeof (short) / sizeof (int) + 128,
239 5 + 384 * sizeof (short) / sizeof (int) + 128,
240 5 + 384 * sizeof (short) / sizeof (int) + 288,
241 -1,
242 -1,
243 -1,
244 -1,
245 -1,
246 -1,
247 -1,
248 -1,
249 -1,
250 -1,
251 -1,
252 -1,
253 -1,
254 -1,
255 -1,
256 -1,
257 5 + 384 * sizeof (short) / sizeof (int) + 304,
258 5 + 384 * sizeof (short) / sizeof (int) + 320,
259 5 + 384 * sizeof (short) / sizeof (int) + 336,
260 -1,
261 -1,
262 -1,
263 -1,
264 -1,
265 -1,
266 -1,
267 -1,
268 -1,
269 -1,
270 -1,
271 -1,
272 -1,
273 -1,
274 -1,
275 -1,
276 -1,
277 -1,
278 -1,
279 -1,
280 -1,
281 -1,
282 -1,
283 -1,
284 -1,
285 -1,
286 -1,
287 -1,
288 -1,
289 -1,
290 5 + 384 * sizeof (short) / sizeof (int) + 352,
291 5 + 384 * sizeof (short) / sizeof (int) + 368,
292 5 + 384 * sizeof (short) / sizeof (int) + 384,
293 5 + 384 * sizeof (short) / sizeof (int) + 400,
294 5 + 384 * sizeof (short) / sizeof (int) + 416,
295 5 + 384 * sizeof (short) / sizeof (int) + 432,
296 -1,
297 -1,
298 5 + 384 * sizeof (short) / sizeof (int) + 128,
299 5 + 384 * sizeof (short) / sizeof (int) + 128,
300 5 + 384 * sizeof (short) / sizeof (int) + 128,
301 5 + 384 * sizeof (short) / sizeof (int) + 128,
302 5 + 384 * sizeof (short) / sizeof (int) + 128,
303 5 + 384 * sizeof (short) / sizeof (int) + 128,
304 5 + 384 * sizeof (short) / sizeof (int) + 128,
305 5 + 384 * sizeof (short) / sizeof (int) + 128,
306 5 + 384 * sizeof (short) / sizeof (int) + 128,
307 5 + 384 * sizeof (short) / sizeof (int) + 128,
308 5 + 384 * sizeof (short) / sizeof (int) + 128,
309 5 + 384 * sizeof (short) / sizeof (int) + 128,
310 5 + 384 * sizeof (short) / sizeof (int) + 128,
311 5 + 384 * sizeof (short) / sizeof (int) + 128,
312 5 + 384 * sizeof (short) / sizeof (int) + 128,
313 5 + 384 * sizeof (short) / sizeof (int) + 128,
314 5 + 384 * sizeof (short) / sizeof (int) + 128,
315 5 + 384 * sizeof (short) / sizeof (int) + 128,
316 5 + 384 * sizeof (short) / sizeof (int) + 128,
317 5 + 384 * sizeof (short) / sizeof (int) + 128,
318 5 + 384 * sizeof (short) / sizeof (int) + 128,
319 5 + 384 * sizeof (short) / sizeof (int) + 128,
320 5 + 384 * sizeof (short) / sizeof (int) + 128,
321 5 + 384 * sizeof (short) / sizeof (int) + 128,
322 5 + 384 * sizeof (short) / sizeof (int) + 128,
323 5 + 384 * sizeof (short) / sizeof (int) + 128,
324 5 + 384 * sizeof (short) / sizeof (int) + 128,
325 5 + 384 * sizeof (short) / sizeof (int) + 128,
326 5 + 384 * sizeof (short) / sizeof (int) + 128,
327 5 + 384 * sizeof (short) / sizeof (int) + 128,
328 5 + 384 * sizeof (short) / sizeof (int) + 128,
329 5 + 384 * sizeof (short) / sizeof (int) + 128,
330 5 + 384 * sizeof (short) / sizeof (int) + 128,
331 5 + 384 * sizeof (short) / sizeof (int) + 128,
332 5 + 384 * sizeof (short) / sizeof (int) + 128,
333 5 + 384 * sizeof (short) / sizeof (int) + 128,
334 5 + 384 * sizeof (short) / sizeof (int) + 128,
335 5 + 384 * sizeof (short) / sizeof (int) + 128,
336 5 + 384 * sizeof (short) / sizeof (int) + 128,
337 5 + 384 * sizeof (short) / sizeof (int) + 128,
338 5 + 384 * sizeof (short) / sizeof (int) + 128,
339 5 + 384 * sizeof (short) / sizeof (int) + 128,
340 5 + 384 * sizeof (short) / sizeof (int) + 128,
341 5 + 384 * sizeof (short) / sizeof (int) + 128,
342 5 + 384 * sizeof (short) / sizeof (int) + 128,
343 5 + 384 * sizeof (short) / sizeof (int) + 128,
344 5 + 384 * sizeof (short) / sizeof (int) + 128,
345 5 + 384 * sizeof (short) / sizeof (int) + 128,
346 5 + 384 * sizeof (short) / sizeof (int) + 128,
347 5 + 384 * sizeof (short) / sizeof (int) + 128,
348 5 + 384 * sizeof (short) / sizeof (int) + 128,
349 5 + 384 * sizeof (short) / sizeof (int) + 128,
350 5 + 384 * sizeof (short) / sizeof (int) + 128,
351 5 + 384 * sizeof (short) / sizeof (int) + 128,
352 5 + 384 * sizeof (short) / sizeof (int) + 128,
353 5 + 384 * sizeof (short) / sizeof (int) + 128,
354 5 + 384 * sizeof (short) / sizeof (int) + 128,
355 5 + 384 * sizeof (short) / sizeof (int) + 128,
356 5 + 384 * sizeof (short) / sizeof (int) + 128,
357 5 + 384 * sizeof (short) / sizeof (int) + 128,
358 5 + 384 * sizeof (short) / sizeof (int) + 128,
359 5 + 384 * sizeof (short) / sizeof (int) + 128,
360 5 + 384 * sizeof (short) / sizeof (int) + 128,
361 5 + 384 * sizeof (short) / sizeof (int) + 128,
362 5 + 384 * sizeof (short) / sizeof (int) + 128,
363 5 + 384 * sizeof (short) / sizeof (int) + 128,
364 5 + 384 * sizeof (short) / sizeof (int) + 128,
365 5 + 384 * sizeof (short) / sizeof (int) + 128,
366 5 + 384 * sizeof (short) / sizeof (int) + 128,
367 5 + 384 * sizeof (short) / sizeof (int) + 128,
368 5 + 384 * sizeof (short) / sizeof (int) + 128,
369 5 + 384 * sizeof (short) / sizeof (int) + 128,
370 5 + 384 * sizeof (short) / sizeof (int) + 128,
371 5 + 384 * sizeof (short) / sizeof (int) + 128,
372 5 + 384 * sizeof (short) / sizeof (int) + 128,
373 5 + 384 * sizeof (short) / sizeof (int) + 128,
374 5 + 384 * sizeof (short) / sizeof (int) + 128,
375 5 + 384 * sizeof (short) / sizeof (int) + 128,
376 5 + 384 * sizeof (short) / sizeof (int) + 128,
377 5 + 384 * sizeof (short) / sizeof (int) + 128,
378 5 + 384 * sizeof (short) / sizeof (int) + 128,
379 5 + 384 * sizeof (short) / sizeof (int) + 128,
380 5 + 384 * sizeof (short) / sizeof (int) + 128,
381 5 + 384 * sizeof (short) / sizeof (int) + 128,
382 5 + 384 * sizeof (short) / sizeof (int) + 128,
383 5 + 384 * sizeof (short) / sizeof (int) + 128,
384 5 + 384 * sizeof (short) / sizeof (int) + 128,
385 5 + 384 * sizeof (short) / sizeof (int) + 128,
386 5 + 384 * sizeof (short) / sizeof (int) + 128,
387 5 + 384 * sizeof (short) / sizeof (int) + 128,
388 5 + 384 * sizeof (short) / sizeof (int) + 128,
389 5 + 384 * sizeof (short) / sizeof (int) + 128,
390 5 + 384 * sizeof (short) / sizeof (int) + 128,
391 5 + 384 * sizeof (short) / sizeof (int) + 128,
392 5 + 384 * sizeof (short) / sizeof (int) + 128,
393 5 + 384 * sizeof (short) / sizeof (int) + 128,
394 5 + 384 * sizeof (short) / sizeof (int) + 128,
395 5 + 384 * sizeof (short) / sizeof (int) + 128,
396 5 + 384 * sizeof (short) / sizeof (int) + 128,
397 5 + 384 * sizeof (short) / sizeof (int) + 128,
398 5 + 384 * sizeof (short) / sizeof (int) + 128,
399 5 + 384 * sizeof (short) / sizeof (int) + 128,
400 5 + 384 * sizeof (short) / sizeof (int) + 128,
401 5 + 384 * sizeof (short) / sizeof (int) + 128,
402 5 + 384 * sizeof (short) / sizeof (int) + 128,
403 5 + 384 * sizeof (short) / sizeof (int) + 128,
404 5 + 384 * sizeof (short) / sizeof (int) + 128,
405 5 + 384 * sizeof (short) / sizeof (int) + 128,
406 5 + 384 * sizeof (short) / sizeof (int) + 128,
407 5 + 384 * sizeof (short) / sizeof (int) + 128,
408 5 + 384 * sizeof (short) / sizeof (int) + 128,
409 5 + 384 * sizeof (short) / sizeof (int) + 128,
410 5 + 384 * sizeof (short) / sizeof (int) + 128,
411 5 + 384 * sizeof (short) / sizeof (int) + 128,
412 5 + 384 * sizeof (short) / sizeof (int) + 128,
413 5 + 384 * sizeof (short) / sizeof (int) + 128,
414 5 + 384 * sizeof (short) / sizeof (int) + 128,
415 5 + 384 * sizeof (short) / sizeof (int) + 128,
416 5 + 384 * sizeof (short) / sizeof (int) + 128,
417 5 + 384 * sizeof (short) / sizeof (int) + 128,
418 5 + 384 * sizeof (short) / sizeof (int) + 128,
419 5 + 384 * sizeof (short) / sizeof (int) + 128,
420 5 + 384 * sizeof (short) / sizeof (int) + 128,
421 5 + 384 * sizeof (short) / sizeof (int) + 128,
422 5 + 384 * sizeof (short) / sizeof (int) + 128,
423 5 + 384 * sizeof (short) / sizeof (int) + 128,
424 5 + 384 * sizeof (short) / sizeof (int) + 128,
425 5 + 384 * sizeof (short) / sizeof (int) + 128
426 },
427 {
428 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
429 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
430 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000000U,
431 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
432 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
433 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
434 0x0C000000U, 0x00000600U, 0x00000000U, 0x00000000U,
435 0x00000000U, 0x00000000U, 0x00000000U, 0x00091E00U,
436 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
437 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
438 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
439 0x00000000U, 0x00000000U, 0x00000000U, 0x60000000U,
440 0x00300000U, 0x00000000U, 0x000FFF00U, 0x80000000U,
441 0x00080000U, 0x60000C02U, 0x00104030U, 0x242C0400U,
442 0x00000C20U, 0x00000100U, 0x00B85000U, 0x00000000U,
443 0x00E00000U, 0x80010000U, 0x00000000U, 0x00000000U,
444 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
445 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
446 0x18000000U, 0x00000000U, 0x00210000U, 0x00000000U,
447 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
448 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
449 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
450 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
451 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
452 0xFFFFFFFFU, 0x7FFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
453 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
454 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
455 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
456 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFF00FFU, 0xFFFFFFFFU,
457 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
458 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
459 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
460 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
461 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
462 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
463 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
464 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
465 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
466 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
467 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000000U, 0x00000000U,
468 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
469 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000FFFFU, 0x00000000U,
470 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
471 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
472 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
473 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
474 0x00000000U, 0x00000000U, 0x00000000U, 0x1FFFFFFFU,
475 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
476 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
477 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
478 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
479 0xFFFFFFFFU, 0x0000000FU, 0x00000000U, 0x00000000U,
480 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
481 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
482 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
483 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
484 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
485 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
486 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
487 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
488 0xFFFF0000U, 0xFFFF0000U, 0xFFFFFFFFU, 0x0000FFFFU,
489 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
490 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000001U,
491 0x00000000U, 0x00000000U, 0x00000000U, 0x0000007FU,
492 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
493 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
494 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
495 0x00000000U, 0x00000000U, 0x00000000U, 0x0003000FU,
496 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
497 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
498 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
499 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x00FFFFFFU,
500 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
501 0xFFFFFFFFU, 0xFFFFFFFFU, 0x003FFFFFU, 0x00000000U,
502 0x000001FFU, 0x00000000U, 0x00000000U, 0x00000000U,
503 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
504 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
505 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
506 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
507 0x00000000U, 0x00000000U, 0x00000000U, 0x6FEF0000U,
508 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
509 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
510 0xFFFFFFFFU, 0x00000007U, 0x00070000U, 0xFFFF00F0U,
511 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
512 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
513 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0FFFFFFFU,
514 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
515 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
516 0x00000010U, 0x00000000U, 0x00000000U, 0x00000000U,
517 0x00000000U, 0x00000000U, 0x00008000U, 0x00000000U,
518 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
519 0x07FE4000U, 0x00000000U, 0x00000000U, 0x00000000U,
520 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
521 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
522 0xFFFFFFFFU, 0xFFBFE001U, 0xFFFFFFFFU, 0xDFFFFFFFU,
523 0x000FFFFFU, 0xFFFFFFFFU, 0x000F87FFU, 0xFF11FFFFU,
524 0xFFFFFFFFU, 0x7FFFFFFFU, 0xFFFFFFFDU, 0xFFFFFFFFU,
525 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x9FFFFFFFU,
526 0xFFFFFFFFU, 0x3FFFFFFFU, 0xFFFF7800U, 0x040000FFU,
527 0x00600000U, 0x00000010U, 0x00000000U, 0xF8000000U,
528 0xFFFFFFFFU, 0xFFFFFFFFU, 0x0000FFFFU, 0x00000000U,
529 0xFFFFFFFFU, 0xFFFFFFFFU, 0xE0E7103FU, 0x1FF01800U,
530 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
531 0x00000000U, 0x00000000U, 0x00000000U, 0x00010FFFU,
532 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
533 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
534 0xFFFFF000U, 0xF7FFFFFFU, 0xFFFFFFBFU, 0xFFFFFFFFU,
535 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
536 0x00000000U, 0x00000000U, 0x00000000U, 0x1F1F0000U,
537 0xFFFF007FU, 0x07FF1FFFU, 0x03FF003FU, 0x007F00FFU,
538 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U,
539 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U
540 }
541};
diff --git a/gl/unlocked-io.h b/gl/unlocked-io.h
index 0cd9bbf3..69ea6641 100644
--- a/gl/unlocked-io.h
+++ b/gl/unlocked-io.h
@@ -1,6 +1,6 @@
1/* Prefer faster, non-thread-safe stdio functions if available. 1/* Prefer faster, non-thread-safe stdio functions if available.
2 2
3 Copyright (C) 2001-2004, 2009-2024 Free Software Foundation, Inc. 3 Copyright (C) 2001-2004, 2009-2025 Free Software Foundation, Inc.
4 4
5 This program is free software: you can redistribute it and/or modify 5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
diff --git a/gl/unsetenv.c b/gl/unsetenv.c
index d8ada2aa..d38ed37a 100644
--- a/gl/unsetenv.c
+++ b/gl/unsetenv.c
@@ -1,4 +1,4 @@
1/* Copyright (C) 1992, 1995-2002, 2005-2024 Free Software Foundation, Inc. 1/* Copyright (C) 1992, 1995-2002, 2005-2025 Free Software Foundation, Inc.
2 This file is part of the GNU C Library. 2 This file is part of the GNU C Library.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
@@ -57,7 +57,6 @@ int
57unsetenv (const char *name) 57unsetenv (const char *name)
58{ 58{
59 size_t len; 59 size_t len;
60 char **ep;
61 60
62 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) 61 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
63 { 62 {
@@ -67,9 +66,37 @@ unsetenv (const char *name)
67 66
68 len = strlen (name); 67 len = strlen (name);
69 68
69#if HAVE_DECL__PUTENV /* native Windows */
70 /* The Microsoft documentation
71 <https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-wputenv>
72 says:
73 "Don't change an environment entry directly: instead,
74 use _putenv or _wputenv to change it."
75 Note: Microsoft's _putenv updates not only the contents of _environ but
76 also the contents of _wenviron, so that both are in kept in sync.
77
78 The way to remove an environment variable is to pass to _putenv a string
79 of the form "NAME=". (NB: This is a different convention than with glibc
80 putenv, which expects a string of the form "NAME"!) */
81 {
82 int putenv_result;
83 char *name_ = malloc (len + 2);
84 if (name_ == NULL)
85 return -1;
86 memcpy (name_, name, len);
87 name_[len] = '=';
88 name_[len + 1] = 0;
89 putenv_result = _putenv (name_);
90 /* In this particular case it is OK to free() the argument passed to
91 _putenv. */
92 free (name_);
93 return putenv_result;
94 }
95#else
96
70 LOCK; 97 LOCK;
71 98
72 ep = __environ; 99 char **ep = __environ;
73 while (*ep != NULL) 100 while (*ep != NULL)
74 if (!strncmp (*ep, name, len) && (*ep)[len] == '=') 101 if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
75 { 102 {
@@ -87,6 +114,7 @@ unsetenv (const char *name)
87 UNLOCK; 114 UNLOCK;
88 115
89 return 0; 116 return 0;
117#endif
90} 118}
91 119
92#ifdef _LIBC 120#ifdef _LIBC
diff --git a/gl/vasnprintf.c b/gl/vasnprintf.c
index de204458..f46e8701 100644
--- a/gl/vasnprintf.c
+++ b/gl/vasnprintf.c
@@ -1,5 +1,5 @@
1/* vsprintf with automatic memory allocation. 1/* vsprintf with automatic memory allocation.
2 Copyright (C) 1999, 2002-2024 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2002-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -29,6 +29,7 @@
29 Depends on FCHAR_T. 29 Depends on FCHAR_T.
30 DCHAR_CPY memcpy like function for DCHAR_T[] arrays. 30 DCHAR_CPY memcpy like function for DCHAR_T[] arrays.
31 DCHAR_SET memset like function for DCHAR_T[] arrays. 31 DCHAR_SET memset like function for DCHAR_T[] arrays.
32 DCHAR_STRLEN strlen like function for DCHAR_T[] arrays.
32 DCHAR_MBSNLEN mbsnlen like function for DCHAR_T[] arrays. 33 DCHAR_MBSNLEN mbsnlen like function for DCHAR_T[] arrays.
33 SNPRINTF The system's snprintf (or similar) function. 34 SNPRINTF The system's snprintf (or similar) function.
34 This may be either snprintf or swprintf. 35 This may be either snprintf or swprintf.
@@ -64,7 +65,7 @@
64/* As of GCC 11.2.1, gcc -Wanalyzer-too-complex reports that main's 65/* As of GCC 11.2.1, gcc -Wanalyzer-too-complex reports that main's
65 use of CHECK macros expands to code that is too complicated for gcc 66 use of CHECK macros expands to code that is too complicated for gcc
66 -fanalyzer. Suppress the resulting bogus warnings. */ 67 -fanalyzer. Suppress the resulting bogus warnings. */
67#if 10 <= __GNUC__ 68#if _GL_GNUC_PREREQ (10, 0)
68# pragma GCC diagnostic ignored "-Wanalyzer-null-argument" 69# pragma GCC diagnostic ignored "-Wanalyzer-null-argument"
69#endif 70#endif
70 71
@@ -80,14 +81,15 @@
80#endif 81#endif
81 82
82#include <locale.h> /* localeconv() */ 83#include <locale.h> /* localeconv() */
84#include <stdint.h> /* PTRDIFF_MAX */
83#include <stdio.h> /* snprintf(), sprintf() */ 85#include <stdio.h> /* snprintf(), sprintf() */
84#include <stdlib.h> /* abort(), malloc(), realloc(), free() */ 86#include <stdlib.h> /* abort(), malloc(), realloc(), free() */
85#include <string.h> /* memcpy(), strlen() */ 87#include <string.h> /* memcpy(), strlen() */
86#include <wchar.h> /* mbstate_t, mbrtowc(), mbrlen(), wcrtomb(), mbszero() */ 88#include <wchar.h> /* mbstate_t, mbrtowc(), mbrlen(), wcrtomb(), mbszero() */
87#include <errno.h> /* errno */ 89#include <errno.h> /* errno */
88#include <limits.h> /* CHAR_BIT, INT_WIDTH, LONG_WIDTH */ 90#include <limits.h> /* CHAR_BIT, INT_MAX, INT_WIDTH, LONG_WIDTH */
89#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */ 91#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP, LDBL_MANT_DIG */
90#if HAVE_NL_LANGINFO 92#if HAVE_NL_LANGINFO || __GLIBC__ >= 2 || defined __CYGWIN__
91# include <langinfo.h> 93# include <langinfo.h>
92#endif 94#endif
93#ifndef VASNPRINTF 95#ifndef VASNPRINTF
@@ -182,6 +184,20 @@
182# define TCHAR_T char 184# define TCHAR_T char
183# endif 185# endif
184#endif 186#endif
187#ifndef DCHAR_STRLEN
188# if WIDE_CHAR_VERSION
189# define DCHAR_STRLEN local_wcslen
190# else
191# define DCHAR_STRLEN strlen
192# endif
193#endif
194#ifndef DCHAR_MBSNLEN
195# if WIDE_CHAR_VERSION
196# define DCHAR_MBSNLEN wcsnlen
197# else
198# define DCHAR_MBSNLEN mbsnlen
199# endif
200#endif
185#if !WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR 201#if !WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR
186 /* TCHAR_T is char. */ 202 /* TCHAR_T is char. */
187 /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'. 203 /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'.
@@ -216,6 +232,12 @@
216/* Here we need to call the native sprintf, not rpl_sprintf. */ 232/* Here we need to call the native sprintf, not rpl_sprintf. */
217#undef sprintf 233#undef sprintf
218 234
235/* macOS 12's "warning: 'sprintf' is deprecated" is pointless,
236 as sprintf is used safely here. */
237#if defined __APPLE__ && defined __MACH__ && _GL_GNUC_PREREQ (4, 2)
238# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
239#endif
240
219/* GCC >= 4.0 with -Wall emits unjustified "... may be used uninitialized" 241/* GCC >= 4.0 with -Wall emits unjustified "... may be used uninitialized"
220 warnings in this file. Use -Dlint to suppress them. */ 242 warnings in this file. Use -Dlint to suppress them. */
221#if defined GCC_LINT || defined lint 243#if defined GCC_LINT || defined lint
@@ -224,6 +246,11 @@
224# define IF_LINT(Code) /* empty */ 246# define IF_LINT(Code) /* empty */
225#endif 247#endif
226 248
249/* Here we need only the most basic fields of 'struct lconv', and can
250 therefore use the system's localeconv() function, without needing a
251 dependency on module 'localeconv'. */
252#undef localeconv
253
227/* Avoid some warnings from "gcc -Wshadow". 254/* Avoid some warnings from "gcc -Wshadow".
228 This file doesn't use the exp() and remainder() functions. */ 255 This file doesn't use the exp() and remainder() functions. */
229#undef exp 256#undef exp
@@ -231,7 +258,7 @@
231#undef remainder 258#undef remainder
232#define remainder rem 259#define remainder rem
233 260
234#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && !WIDE_CHAR_VERSION 261#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (PTRDIFF_MAX > INT_MAX)) && !WIDE_CHAR_VERSION
235# if (HAVE_STRNLEN && !defined _AIX) 262# if (HAVE_STRNLEN && !defined _AIX)
236# define local_strnlen strnlen 263# define local_strnlen strnlen
237# else 264# else
@@ -247,7 +274,7 @@ local_strnlen (const char *string, size_t maxlen)
247# endif 274# endif
248#endif 275#endif
249 276
250#if (((!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_WPRINTF_DIRECTIVE_LC) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T 277#if ((!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (PTRDIFF_MAX > INT_MAX) || !DCHAR_IS_TCHAR || NEED_WPRINTF_DIRECTIVE_LC) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || (PTRDIFF_MAX > INT_MAX) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)
251# if HAVE_WCSLEN 278# if HAVE_WCSLEN
252# define local_wcslen wcslen 279# define local_wcslen wcslen
253# else 280# else
@@ -270,7 +297,7 @@ local_wcslen (const wchar_t *s)
270# endif 297# endif
271#endif 298#endif
272 299
273#if (!USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && HAVE_WCHAR_T && WIDE_CHAR_VERSION 300#if (!USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && WIDE_CHAR_VERSION
274# if HAVE_WCSNLEN && HAVE_DECL_WCSNLEN 301# if HAVE_WCSNLEN && HAVE_DECL_WCSNLEN
275# define local_wcsnlen wcsnlen 302# define local_wcsnlen wcsnlen
276# else 303# else
@@ -289,7 +316,7 @@ local_wcsnlen (const wchar_t *s, size_t maxlen)
289# endif 316# endif
290#endif 317#endif
291 318
292#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) || ((NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T)) && !WIDE_CHAR_VERSION 319#if ((!USE_SNPRINTF || (PTRDIFF_MAX > INT_MAX) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) || ((NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T)) && !WIDE_CHAR_VERSION
293# if ENABLE_WCHAR_FALLBACK 320# if ENABLE_WCHAR_FALLBACK
294static size_t 321static size_t
295wctomb_fallback (char *s, wchar_t wc) 322wctomb_fallback (char *s, wchar_t wc)
@@ -357,7 +384,7 @@ local_wctomb (char *s, wchar_t wc)
357# endif 384# endif
358#endif 385#endif
359 386
360#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION) 387#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION) || (NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT)
361/* Determine the decimal-point character according to the current locale. */ 388/* Determine the decimal-point character according to the current locale. */
362# ifndef decimal_point_char_defined 389# ifndef decimal_point_char_defined
363# define decimal_point_char_defined 1 390# define decimal_point_char_defined 1
@@ -384,6 +411,217 @@ decimal_point_char (void)
384# endif 411# endif
385#endif 412#endif
386 413
414#if (!WIDE_CHAR_VERSION && (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE)) || ((!WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR) && (NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT))
415/* Determine the thousands-separator character according to the current
416 locale.
417 It is a single multibyte character.
418 In glibc: 35x ".", 90x ",", 23x U+202F, 1x U+2019, 1x U+066C, on other
419 systems also U+00A0. */
420# ifndef thousands_separator_char_defined
421# define thousands_separator_char_defined 1
422static const char *
423thousands_separator_char (char stackbuf[10])
424{
425 /* Determine it in a multithread-safe way.
426 We know nl_langinfo is multithread-safe on glibc systems, on Mac OS X
427 systems, and on NetBSD, but is not required to be multithread-safe by
428 POSIX.
429 localeconv() is not guaranteed to be multithread-safe by POSIX either;
430 however, on native Windows it is (cf. test-localeconv-mt).
431 sprintf(), however, is multithread-safe. */
432# if HAVE_NL_LANGINFO && (__GLIBC__ || defined __UCLIBC__ || (defined __APPLE__ && defined __MACH__) || defined __NetBSD__)
433 return nl_langinfo (THOUSEP);
434# elif defined _WIN32 && !defined __CYGWIN__
435 return localeconv () -> thousands_sep;
436# else
437 sprintf (stackbuf, "%'.0f", 1000.0);
438 /* Now stackbuf = "1<thousep>000". */
439 stackbuf[strlen (stackbuf) - 3] = '\0';
440# if defined __sun
441 /* Solaris specific hack: Replace wrong result (0xC2 means U+00A0). */
442 if (strcmp (&stackbuf[1], "\302") == 0)
443 strcpy (&stackbuf[1], MB_CUR_MAX > 1 ? "\302\240" : "\240");
444# endif
445 return &stackbuf[1];
446# endif
447}
448# endif
449#endif
450#if !WIDE_CHAR_VERSION && defined DCHAR_CONV_FROM_ENCODING && (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE)
451/* Determine the thousands-separator character, as a DCHAR_T[] array,
452 according to the current locale.
453 It is a single Unicode character. */
454# ifndef thousands_separator_DCHAR_defined
455# define thousands_separator_DCHAR_defined 1
456static const DCHAR_T *
457thousands_separator_DCHAR (DCHAR_T stackbuf[10])
458{
459 /* Determine it in a multithread-safe way. */
460 char tmpbuf[10];
461 const char *tmp = thousands_separator_char (tmpbuf);
462 if (*tmp != '\0')
463 {
464 /* Convert it from char[] to DCHAR_T[]. */
465 size_t converted_len = 10;
466 DCHAR_T *converted =
467 DCHAR_CONV_FROM_ENCODING (locale_charset (),
468 iconveh_question_mark,
469 tmp, strlen (tmp) + 1,
470 NULL,
471 stackbuf, &converted_len);
472 if (converted != NULL)
473 {
474 if (converted != stackbuf)
475 /* It should not be so long. */
476 abort ();
477 return stackbuf;
478 }
479 }
480 stackbuf[0] = 0;
481 return stackbuf;
482}
483# endif
484#endif
485/* Maximum number of 'char' in the char[] or DCHAR_T[] representation of the
486 thousands separator. */
487#define THOUSEP_CHAR_MAXLEN 3
488
489#if WIDE_CHAR_VERSION && ((NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) || ((NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT) && DCHAR_IS_TCHAR))
490/* Determine the thousands-separator character, as a wide character, according
491 to the current locale.
492 It is a single wide character. */
493# ifndef thousands_separator_wchar_defined
494# define thousands_separator_wchar_defined 1
495static const wchar_t *
496thousands_separator_wchar (wchar_t stackbuf[10])
497{
498# if __GLIBC__ >= 2 || defined __CYGWIN__
499 /* On glibc, in the unibyte locale fr_FR, the *wprintf routines use U+202F
500 as separator, which cannot be represented in the locale encoding. */
501 stackbuf[0] =
502 (wchar_t) (unsigned long) nl_langinfo (_NL_NUMERIC_THOUSANDS_SEP_WC);
503 stackbuf[1] = L'\0';
504 return stackbuf;
505# elif defined _WIN32 && !defined __CYGWIN__
506 const char *tmp = localeconv () -> thousands_sep;
507 if (*tmp != '\0')
508 {
509 mbstate_t state;
510 mbszero (&state);
511 if ((int) mbrtowc (&stackbuf[0], tmp, strlen (tmp), &state) > 0)
512 stackbuf[1] = L'\0';
513 else
514 stackbuf[0] = L'\0';
515 }
516 else
517 stackbuf[0] = L'\0';
518 return stackbuf;
519# elif defined __sun
520 /* Use sprintf, because swprintf retrieves a wrong value for the
521 thousands-separator wide character (e.g. (wchar_t) 0xffffffa0). */
522 char tmp[10];
523 sprintf (tmp, "%'.0f", 1000.0);
524 /* Now tmp = L"1<thousep>000". */
525 tmp[strlen (tmp) - 3] = '\0';
526 /* Solaris specific hack: Replace wrong result (0xC2 means U+00A0). */
527 if (strcmp (&tmp[1], "\302") == 0)
528 strcpy (&tmp[1], MB_CUR_MAX > 1 ? "\302\240" : "\240");
529 if (tmp[1] != '\0')
530 {
531 mbstate_t state;
532 mbszero (&state);
533 if ((int) mbrtowc (&stackbuf[0], &tmp[1], strlen (&tmp[1]), &state) > 0)
534 stackbuf[1] = L'\0';
535 else
536 stackbuf[0] = L'\0';
537 }
538 else
539 stackbuf[0] = L'\0';
540 return stackbuf;
541# else
542 swprintf (stackbuf, 10, L"%'.0f", 1000.0);
543 /* Now stackbuf = L"1<thousep>000". */
544 stackbuf[local_wcslen (stackbuf) - 3] = '\0';
545 return &stackbuf[1];
546# endif
547}
548# endif
549#endif
550/* Maximum number of 'wchar_t' in the wchar_t[] representation of the thousands
551 separator. */
552#define THOUSEP_WCHAR_MAXLEN 1
553
554#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) || (NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT)
555# ifndef grouping_rule_defined
556# define grouping_rule_defined 1
557/* Determine the grouping rule.
558 * As specified in POSIX
559 * <https://pubs.opengroup.org/onlinepubs/9799919799/functions/localeconv.html>
560 * <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html#tag_07_03_04>
561 * it is a string whose elements are 'signed char' values, where
562 * "Each integer specifies the number of digits in each group, with the initial
563 * integer defining the size of the group immediately preceding the decimal
564 * delimiter, and the following integers defining the preceding groups. If
565 * the last integer is not -1, then the size of the previous group (if any)
566 * shall be repeatedly used for the remainder of the digits. If the last
567 * integer is -1, then no further grouping shall be performed."
568 * Platforms that have locales with grouping:
569 * glibc, FreeBSD, NetBSD, AIX, Solaris, Cygwin, Haiku.
570 * Platforms that don't:
571 * musl libc, macOS, OpenBSD, Android, mingw, MSVC.
572 * Typical grouping rules on glibc:
573 * 136x 3 (fr_FR etc.)
574 * 4x 4 (cmn_TW etc.)
575 * 9x 3;2 (ta_IN etc.)
576 * 1x 2;2;2;3 (umn_US)
577 * 21x -1 (C etc.)
578 */
579static const signed char *
580grouping_rule (void)
581{
582 /* We know nl_langinfo is multithread-safe on glibc systems and on Cygwin,
583 but is not required to be multithread-safe by POSIX.
584 localeconv() is not guaranteed to be multithread-safe by POSIX either;
585 however, on all known systems it is (cf. test-localeconv-mt). */
586# if __GLIBC__ >= 2
587 return (const signed char *) nl_langinfo (GROUPING);
588# elif defined __CYGWIN__
589 return (const signed char *) nl_langinfo (_NL_NUMERIC_GROUPING);
590# else
591 return (const signed char *) localeconv () -> grouping;
592# endif
593}
594/* Determines the number of thousands-separators to be inserted in a digit
595 sequence with ndigits digits (before the decimal point). */
596static size_t
597num_thousands_separators (const signed char *grouping, size_t ndigits)
598{
599 const signed char *g = grouping;
600 int h = *g;
601 if (h <= 0 || ndigits == 0)
602 return 0;
603 size_t insert = 0;
604 for (;;)
605 {
606 /* Invariant: here h == *g, h > 0, ndigits > 0. */
607 if (g[1] == 0)
608 /* h repeats endlessly. */
609 return insert + (ndigits - 1) / h;
610 /* h does not repeat. */
611 if (ndigits <= h)
612 return insert;
613 ndigits -= h;
614 insert++;
615 g++;
616 h = *g;
617 if (h < 0)
618 /* No further grouping. */
619 return insert;
620 }
621}
622# endif
623#endif
624
387#if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE 625#if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE
388 626
389/* Equivalent to !isfinite(x) || x == 0, but does not require libm. */ 627/* Equivalent to !isfinite(x) || x == 0, but does not require libm. */
@@ -406,8 +644,45 @@ is_infinite_or_zerol (long double x)
406 644
407#endif 645#endif
408 646
647#if NEED_PRINTF_LONG_DOUBLE
648
649/* Like frexpl, except that it supports even "unsupported" numbers. */
650# if (LDBL_MANT_DIG == 64 && (defined __ia64 || (defined __x86_64__ || defined __amd64__) || (defined __i386 || defined __i386__ || defined _I386 || defined _M_IX86 || defined _X86_))) && (defined __APPLE__ && defined __MACH__)
651/* Don't assume that frexpl can handle pseudo-denormals; it does not on
652 macOS 12/x86_64. Therefore test for a pseudo-denormal explicitly. */
653
654static
655long double safe_frexpl (long double x, int *exp)
656{
657 union
658 {
659 long double value;
660 struct { unsigned int mant_word[2]; unsigned short sign_exp_word; } r;
661 }
662 u;
663 u.value = x;
664 if (u.r.sign_exp_word == 0 && (u.r.mant_word[1] & 0x80000000u) != 0)
665 {
666 /* Pseudo-Denormal. */
667 *exp = LDBL_MIN_EXP;
668 u.r.sign_exp_word = 1 - LDBL_MIN_EXP;
669 return u.value;
670 }
671 else
672 return frexpl (x, exp);
673}
674
675# else
676# define safe_frexpl frexpl
677# endif
678
679#endif
680
409#if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE 681#if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE
410 682
683/* An indicator for a failed memory allocation. */
684# define NOMEM_PTR ((void *) (-1))
685
411/* Converting 'long double' to decimal without rare rounding bugs requires 686/* Converting 'long double' to decimal without rare rounding bugs requires
412 real bignums. We use the naming conventions of GNU gmp, but vastly simpler 687 real bignums. We use the naming conventions of GNU gmp, but vastly simpler
413 (and slower) algorithms. */ 688 (and slower) algorithms. */
@@ -428,8 +703,8 @@ typedef struct
428} mpn_t; 703} mpn_t;
429 704
430/* Compute the product of two bignums >= 0. 705/* Compute the product of two bignums >= 0.
431 Return the allocated memory in case of success, NULL in case of memory 706 Return the allocated memory (possibly NULL) in case of success, NOMEM_PTR
432 allocation failure. */ 707 in case of memory allocation failure. */
433static void * 708static void *
434multiply (mpn_t src1, mpn_t src2, mpn_t *dest) 709multiply (mpn_t src1, mpn_t src2, mpn_t *dest)
435{ 710{
@@ -457,7 +732,7 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest)
457 { 732 {
458 /* src1 or src2 is zero. */ 733 /* src1 or src2 is zero. */
459 dest->nlimbs = 0; 734 dest->nlimbs = 0;
460 dest->limbs = (mp_limb_t *) malloc (1); 735 dest->limbs = NULL;
461 } 736 }
462 else 737 else
463 { 738 {
@@ -469,7 +744,7 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest)
469 dlen = len1 + len2; 744 dlen = len1 + len2;
470 dp = (mp_limb_t *) malloc (dlen * sizeof (mp_limb_t)); 745 dp = (mp_limb_t *) malloc (dlen * sizeof (mp_limb_t));
471 if (dp == NULL) 746 if (dp == NULL)
472 return NULL; 747 return NOMEM_PTR;
473 for (k = len2; k > 0; ) 748 for (k = len2; k > 0; )
474 dp[--k] = 0; 749 dp[--k] = 0;
475 for (i = 0; i < len1; i++) 750 for (i = 0; i < len1; i++)
@@ -500,8 +775,8 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest)
500 the remainder. 775 the remainder.
501 Finally, round-to-even is performed: If r > b/2 or if r = b/2 and q is odd, 776 Finally, round-to-even is performed: If r > b/2 or if r = b/2 and q is odd,
502 q is incremented. 777 q is incremented.
503 Return the allocated memory in case of success, NULL in case of memory 778 Return the allocated memory (possibly NULL) in case of success, NOMEM_PTR
504 allocation failure. */ 779 in case of memory allocation failure. */
505static void * 780static void *
506divide (mpn_t a, mpn_t b, mpn_t *q) 781divide (mpn_t a, mpn_t b, mpn_t *q)
507{ 782{
@@ -572,7 +847,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
572 final rounding of q.) */ 847 final rounding of q.) */
573 roomptr = (mp_limb_t *) malloc ((a_len + 2) * sizeof (mp_limb_t)); 848 roomptr = (mp_limb_t *) malloc ((a_len + 2) * sizeof (mp_limb_t));
574 if (roomptr == NULL) 849 if (roomptr == NULL)
575 return NULL; 850 return NOMEM_PTR;
576 851
577 /* Normalise a. */ 852 /* Normalise a. */
578 while (a_len > 0 && a_ptr[a_len - 1] == 0) 853 while (a_len > 0 && a_ptr[a_len - 1] == 0)
@@ -708,7 +983,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
708 if (tmp_roomptr == NULL) 983 if (tmp_roomptr == NULL)
709 { 984 {
710 free (roomptr); 985 free (roomptr);
711 return NULL; 986 return NOMEM_PTR;
712 } 987 }
713 { 988 {
714 const mp_limb_t *sourceptr = b_ptr; 989 const mp_limb_t *sourceptr = b_ptr;
@@ -930,7 +1205,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
930/* Avoid pointless GCC warning "argument 1 value '18446744073709551615' exceeds 1205/* Avoid pointless GCC warning "argument 1 value '18446744073709551615' exceeds
931 maximum object size 9223372036854775807", triggered by the use of xsum as 1206 maximum object size 9223372036854775807", triggered by the use of xsum as
932 argument of malloc. */ 1207 argument of malloc. */
933# if __GNUC__ >= 7 1208# if _GL_GNUC_PREREQ (7, 0)
934# pragma GCC diagnostic push 1209# pragma GCC diagnostic push
935# pragma GCC diagnostic ignored "-Walloc-size-larger-than=" 1210# pragma GCC diagnostic ignored "-Walloc-size-larger-than="
936# endif 1211# endif
@@ -991,7 +1266,7 @@ convert_to_decimal (mpn_t a, size_t extra_zeroes)
991 return c_ptr; 1266 return c_ptr;
992} 1267}
993 1268
994# if __GNUC__ >= 7 1269# if _GL_GNUC_PREREQ (7, 0)
995# pragma GCC diagnostic pop 1270# pragma GCC diagnostic pop
996# endif 1271# endif
997 1272
@@ -1015,7 +1290,7 @@ decode_long_double (long double x, int *ep, mpn_t *mp)
1015 if (m.limbs == NULL) 1290 if (m.limbs == NULL)
1016 return NULL; 1291 return NULL;
1017 /* Split into exponential part and mantissa. */ 1292 /* Split into exponential part and mantissa. */
1018 y = frexpl (x, &exp); 1293 y = safe_frexpl (x, &exp);
1019 if (!(y >= 0.0L && y < 1.0L)) 1294 if (!(y >= 0.0L && y < 1.0L))
1020 abort (); 1295 abort ();
1021 /* x = 2^exp * y = 2^(exp - LDBL_MANT_BIT) * (y * 2^LDBL_MANT_BIT), and the 1296 /* x = 2^exp * y = 2^(exp - LDBL_MANT_BIT) * (y * 2^LDBL_MANT_BIT), and the
@@ -1306,7 +1581,7 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
1306 mpn_t denominator; 1581 mpn_t denominator;
1307 void *tmp_memory; 1582 void *tmp_memory;
1308 tmp_memory = multiply (m, pow5, &numerator); 1583 tmp_memory = multiply (m, pow5, &numerator);
1309 if (tmp_memory == NULL) 1584 if (tmp_memory == NOMEM_PTR)
1310 { 1585 {
1311 free (pow5_ptr); 1586 free (pow5_ptr);
1312 free (memory); 1587 free (memory);
@@ -1379,7 +1654,7 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
1379 1654
1380 /* Here y = round (x * 10^n) = z * 10^extra_zeroes. */ 1655 /* Here y = round (x * 10^n) = z * 10^extra_zeroes. */
1381 1656
1382 if (z_memory == NULL) 1657 if (z_memory == NOMEM_PTR)
1383 return NULL; 1658 return NULL;
1384 digits = convert_to_decimal (z, extra_zeroes); 1659 digits = convert_to_decimal (z, extra_zeroes);
1385 free (z_memory); 1660 free (z_memory);
@@ -1442,7 +1717,7 @@ floorlog10l (long double x)
1442 double l; 1717 double l;
1443 1718
1444 /* Split into exponential part and mantissa. */ 1719 /* Split into exponential part and mantissa. */
1445 y = frexpl (x, &exp); 1720 y = safe_frexpl (x, &exp);
1446 if (!(y >= 0.0L && y < 1.0L)) 1721 if (!(y >= 0.0L && y < 1.0L))
1447 abort (); 1722 abort ();
1448 if (y == 0.0L) 1723 if (y == 0.0L)
@@ -1801,8 +2076,17 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1801 } 2076 }
1802 if (tmp_length < precision) 2077 if (tmp_length < precision)
1803 tmp_length = precision; 2078 tmp_length = precision;
1804 /* Multiply by 2, as an estimate for FLAG_GROUP. */ 2079 /* Account for thousands separators. */
1805 tmp_length = xsum (tmp_length, tmp_length); 2080 if (flags & FLAG_GROUP)
2081 {
2082 /* A thousands separator needs to be inserted at most every 2 digits.
2083 This is the case in the ta_IN locale. */
2084# if WIDE_CHAR_VERSION
2085 tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_WCHAR_MAXLEN);
2086# else
2087 tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_CHAR_MAXLEN);
2088# endif
2089 }
1806 /* Add 1, to account for a leading sign. */ 2090 /* Add 1, to account for a leading sign. */
1807 tmp_length = xsum (tmp_length, 1); 2091 tmp_length = xsum (tmp_length, 1);
1808 break; 2092 break;
@@ -2050,12 +2334,18 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
2050 tmp_length = xsum (tmp_length, 2); 2334 tmp_length = xsum (tmp_length, 2);
2051 break; 2335 break;
2052 2336
2337 case 'e': case 'E':
2338 tmp_length =
2339 12; /* sign, decimal point, exponent etc. */
2340 tmp_length = xsum (tmp_length, precision);
2341 break;
2342
2053 case 'f': case 'F': 2343 case 'f': case 'F':
2054 if (type == TYPE_LONGDOUBLE) 2344 if (type == TYPE_LONGDOUBLE)
2055 tmp_length = 2345 tmp_length =
2056 (unsigned int) (LDBL_MAX_EXP 2346 (unsigned int) (LDBL_MAX_EXP
2057 * 0.30103 /* binary -> decimal */ 2347 * 0.30103 /* binary -> decimal */
2058 * 2 /* estimate for FLAG_GROUP */ 2348 * 0.5 * 3 /* estimate for FLAG_GROUP */
2059 ) 2349 )
2060 + 1 /* turn floor into ceil */ 2350 + 1 /* turn floor into ceil */
2061 + 10; /* sign, decimal point etc. */ 2351 + 10; /* sign, decimal point etc. */
@@ -2063,17 +2353,20 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
2063 tmp_length = 2353 tmp_length =
2064 (unsigned int) (DBL_MAX_EXP 2354 (unsigned int) (DBL_MAX_EXP
2065 * 0.30103 /* binary -> decimal */ 2355 * 0.30103 /* binary -> decimal */
2066 * 2 /* estimate for FLAG_GROUP */ 2356 * 0.5 * 3 /* estimate for FLAG_GROUP */
2067 ) 2357 )
2068 + 1 /* turn floor into ceil */ 2358 + 1 /* turn floor into ceil */
2069 + 10; /* sign, decimal point etc. */ 2359 + 10; /* sign, decimal point etc. */
2070 tmp_length = xsum (tmp_length, precision); 2360 tmp_length = xsum (tmp_length, precision);
2071 break; 2361 break;
2072 2362
2073 case 'e': case 'E': case 'g': case 'G': 2363 case 'g': case 'G':
2074 tmp_length = 2364 tmp_length =
2075 12; /* sign, decimal point, exponent etc. */ 2365 12; /* sign, decimal point, exponent etc. */
2076 tmp_length = xsum (tmp_length, precision); 2366 tmp_length = xsum (tmp_length,
2367 precision
2368 * 0.5 * 3 /* estimate for FLAG_GROUP */
2369 );
2077 break; 2370 break;
2078 2371
2079 case 'a': case 'A': 2372 case 'a': case 'A':
@@ -2111,10 +2404,9 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
2111 break; 2404 break;
2112 2405
2113 case 's': 2406 case 's':
2114# if HAVE_WCHAR_T
2115 if (type == TYPE_WIDE_STRING) 2407 if (type == TYPE_WIDE_STRING)
2116 { 2408 {
2117# if WIDE_CHAR_VERSION 2409# if WIDE_CHAR_VERSION
2118 /* ISO C says about %ls in fwprintf: 2410 /* ISO C says about %ls in fwprintf:
2119 "If the precision is not specified or is greater than the size 2411 "If the precision is not specified or is greater than the size
2120 of the array, the array shall contain a null wide character." 2412 of the array, the array shall contain a null wide character."
@@ -2125,7 +2417,7 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
2125 tmp_length = local_wcsnlen (arg, precision); 2417 tmp_length = local_wcsnlen (arg, precision);
2126 else 2418 else
2127 tmp_length = local_wcslen (arg); 2419 tmp_length = local_wcslen (arg);
2128# else 2420# else
2129 /* ISO C says about %ls in fprintf: 2421 /* ISO C says about %ls in fprintf:
2130 "If a precision is specified, no more than that many bytes are 2422 "If a precision is specified, no more than that many bytes are
2131 written (including shift sequences, if any), and the array 2423 written (including shift sequences, if any), and the array
@@ -2136,10 +2428,9 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
2136 So if there is a precision, we must not use wcslen. */ 2428 So if there is a precision, we must not use wcslen. */
2137 /* This case has already been handled separately in VASNPRINTF. */ 2429 /* This case has already been handled separately in VASNPRINTF. */
2138 abort (); 2430 abort ();
2139# endif 2431# endif
2140 } 2432 }
2141 else 2433 else
2142# endif
2143 { 2434 {
2144# if WIDE_CHAR_VERSION 2435# if WIDE_CHAR_VERSION
2145 /* ISO C says about %s in fwprintf: 2436 /* ISO C says about %s in fwprintf:
@@ -2226,7 +2517,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2226 TCHAR_T *buf; 2517 TCHAR_T *buf;
2227 TCHAR_T *buf_malloced; 2518 TCHAR_T *buf_malloced;
2228 const FCHAR_T *cp; 2519 const FCHAR_T *cp;
2229 size_t i; 2520 size_t di;
2230 DIRECTIVE *dp; 2521 DIRECTIVE *dp;
2231 /* Output string accumulator. */ 2522 /* Output string accumulator. */
2232 DCHAR_T *result; 2523 DCHAR_T *result;
@@ -2290,7 +2581,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2290#define ENSURE_ALLOCATION(needed) \ 2581#define ENSURE_ALLOCATION(needed) \
2291 ENSURE_ALLOCATION_ELSE((needed), goto out_of_memory; ) 2582 ENSURE_ALLOCATION_ELSE((needed), goto out_of_memory; )
2292 2583
2293 for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++) 2584 for (cp = format, di = 0, dp = &d.dir[0]; ; cp = dp->dir_end, di++, dp++)
2294 { 2585 {
2295 if (cp != dp->dir_start) 2586 if (cp != dp->dir_start)
2296 { 2587 {
@@ -2313,7 +2604,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2313 while (--n > 0); 2604 while (--n > 0);
2314 } 2605 }
2315 } 2606 }
2316 if (i == d.count) 2607 if (di == d.count)
2317 break; 2608 break;
2318 2609
2319 /* Execute a single directive. */ 2610 /* Execute a single directive. */
@@ -2423,6 +2714,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2423 width = xsum (xtimes (width, 10), *digitp++ - '0'); 2714 width = xsum (xtimes (width, 10), *digitp++ - '0');
2424 while (digitp != dp->width_end); 2715 while (digitp != dp->width_end);
2425 } 2716 }
2717 if (width > (size_t) INT_MAX)
2718 goto overflow;
2426 has_width = 1; 2719 has_width = 1;
2427 } 2720 }
2428 2721
@@ -2501,7 +2794,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2501 { 2794 {
2502 /* Use the entire string. */ 2795 /* Use the entire string. */
2503 arg_end = arg + u8_strlen (arg); 2796 arg_end = arg + u8_strlen (arg);
2504 /* The number of characters doesn't matter. */ 2797 /* The number of characters doesn't matter,
2798 because !has_width and therefore width==0. */
2505 characters = 0; 2799 characters = 0;
2506 } 2800 }
2507 2801
@@ -2542,7 +2836,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2542 if (converted != result + length) 2836 if (converted != result + length)
2543 { 2837 {
2544 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len), 2838 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len),
2545 { free (converted); goto out_of_memory; }); 2839 { free (converted); goto out_of_memory; });
2546 DCHAR_CPY (result + length, converted, converted_len); 2840 DCHAR_CPY (result + length, converted, converted_len);
2547 free (converted); 2841 free (converted);
2548 } 2842 }
@@ -2603,7 +2897,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2603 { 2897 {
2604 /* Use the entire string. */ 2898 /* Use the entire string. */
2605 arg_end = arg + u16_strlen (arg); 2899 arg_end = arg + u16_strlen (arg);
2606 /* The number of characters doesn't matter. */ 2900 /* The number of characters doesn't matter,
2901 because !has_width and therefore width==0. */
2607 characters = 0; 2902 characters = 0;
2608 } 2903 }
2609 2904
@@ -2644,7 +2939,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2644 if (converted != result + length) 2939 if (converted != result + length)
2645 { 2940 {
2646 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len), 2941 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len),
2647 { free (converted); goto out_of_memory; }); 2942 { free (converted); goto out_of_memory; });
2648 DCHAR_CPY (result + length, converted, converted_len); 2943 DCHAR_CPY (result + length, converted, converted_len);
2649 free (converted); 2944 free (converted);
2650 } 2945 }
@@ -2705,7 +3000,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2705 { 3000 {
2706 /* Use the entire string. */ 3001 /* Use the entire string. */
2707 arg_end = arg + u32_strlen (arg); 3002 arg_end = arg + u32_strlen (arg);
2708 /* The number of characters doesn't matter. */ 3003 /* The number of characters doesn't matter,
3004 because !has_width and therefore width==0. */
2709 characters = 0; 3005 characters = 0;
2710 } 3006 }
2711 3007
@@ -2746,7 +3042,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2746 if (converted != result + length) 3042 if (converted != result + length)
2747 { 3043 {
2748 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len), 3044 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len),
2749 { free (converted); goto out_of_memory; }); 3045 { free (converted); goto out_of_memory; });
2750 DCHAR_CPY (result + length, converted, converted_len); 3046 DCHAR_CPY (result + length, converted, converted_len);
2751 free (converted); 3047 free (converted);
2752 } 3048 }
@@ -2769,7 +3065,190 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2769 } 3065 }
2770 } 3066 }
2771#endif 3067#endif
2772#if WIDE_CHAR_VERSION && (!DCHAR_IS_TCHAR || NEED_WPRINTF_DIRECTIVE_LC) 3068#if !WIDE_CHAR_VERSION && (PTRDIFF_MAX > INT_MAX)
3069 else if (dp->conversion == 's'
3070 && a.arg[dp->arg_index].type != TYPE_WIDE_STRING)
3071 {
3072 /* %s in vasnprintf. See the specification of fprintf.
3073 We handle it ourselves here, because the string may be longer
3074 than INT_MAX characters, whence snprintf or sprintf would
3075 fail to process it. */
3076 int flags = dp->flags;
3077 int has_width;
3078 size_t width;
3079 int has_precision;
3080 size_t precision;
3081
3082 has_width = 0;
3083 width = 0;
3084 if (dp->width_start != dp->width_end)
3085 {
3086 if (dp->width_arg_index != ARG_NONE)
3087 {
3088 int arg;
3089
3090 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
3091 abort ();
3092 arg = a.arg[dp->width_arg_index].a.a_int;
3093 width = arg;
3094 if (arg < 0)
3095 {
3096 /* "A negative field width is taken as a '-' flag
3097 followed by a positive field width." */
3098 flags |= FLAG_LEFT;
3099 width = -width;
3100 }
3101 }
3102 else
3103 {
3104 const FCHAR_T *digitp = dp->width_start;
3105
3106 do
3107 width = xsum (xtimes (width, 10), *digitp++ - '0');
3108 while (digitp != dp->width_end);
3109 }
3110 if (width > (size_t) INT_MAX)
3111 goto overflow;
3112 has_width = 1;
3113 }
3114
3115 has_precision = 0;
3116 precision = 6;
3117 if (dp->precision_start != dp->precision_end)
3118 {
3119 if (dp->precision_arg_index != ARG_NONE)
3120 {
3121 int arg;
3122
3123 if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
3124 abort ();
3125 arg = a.arg[dp->precision_arg_index].a.a_int;
3126 /* "A negative precision is taken as if the precision
3127 were omitted." */
3128 if (arg >= 0)
3129 {
3130 precision = arg;
3131 has_precision = 1;
3132 }
3133 }
3134 else
3135 {
3136 const FCHAR_T *digitp = dp->precision_start + 1;
3137
3138 precision = 0;
3139 while (digitp != dp->precision_end)
3140 precision = xsum (xtimes (precision, 10), *digitp++ - '0');
3141 has_precision = 1;
3142 }
3143 }
3144
3145 {
3146 const char *arg = a.arg[dp->arg_index].a.a_string;
3147 size_t bytes;
3148# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
3149 size_t characters;
3150# endif
3151# if !DCHAR_IS_TCHAR
3152 /* This code assumes that TCHAR_T is 'char'. */
3153 static_assert (sizeof (TCHAR_T) == 1);
3154 DCHAR_T *tmpdst;
3155 size_t tmpdst_len;
3156# endif
3157 size_t w;
3158
3159 if (has_precision)
3160 {
3161 /* Use only at most PRECISION bytes, from the left. */
3162 bytes = local_strnlen (arg, precision);
3163 }
3164 else
3165 {
3166 /* Use the entire string, and count the number of
3167 bytes. */
3168 bytes = strlen (arg);
3169 }
3170
3171# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
3172 if (has_width)
3173 characters = mbsnlen (arg, bytes);
3174 else
3175 {
3176 /* The number of characters doesn't matter,
3177 because !has_width and therefore width==0. */
3178 characters = 0;
3179 }
3180# endif
3181
3182# if !DCHAR_IS_TCHAR
3183 /* Convert from TCHAR_T[] to DCHAR_T[]. */
3184 tmpdst =
3185 DCHAR_CONV_FROM_ENCODING (locale_charset (),
3186 iconveh_question_mark,
3187 arg, bytes,
3188 NULL,
3189 NULL, &tmpdst_len);
3190 if (tmpdst == NULL)
3191 goto fail_with_errno;
3192# endif
3193
3194 if (has_width)
3195 {
3196# if ENABLE_UNISTDIO
3197 /* Outside POSIX, it's preferable to compare the width
3198 against the number of _characters_ of the converted
3199 value. */
3200# if DCHAR_IS_TCHAR
3201 w = characters;
3202# else
3203 w = DCHAR_MBSNLEN (tmpdst, tmpdst_len);
3204# endif
3205# else
3206 /* The width is compared against the number of _bytes_
3207 of the converted value, says POSIX. */
3208 w = bytes;
3209# endif
3210 }
3211 else
3212 /* w doesn't matter. */
3213 w = 0;
3214
3215 {
3216# if DCHAR_IS_TCHAR
3217 size_t total = bytes + (w < width ? width - w : 0);
3218 ENSURE_ALLOCATION (xsum (length, total));
3219# else
3220 size_t total = tmpdst_len + (w < width ? width - w : 0);
3221 ENSURE_ALLOCATION_ELSE (xsum (length, total),
3222 { free (tmpdst); goto out_of_memory; });
3223# endif
3224
3225 if (w < width && !(flags & FLAG_LEFT))
3226 {
3227 size_t n = width - w;
3228 DCHAR_SET (result + length, ' ', n);
3229 length += n;
3230 }
3231
3232# if DCHAR_IS_TCHAR
3233 memcpy (result + length, arg, bytes);
3234 length += bytes;
3235# else
3236 DCHAR_CPY (result + length, tmpdst, tmpdst_len);
3237 free (tmpdst);
3238 length += tmpdst_len;
3239# endif
3240
3241 if (w < width && (flags & FLAG_LEFT))
3242 {
3243 size_t n = width - w;
3244 DCHAR_SET (result + length, ' ', n);
3245 length += n;
3246 }
3247 }
3248 }
3249 }
3250#endif
3251#if WIDE_CHAR_VERSION && ((PTRDIFF_MAX > INT_MAX) || !DCHAR_IS_TCHAR || NEED_WPRINTF_DIRECTIVE_LC)
2773 else if ((dp->conversion == 's' 3252 else if ((dp->conversion == 's'
2774 && a.arg[dp->arg_index].type == TYPE_WIDE_STRING) 3253 && a.arg[dp->arg_index].type == TYPE_WIDE_STRING)
2775 || (dp->conversion == 'c' 3254 || (dp->conversion == 'c'
@@ -2810,6 +3289,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2810 width = xsum (xtimes (width, 10), *digitp++ - '0'); 3289 width = xsum (xtimes (width, 10), *digitp++ - '0');
2811 while (digitp != dp->width_end); 3290 while (digitp != dp->width_end);
2812 } 3291 }
3292 if (width > (size_t) INT_MAX)
3293 goto overflow;
2813 } 3294 }
2814 3295
2815 { 3296 {
@@ -2912,7 +3393,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2912 } 3393 }
2913 } 3394 }
2914#endif 3395#endif
2915#if (!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T 3396#if WIDE_CHAR_VERSION || !USE_SNPRINTF || (PTRDIFF_MAX > INT_MAX) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK
2916 else if (dp->conversion == 's' 3397 else if (dp->conversion == 's'
2917# if WIDE_CHAR_VERSION 3398# if WIDE_CHAR_VERSION
2918 && a.arg[dp->arg_index].type != TYPE_WIDE_STRING 3399 && a.arg[dp->arg_index].type != TYPE_WIDE_STRING
@@ -2965,6 +3446,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2965 width = xsum (xtimes (width, 10), *digitp++ - '0'); 3446 width = xsum (xtimes (width, 10), *digitp++ - '0');
2966 while (digitp != dp->width_end); 3447 while (digitp != dp->width_end);
2967 } 3448 }
3449 if (width > (size_t) INT_MAX)
3450 goto overflow;
2968 has_width = 1; 3451 has_width = 1;
2969 } 3452 }
2970 3453
@@ -3145,11 +3628,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3145 { 3628 {
3146 const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string; 3629 const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
3147 const wchar_t *arg_end; 3630 const wchar_t *arg_end;
3631 size_t bytes;
3632# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
3148 size_t characters; 3633 size_t characters;
3634# endif
3149# if !DCHAR_IS_TCHAR 3635# if !DCHAR_IS_TCHAR
3150 /* This code assumes that TCHAR_T is 'char'. */ 3636 /* This code assumes that TCHAR_T is 'char'. */
3151 static_assert (sizeof (TCHAR_T) == 1); 3637 static_assert (sizeof (TCHAR_T) == 1);
3152 TCHAR_T *tmpsrc;
3153 DCHAR_T *tmpdst; 3638 DCHAR_T *tmpdst;
3154 size_t tmpdst_len; 3639 size_t tmpdst_len;
3155# endif 3640# endif
@@ -3164,7 +3649,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3164 mbszero (&state); 3649 mbszero (&state);
3165# endif 3650# endif
3166 arg_end = arg; 3651 arg_end = arg;
3652 bytes = 0;
3653# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
3167 characters = 0; 3654 characters = 0;
3655# endif
3168 while (precision > 0) 3656 while (precision > 0)
3169 { 3657 {
3170 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ 3658 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
@@ -3180,7 +3668,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3180 if (precision < (unsigned int) count) 3668 if (precision < (unsigned int) count)
3181 break; 3669 break;
3182 arg_end++; 3670 arg_end++;
3183 characters += count; 3671 bytes += count;
3672# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
3673 characters += mbsnlen (cbuf, count);
3674# endif
3184 precision -= count; 3675 precision -= count;
3185 } 3676 }
3186 } 3677 }
@@ -3197,7 +3688,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3197 mbszero (&state); 3688 mbszero (&state);
3198# endif 3689# endif
3199 arg_end = arg; 3690 arg_end = arg;
3691 bytes = 0;
3692# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
3200 characters = 0; 3693 characters = 0;
3694# endif
3201 for (;;) 3695 for (;;)
3202 { 3696 {
3203 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ 3697 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
@@ -3211,7 +3705,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3211 /* Cannot convert. */ 3705 /* Cannot convert. */
3212 goto fail_with_EILSEQ; 3706 goto fail_with_EILSEQ;
3213 arg_end++; 3707 arg_end++;
3214 characters += count; 3708 bytes += count;
3709# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
3710 characters += mbsnlen (cbuf, count);
3711# endif
3215 } 3712 }
3216 } 3713 }
3217# if DCHAR_IS_TCHAR 3714# if DCHAR_IS_TCHAR
@@ -3219,56 +3716,64 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3219 { 3716 {
3220 /* Use the entire string. */ 3717 /* Use the entire string. */
3221 arg_end = arg + local_wcslen (arg); 3718 arg_end = arg + local_wcslen (arg);
3222 /* The number of bytes doesn't matter. */ 3719 /* The number of bytes and characters doesn't matter,
3720 because !has_width and therefore width==0. */
3721 bytes = 0;
3722# if ENABLE_UNISTDIO
3223 characters = 0; 3723 characters = 0;
3724# endif
3224 } 3725 }
3225# endif 3726# endif
3226 3727
3227# if !DCHAR_IS_TCHAR 3728# if !DCHAR_IS_TCHAR
3228 /* Convert the string into a piece of temporary memory. */
3229 tmpsrc = (TCHAR_T *) malloc (characters * sizeof (TCHAR_T));
3230 if (tmpsrc == NULL)
3231 goto out_of_memory;
3232 { 3729 {
3233 TCHAR_T *tmpptr = tmpsrc; 3730 TCHAR_T *tmpsrc;
3234 size_t remaining; 3731
3732 /* Convert the string into a piece of temporary memory. */
3733 tmpsrc = (TCHAR_T *) malloc (bytes * sizeof (TCHAR_T));
3734 if (tmpsrc == NULL)
3735 goto out_of_memory;
3736 {
3737 TCHAR_T *tmpptr = tmpsrc;
3738 size_t remaining;
3235# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3739# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
3236 mbstate_t state; 3740 mbstate_t state;
3237 mbszero (&state); 3741 mbszero (&state);
3238# endif 3742# endif
3239 for (remaining = characters; remaining > 0; ) 3743 for (remaining = bytes; remaining > 0; )
3240 { 3744 {
3241 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ 3745 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
3242 int count; 3746 int count;
3243 3747
3244 if (*arg == 0) 3748 if (*arg == 0)
3245 abort (); 3749 abort ();
3246 count = local_wcrtomb (cbuf, *arg, &state); 3750 count = local_wcrtomb (cbuf, *arg, &state);
3247 if (count <= 0) 3751 if (count <= 0)
3248 /* Inconsistency. */ 3752 /* Inconsistency. */
3249 abort (); 3753 abort ();
3250 memcpy (tmpptr, cbuf, count); 3754 memcpy (tmpptr, cbuf, count);
3251 tmpptr += count; 3755 tmpptr += count;
3252 arg++; 3756 arg++;
3253 remaining -= count; 3757 remaining -= count;
3758 }
3759 if (!(arg == arg_end))
3760 abort ();
3761 }
3762
3763 /* Convert from TCHAR_T[] to DCHAR_T[]. */
3764 tmpdst =
3765 DCHAR_CONV_FROM_ENCODING (locale_charset (),
3766 iconveh_question_mark,
3767 tmpsrc, bytes,
3768 NULL,
3769 NULL, &tmpdst_len);
3770 if (tmpdst == NULL)
3771 {
3772 free (tmpsrc);
3773 goto fail_with_errno;
3254 } 3774 }
3255 if (!(arg == arg_end)) 3775 free (tmpsrc);
3256 abort ();
3257 } 3776 }
3258
3259 /* Convert from TCHAR_T[] to DCHAR_T[]. */
3260 tmpdst =
3261 DCHAR_CONV_FROM_ENCODING (locale_charset (),
3262 iconveh_question_mark,
3263 tmpsrc, characters,
3264 NULL,
3265 NULL, &tmpdst_len);
3266 if (tmpdst == NULL)
3267 {
3268 free (tmpsrc);
3269 goto fail_with_errno;
3270 }
3271 free (tmpsrc);
3272# endif 3777# endif
3273 3778
3274 if (has_width) 3779 if (has_width)
@@ -3277,11 +3782,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3277 /* Outside POSIX, it's preferable to compare the width 3782 /* Outside POSIX, it's preferable to compare the width
3278 against the number of _characters_ of the converted 3783 against the number of _characters_ of the converted
3279 value. */ 3784 value. */
3280 w = DCHAR_MBSNLEN (result + length, characters); 3785# if DCHAR_IS_TCHAR
3786 w = characters;
3787# else
3788 w = DCHAR_MBSNLEN (tmpdst, tmpdst_len);
3789# endif
3281# else 3790# else
3282 /* The width is compared against the number of _bytes_ 3791 /* The width is compared against the number of _bytes_
3283 of the converted value, says POSIX. */ 3792 of the converted value, says POSIX. */
3284 w = characters; 3793 w = bytes;
3285# endif 3794# endif
3286 } 3795 }
3287 else 3796 else
@@ -3291,7 +3800,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3291 if (w < width && !(flags & FLAG_LEFT)) 3800 if (w < width && !(flags & FLAG_LEFT))
3292 { 3801 {
3293 size_t n = width - w; 3802 size_t n = width - w;
3803# if DCHAR_IS_TCHAR
3294 ENSURE_ALLOCATION (xsum (length, n)); 3804 ENSURE_ALLOCATION (xsum (length, n));
3805# else
3806 ENSURE_ALLOCATION_ELSE (xsum (length, n),
3807 { free (tmpdst); goto out_of_memory; });
3808# endif
3295 DCHAR_SET (result + length, ' ', n); 3809 DCHAR_SET (result + length, ' ', n);
3296 length += n; 3810 length += n;
3297 } 3811 }
@@ -3305,8 +3819,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3305 mbstate_t state; 3819 mbstate_t state;
3306 mbszero (&state); 3820 mbszero (&state);
3307# endif 3821# endif
3308 ENSURE_ALLOCATION (xsum (length, characters)); 3822 ENSURE_ALLOCATION (xsum (length, bytes));
3309 for (remaining = characters; remaining > 0; ) 3823 for (remaining = bytes; remaining > 0; )
3310 { 3824 {
3311 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ 3825 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
3312 int count; 3826 int count;
@@ -3350,7 +3864,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3350 } 3864 }
3351# else 3865# else
3352 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len), 3866 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
3353 { free (tmpdst); goto out_of_memory; }); 3867 { free (tmpdst); goto out_of_memory; });
3354 DCHAR_CPY (result + length, tmpdst, tmpdst_len); 3868 DCHAR_CPY (result + length, tmpdst, tmpdst_len);
3355 free (tmpdst); 3869 free (tmpdst);
3356 length += tmpdst_len; 3870 length += tmpdst_len;
@@ -3406,17 +3920,21 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3406 width = xsum (xtimes (width, 10), *digitp++ - '0'); 3920 width = xsum (xtimes (width, 10), *digitp++ - '0');
3407 while (digitp != dp->width_end); 3921 while (digitp != dp->width_end);
3408 } 3922 }
3923 if (width > (size_t) INT_MAX)
3924 goto overflow;
3409 has_width = 1; 3925 has_width = 1;
3410 } 3926 }
3411 3927
3412 /* %lc in vasnprintf. See the specification of fprintf. */ 3928 /* %lc in vasnprintf. See the specification of fprintf. */
3413 { 3929 {
3414 wchar_t arg = (wchar_t) a.arg[dp->arg_index].a.a_wide_char; 3930 wchar_t arg = (wchar_t) a.arg[dp->arg_index].a.a_wide_char;
3931 size_t bytes;
3932# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
3415 size_t characters; 3933 size_t characters;
3934# endif
3416# if !DCHAR_IS_TCHAR 3935# if !DCHAR_IS_TCHAR
3417 /* This code assumes that TCHAR_T is 'char'. */ 3936 /* This code assumes that TCHAR_T is 'char'. */
3418 static_assert (sizeof (TCHAR_T) == 1); 3937 static_assert (sizeof (TCHAR_T) == 1);
3419 TCHAR_T tmpsrc[64]; /* Assume MB_CUR_MAX <= 64. */
3420 DCHAR_T *tmpdst; 3938 DCHAR_T *tmpdst;
3421 size_t tmpdst_len; 3939 size_t tmpdst_len;
3422# endif 3940# endif
@@ -3427,7 +3945,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3427# endif 3945# endif
3428 { 3946 {
3429 /* Count the number of bytes. */ 3947 /* Count the number of bytes. */
3430 characters = 0;
3431 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ 3948 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
3432 int count; 3949 int count;
3433# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3950# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
@@ -3439,43 +3956,54 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3439 if (count < 0) 3956 if (count < 0)
3440 /* Cannot convert. */ 3957 /* Cannot convert. */
3441 goto fail_with_EILSEQ; 3958 goto fail_with_EILSEQ;
3442 characters = count; 3959 bytes = count;
3960# if ENABLE_UNISTDIO && DCHAR_IS_TCHAR
3961 characters = mbsnlen (cbuf, count);
3962# endif
3443 } 3963 }
3444# if DCHAR_IS_TCHAR 3964# if DCHAR_IS_TCHAR
3445 else 3965 else
3446 { 3966 {
3447 /* The number of bytes doesn't matter. */ 3967 /* The number of bytes and characters doesn't matter,
3968 because !has_width and therefore width==0. */
3969 bytes = 0;
3970# if ENABLE_UNISTDIO
3448 characters = 0; 3971 characters = 0;
3972# endif
3449 } 3973 }
3450# endif 3974# endif
3451 3975
3452# if !DCHAR_IS_TCHAR 3976# if !DCHAR_IS_TCHAR
3453 /* Convert the string into a piece of temporary memory. */ 3977 {
3454 if (characters > 0) 3978 TCHAR_T tmpsrc[64]; /* Assume MB_CUR_MAX <= 64. */
3455 { 3979
3456 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ 3980 /* Convert the string into a piece of temporary memory. */
3457 int count; 3981 if (bytes > 0)
3982 {
3983 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
3984 int count;
3458# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3985# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
3459 mbstate_t state; 3986 mbstate_t state;
3460 mbszero (&state); 3987 mbszero (&state);
3461# endif 3988# endif
3462 3989
3463 count = local_wcrtomb (cbuf, arg, &state); 3990 count = local_wcrtomb (cbuf, arg, &state);
3464 if (count <= 0) 3991 if (count <= 0)
3465 /* Inconsistency. */ 3992 /* Inconsistency. */
3466 abort (); 3993 abort ();
3467 memcpy (tmpsrc, cbuf, count); 3994 memcpy (tmpsrc, cbuf, count);
3468 } 3995 }
3469 3996
3470 /* Convert from TCHAR_T[] to DCHAR_T[]. */ 3997 /* Convert from TCHAR_T[] to DCHAR_T[]. */
3471 tmpdst = 3998 tmpdst =
3472 DCHAR_CONV_FROM_ENCODING (locale_charset (), 3999 DCHAR_CONV_FROM_ENCODING (locale_charset (),
3473 iconveh_question_mark, 4000 iconveh_question_mark,
3474 tmpsrc, characters, 4001 tmpsrc, bytes,
3475 NULL, 4002 NULL,
3476 NULL, &tmpdst_len); 4003 NULL, &tmpdst_len);
3477 if (tmpdst == NULL) 4004 if (tmpdst == NULL)
3478 goto fail_with_errno; 4005 goto fail_with_errno;
4006 }
3479# endif 4007# endif
3480 4008
3481 if (has_width) 4009 if (has_width)
@@ -3484,11 +4012,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3484 /* Outside POSIX, it's preferable to compare the width 4012 /* Outside POSIX, it's preferable to compare the width
3485 against the number of _characters_ of the converted 4013 against the number of _characters_ of the converted
3486 value. */ 4014 value. */
3487 w = DCHAR_MBSNLEN (result + length, characters); 4015# if DCHAR_IS_TCHAR
4016 w = characters;
4017# else
4018 w = DCHAR_MBSNLEN (tmpdst, tmpdst_len);
4019# endif
3488# else 4020# else
3489 /* The width is compared against the number of _bytes_ 4021 /* The width is compared against the number of _bytes_
3490 of the converted value, says POSIX. */ 4022 of the converted value, says POSIX. */
3491 w = characters; 4023 w = bytes;
3492# endif 4024# endif
3493 } 4025 }
3494 else 4026 else
@@ -3498,7 +4030,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3498 if (w < width && !(flags & FLAG_LEFT)) 4030 if (w < width && !(flags & FLAG_LEFT))
3499 { 4031 {
3500 size_t n = width - w; 4032 size_t n = width - w;
4033# if DCHAR_IS_TCHAR
3501 ENSURE_ALLOCATION (xsum (length, n)); 4034 ENSURE_ALLOCATION (xsum (length, n));
4035# else
4036 ENSURE_ALLOCATION_ELSE (xsum (length, n),
4037 { free (tmpdst); goto out_of_memory; });
4038# endif
3502 DCHAR_SET (result + length, ' ', n); 4039 DCHAR_SET (result + length, ' ', n);
3503 length += n; 4040 length += n;
3504 } 4041 }
@@ -3507,8 +4044,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3507 if (has_width) 4044 if (has_width)
3508 { 4045 {
3509 /* We know the number of bytes in advance. */ 4046 /* We know the number of bytes in advance. */
3510 ENSURE_ALLOCATION (xsum (length, characters)); 4047 ENSURE_ALLOCATION (xsum (length, bytes));
3511 if (characters > 0) 4048 if (bytes > 0)
3512 { 4049 {
3513 int count; 4050 int count;
3514# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 4051# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
@@ -3542,7 +4079,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3542 } 4079 }
3543# else 4080# else
3544 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len), 4081 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
3545 { free (tmpdst); goto out_of_memory; }); 4082 { free (tmpdst); goto out_of_memory; });
3546 DCHAR_CPY (result + length, tmpdst, tmpdst_len); 4083 DCHAR_CPY (result + length, tmpdst, tmpdst_len);
3547 free (tmpdst); 4084 free (tmpdst);
3548 length += tmpdst_len; 4085 length += tmpdst_len;
@@ -3594,6 +4131,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3594 width = xsum (xtimes (width, 10), *digitp++ - '0'); 4131 width = xsum (xtimes (width, 10), *digitp++ - '0');
3595 while (digitp != dp->width_end); 4132 while (digitp != dp->width_end);
3596 } 4133 }
4134 if (width > (size_t) INT_MAX)
4135 goto overflow;
3597 } 4136 }
3598 4137
3599 /* %c in vasnwprintf. See the specification of fwprintf. */ 4138 /* %c in vasnwprintf. See the specification of fwprintf. */
@@ -3608,24 +4147,26 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3608 /* Invalid or incomplete multibyte character. */ 4147 /* Invalid or incomplete multibyte character. */
3609 goto fail_with_EILSEQ; 4148 goto fail_with_EILSEQ;
3610 4149
3611 if (1 < width && !(flags & FLAG_LEFT)) 4150 {
3612 { 4151 size_t total = (1 < width ? width : 1);
3613 size_t n = width - 1; 4152 ENSURE_ALLOCATION (xsum (length, total));
3614 ENSURE_ALLOCATION (xsum (length, n)); 4153
3615 DCHAR_SET (result + length, ' ', n); 4154 if (1 < width && !(flags & FLAG_LEFT))
3616 length += n; 4155 {
3617 } 4156 size_t n = width - 1;
4157 DCHAR_SET (result + length, ' ', n);
4158 length += n;
4159 }
3618 4160
3619 ENSURE_ALLOCATION (xsum (length, 1)); 4161 result[length++] = wc;
3620 result[length++] = wc;
3621 4162
3622 if (1 < width && (flags & FLAG_LEFT)) 4163 if (1 < width && (flags & FLAG_LEFT))
3623 { 4164 {
3624 size_t n = width - 1; 4165 size_t n = width - 1;
3625 ENSURE_ALLOCATION (xsum (length, n)); 4166 DCHAR_SET (result + length, ' ', n);
3626 DCHAR_SET (result + length, ' ', n); 4167 length += n;
3627 length += n; 4168 }
3628 } 4169 }
3629 } 4170 }
3630 } 4171 }
3631#endif 4172#endif
@@ -3682,6 +4223,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3682 width = xsum (xtimes (width, 10), *digitp++ - '0'); 4223 width = xsum (xtimes (width, 10), *digitp++ - '0');
3683 while (digitp != dp->width_end); 4224 while (digitp != dp->width_end);
3684 } 4225 }
4226 if (width > (size_t) INT_MAX)
4227 goto overflow;
3685 has_width = 1; 4228 has_width = 1;
3686 } 4229 }
3687 4230
@@ -3933,7 +4476,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3933 { 4476 {
3934 size_t n = xsum (length, count); 4477 size_t n = xsum (length, count);
3935 4478
3936 ENSURE_ALLOCATION (n); 4479 ENSURE_ALLOCATION_ELSE (n,
4480 { if (tmp != tmpbuf) free (tmp); goto out_of_memory; });
3937 } 4481 }
3938 4482
3939 /* Append the result. */ 4483 /* Append the result. */
@@ -3996,6 +4540,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3996 width = xsum (xtimes (width, 10), *digitp++ - '0'); 4540 width = xsum (xtimes (width, 10), *digitp++ - '0');
3997 while (digitp != dp->width_end); 4541 while (digitp != dp->width_end);
3998 } 4542 }
4543 if (width > (size_t) INT_MAX)
4544 goto overflow;
3999 } 4545 }
4000 4546
4001 has_precision = 0; 4547 has_precision = 0;
@@ -4423,7 +4969,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4423 { 4969 {
4424 size_t n = xsum (length, count); 4970 size_t n = xsum (length, count);
4425 4971
4426 ENSURE_ALLOCATION (n); 4972 ENSURE_ALLOCATION_ELSE (n,
4973 { if (tmp != tmpbuf) free (tmp); goto out_of_memory; });
4427 } 4974 }
4428 4975
4429 /* Append the result. */ 4976 /* Append the result. */
@@ -4501,6 +5048,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4501 width = xsum (xtimes (width, 10), *digitp++ - '0'); 5048 width = xsum (xtimes (width, 10), *digitp++ - '0');
4502 while (digitp != dp->width_end); 5049 while (digitp != dp->width_end);
4503 } 5050 }
5051 if (width > (size_t) INT_MAX)
5052 goto overflow;
4504 } 5053 }
4505 5054
4506 has_precision = 0; 5055 has_precision = 0;
@@ -4587,6 +5136,17 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4587 } 5136 }
4588 } 5137 }
4589# endif 5138# endif
5139 /* Account for thousands separators. */
5140 if (flags & FLAG_GROUP)
5141 {
5142 /* A thousands separator needs to be inserted at most every 2 digits.
5143 This is the case in the ta_IN locale. */
5144# if WIDE_CHAR_VERSION
5145 tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_WCHAR_MAXLEN);
5146# else
5147 tmp_length = xsum (tmp_length, tmp_length / 2 * THOUSEP_CHAR_MAXLEN);
5148# endif
5149 }
4590 /* Account for sign, decimal point etc. */ 5150 /* Account for sign, decimal point etc. */
4591 tmp_length = xsum (tmp_length, 12); 5151 tmp_length = xsum (tmp_length, 12);
4592 5152
@@ -4682,12 +5242,84 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4682 ndigits = strlen (digits); 5242 ndigits = strlen (digits);
4683 5243
4684 if (ndigits > precision) 5244 if (ndigits > precision)
4685 do 5245 {
4686 { 5246 /* Number of digits before the decimal point. */
4687 --ndigits; 5247 size_t intpart_digits = ndigits - precision;
4688 *p++ = digits[ndigits]; 5248
4689 } 5249 const DCHAR_T *thousep = NULL;
4690 while (ndigits > precision); 5250 DCHAR_T thousep_buf[10];
5251# if !WIDE_CHAR_VERSION
5252 size_t thousep_len = 0;
5253# endif
5254 const signed char *grouping;
5255 size_t insert = 0;
5256
5257 if ((flags & FLAG_GROUP) && (intpart_digits > 1))
5258 {
5259 /* Determine the thousands separator and
5260 the grouping rule of the current locale. */
5261# if WIDE_CHAR_VERSION
5262 /* DCHAR_T is wchar_t. */
5263 thousep = thousands_separator_wchar (thousep_buf);
5264# define thousep_len 1
5265# elif defined DCHAR_CONV_FROM_ENCODING
5266 /* DCHAR_T is uintN_t. */
5267 thousep = thousands_separator_DCHAR (thousep_buf);
5268 thousep_len = DCHAR_STRLEN (thousep);
5269# else
5270 /* DCHAR_T is char. */
5271 thousep = thousands_separator_char (thousep_buf);
5272 thousep_len = strlen (thousep);
5273# endif
5274 if (*thousep == 0)
5275 thousep = NULL;
5276 if (thousep != NULL)
5277 {
5278 grouping = grouping_rule ();
5279 insert =
5280 num_thousands_separators (grouping, intpart_digits);
5281 }
5282 }
5283
5284 const char *digitp = digits + precision;
5285 DCHAR_T *p_before_intpart = p;
5286 p += intpart_digits + insert * thousep_len;
5287 DCHAR_T *p_after_intpart = p;
5288 if (insert > 0) /* implies (flag & FLAG_GROUP) && (thousep != NULL) */
5289 {
5290 const signed char *g = grouping;
5291 for (;;)
5292 {
5293 int h = *g;
5294 if (h <= 0)
5295 abort ();
5296 int i = h;
5297 do
5298 *--p = *digitp++;
5299 while (--i > 0);
5300# if WIDE_CHAR_VERSION
5301 *--p = thousep[0];
5302# else
5303 p -= thousep_len;
5304 DCHAR_CPY (p, thousep, thousep_len);
5305# endif
5306 insert--;
5307 if (insert == 0)
5308 break;
5309 if (g[1] != 0)
5310 g++;
5311 }
5312 }
5313 for (;;)
5314 {
5315 *--p = *digitp++;
5316 if (p == p_before_intpart)
5317 break;
5318 }
5319 p = p_after_intpart;
5320 ndigits = precision;
5321# undef thousep_len
5322 }
4691 else 5323 else
4692 *p++ = '0'; 5324 *p++ = '0';
4693 /* Here ndigits <= precision. */ 5325 /* Here ndigits <= precision. */
@@ -4940,10 +5572,84 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4940 digits without trailing zeroes. */ 5572 digits without trailing zeroes. */
4941 if (exponent >= 0) 5573 if (exponent >= 0)
4942 { 5574 {
4943 size_t ecount = exponent + 1; 5575 /* Number of digits before the decimal point. */
4944 /* Note: count <= precision = ndigits. */ 5576 size_t intpart_digits = exponent + 1;
4945 for (; ecount > 0; ecount--) 5577 /* Note: intpart_digits <= precision = ndigits. */
4946 *p++ = digits[--ndigits]; 5578
5579 const DCHAR_T *thousep = NULL;
5580 DCHAR_T thousep_buf[10];
5581# if !WIDE_CHAR_VERSION
5582 size_t thousep_len = 0;
5583# endif
5584 const signed char *grouping;
5585 size_t insert = 0;
5586
5587 if ((flags & FLAG_GROUP) && (intpart_digits > 1))
5588 {
5589 /* Determine the thousands separator and
5590 the grouping rule of the current locale. */
5591# if WIDE_CHAR_VERSION
5592 /* DCHAR_T is wchar_t. */
5593 thousep = thousands_separator_wchar (thousep_buf);
5594# define thousep_len 1
5595# elif defined DCHAR_CONV_FROM_ENCODING
5596 /* DCHAR_T is uintN_t. */
5597 thousep = thousands_separator_DCHAR (thousep_buf);
5598 thousep_len = DCHAR_STRLEN (thousep);
5599# else
5600 /* DCHAR_T is char. */
5601 thousep = thousands_separator_char (thousep_buf);
5602 thousep_len = strlen (thousep);
5603# endif
5604 if (*thousep == 0)
5605 thousep = NULL;
5606 if (thousep != NULL)
5607 {
5608 grouping = grouping_rule ();
5609 insert =
5610 num_thousands_separators (grouping, intpart_digits);
5611 }
5612 }
5613
5614 const char *digitp = digits + ndigits - intpart_digits;
5615 DCHAR_T *p_before_intpart = p;
5616 p += intpart_digits + insert * thousep_len;
5617 DCHAR_T *p_after_intpart = p;
5618 if (insert > 0) /* implies (flag & FLAG_GROUP) && (thousep != NULL) */
5619 {
5620 const signed char *g = grouping;
5621 for (;;)
5622 {
5623 int h = *g;
5624 if (h <= 0)
5625 abort ();
5626 int i = h;
5627 do
5628 *--p = *digitp++;
5629 while (--i > 0);
5630# if WIDE_CHAR_VERSION
5631 *--p = thousep[0];
5632# else
5633 p -= thousep_len;
5634 DCHAR_CPY (p, thousep, thousep_len);
5635# endif
5636 insert--;
5637 if (insert == 0)
5638 break;
5639 if (g[1] != 0)
5640 g++;
5641 }
5642 }
5643 for (;;)
5644 {
5645 *--p = *digitp++;
5646 if (p == p_before_intpart)
5647 break;
5648 }
5649 p = p_after_intpart;
5650 ndigits -= intpart_digits;
5651# undef thousep_len
5652
4947 if ((flags & FLAG_ALT) || ndigits > nzeroes) 5653 if ((flags & FLAG_ALT) || ndigits > nzeroes)
4948 { 5654 {
4949 *p++ = decimal_point_char (); 5655 *p++ = decimal_point_char ();
@@ -5144,12 +5850,84 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5144 ndigits = strlen (digits); 5850 ndigits = strlen (digits);
5145 5851
5146 if (ndigits > precision) 5852 if (ndigits > precision)
5147 do 5853 {
5148 { 5854 /* Number of digits before the decimal point. */
5149 --ndigits; 5855 size_t intpart_digits = ndigits - precision;
5150 *p++ = digits[ndigits]; 5856
5151 } 5857 const DCHAR_T *thousep = NULL;
5152 while (ndigits > precision); 5858 DCHAR_T thousep_buf[10];
5859# if !WIDE_CHAR_VERSION
5860 size_t thousep_len = 0;
5861# endif
5862 const signed char *grouping;
5863 size_t insert = 0;
5864
5865 if ((flags & FLAG_GROUP) && (intpart_digits > 1))
5866 {
5867 /* Determine the thousands separator and
5868 the grouping rule of the current locale. */
5869# if WIDE_CHAR_VERSION
5870 /* DCHAR_T is wchar_t. */
5871 thousep = thousands_separator_wchar (thousep_buf);
5872# define thousep_len 1
5873# elif defined DCHAR_CONV_FROM_ENCODING
5874 /* DCHAR_T is uintN_t. */
5875 thousep = thousands_separator_DCHAR (thousep_buf);
5876 thousep_len = DCHAR_STRLEN (thousep);
5877# else
5878 /* DCHAR_T is char. */
5879 thousep = thousands_separator_char (thousep_buf);
5880 thousep_len = strlen (thousep);
5881# endif
5882 if (*thousep == 0)
5883 thousep = NULL;
5884 if (thousep != NULL)
5885 {
5886 grouping = grouping_rule ();
5887 insert =
5888 num_thousands_separators (grouping, intpart_digits);
5889 }
5890 }
5891
5892 const char *digitp = digits + precision;
5893 DCHAR_T *p_before_intpart = p;
5894 p += intpart_digits + insert * thousep_len;
5895 DCHAR_T *p_after_intpart = p;
5896 if (insert > 0) /* implies (flag & FLAG_GROUP) && (thousep != NULL) */
5897 {
5898 const signed char *g = grouping;
5899 for (;;)
5900 {
5901 int h = *g;
5902 if (h <= 0)
5903 abort ();
5904 int i = h;
5905 do
5906 *--p = *digitp++;
5907 while (--i > 0);
5908# if WIDE_CHAR_VERSION
5909 *--p = thousep[0];
5910# else
5911 p -= thousep_len;
5912 DCHAR_CPY (p, thousep, thousep_len);
5913# endif
5914 insert--;
5915 if (insert == 0)
5916 break;
5917 if (g[1] != 0)
5918 g++;
5919 }
5920 }
5921 for (;;)
5922 {
5923 *--p = *digitp++;
5924 if (p == p_before_intpart)
5925 break;
5926 }
5927 p = p_after_intpart;
5928 ndigits = precision;
5929# undef thousep_len
5930 }
5153 else 5931 else
5154 *p++ = '0'; 5932 *p++ = '0';
5155 /* Here ndigits <= precision. */ 5933 /* Here ndigits <= precision. */
@@ -5410,10 +6188,84 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5410 digits without trailing zeroes. */ 6188 digits without trailing zeroes. */
5411 if (exponent >= 0) 6189 if (exponent >= 0)
5412 { 6190 {
5413 size_t ecount = exponent + 1; 6191 /* Number of digits before the decimal point. */
5414 /* Note: ecount <= precision = ndigits. */ 6192 size_t intpart_digits = exponent + 1;
5415 for (; ecount > 0; ecount--) 6193 /* Note: intpart_digits <= precision = ndigits. */
5416 *p++ = digits[--ndigits]; 6194
6195 const DCHAR_T *thousep = NULL;
6196 DCHAR_T thousep_buf[10];
6197# if !WIDE_CHAR_VERSION
6198 size_t thousep_len = 0;
6199# endif
6200 const signed char *grouping;
6201 size_t insert = 0;
6202
6203 if ((flags & FLAG_GROUP) && (intpart_digits > 1))
6204 {
6205 /* Determine the thousands separator and
6206 the grouping rule of the current locale. */
6207# if WIDE_CHAR_VERSION
6208 /* DCHAR_T is wchar_t. */
6209 thousep = thousands_separator_wchar (thousep_buf);
6210# define thousep_len 1
6211# elif defined DCHAR_CONV_FROM_ENCODING
6212 /* DCHAR_T is uintN_t. */
6213 thousep = thousands_separator_DCHAR (thousep_buf);
6214 thousep_len = DCHAR_STRLEN (thousep);
6215# else
6216 /* DCHAR_T is char. */
6217 thousep = thousands_separator_char (thousep_buf);
6218 thousep_len = strlen (thousep);
6219# endif
6220 if (*thousep == 0)
6221 thousep = NULL;
6222 if (thousep != NULL)
6223 {
6224 grouping = grouping_rule ();
6225 insert =
6226 num_thousands_separators (grouping, intpart_digits);
6227 }
6228 }
6229
6230 const char *digitp = digits + ndigits - intpart_digits;
6231 DCHAR_T *p_before_intpart = p;
6232 p += intpart_digits + insert * thousep_len;
6233 DCHAR_T *p_after_intpart = p;
6234 if (insert > 0) /* implies (flag & FLAG_GROUP) && (thousep != NULL) */
6235 {
6236 const signed char *g = grouping;
6237 for (;;)
6238 {
6239 int h = *g;
6240 if (h <= 0)
6241 abort ();
6242 int i = h;
6243 do
6244 *--p = *digitp++;
6245 while (--i > 0);
6246# if WIDE_CHAR_VERSION
6247 *--p = thousep[0];
6248# else
6249 p -= thousep_len;
6250 DCHAR_CPY (p, thousep, thousep_len);
6251# endif
6252 insert--;
6253 if (insert == 0)
6254 break;
6255 if (g[1] != 0)
6256 g++;
6257 }
6258 }
6259 for (;;)
6260 {
6261 *--p = *digitp++;
6262 if (p == p_before_intpart)
6263 break;
6264 }
6265 p = p_after_intpart;
6266 ndigits -= intpart_digits;
6267# undef thousep_len
6268
5417 if ((flags & FLAG_ALT) || ndigits > nzeroes) 6269 if ((flags & FLAG_ALT) || ndigits > nzeroes)
5418 { 6270 {
5419 *p++ = decimal_point_char (); 6271 *p++ = decimal_point_char ();
@@ -5606,7 +6458,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5606 { 6458 {
5607 size_t n = xsum (length, count); 6459 size_t n = xsum (length, count);
5608 6460
5609 ENSURE_ALLOCATION (n); 6461 ENSURE_ALLOCATION_ELSE (n,
6462 { if (tmp != tmpbuf) free (tmp); goto out_of_memory; });
5610 } 6463 }
5611 6464
5612 /* Append the result. */ 6465 /* Append the result. */
@@ -5620,13 +6473,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5620 { 6473 {
5621 arg_type type = a.arg[dp->arg_index].type; 6474 arg_type type = a.arg[dp->arg_index].type;
5622 int flags = dp->flags; 6475 int flags = dp->flags;
5623#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 6476#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
5624 int has_width; 6477 int has_width;
5625#endif 6478#endif
5626#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 6479#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
5627 size_t width; 6480 size_t width;
5628#endif 6481#endif
5629#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 6482#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
5630 int has_precision; 6483 int has_precision;
5631 size_t precision; 6484 size_t precision;
5632#endif 6485#endif
@@ -5635,9 +6488,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5635#else 6488#else
5636# define prec_ourselves 0 6489# define prec_ourselves 0
5637#endif 6490#endif
6491#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
6492 int group_ourselves;
6493#else
6494# define group_ourselves 0
6495#endif
5638#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST 6496#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST
5639# define pad_ourselves 1 6497# define pad_ourselves 1
5640#elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 6498#elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
5641 int pad_ourselves; 6499 int pad_ourselves;
5642#else 6500#else
5643# define pad_ourselves 0 6501# define pad_ourselves 0
@@ -5652,10 +6510,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5652 TCHAR_T *tmp; 6510 TCHAR_T *tmp;
5653#endif 6511#endif
5654 6512
5655#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 6513#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
5656 has_width = 0; 6514 has_width = 0;
5657#endif 6515#endif
5658#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 6516#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
5659 width = 0; 6517 width = 0;
5660 if (dp->width_start != dp->width_end) 6518 if (dp->width_start != dp->width_end)
5661 { 6519 {
@@ -5683,13 +6541,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5683 width = xsum (xtimes (width, 10), *digitp++ - '0'); 6541 width = xsum (xtimes (width, 10), *digitp++ - '0');
5684 while (digitp != dp->width_end); 6542 while (digitp != dp->width_end);
5685 } 6543 }
5686# if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 6544 if (width > (size_t) INT_MAX)
6545 goto overflow;
6546# define WIDTH_IS_CHECKED 1
6547# if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
5687 has_width = 1; 6548 has_width = 1;
5688# endif 6549# endif
5689 } 6550 }
5690#endif 6551#endif
5691 6552
5692#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 6553#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
5693 has_precision = 0; 6554 has_precision = 0;
5694 precision = 6; 6555 precision = 6;
5695 if (dp->precision_start != dp->precision_end) 6556 if (dp->precision_start != dp->precision_end)
@@ -5754,8 +6615,37 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5754 } 6615 }
5755#endif 6616#endif
5756 6617
6618 /* Decide whether to add the thousands separators ourselves. */
6619#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
6620 if (flags & FLAG_GROUP)
6621 {
6622 switch (dp->conversion)
6623 {
6624 case 'd': case 'i': case 'u':
6625# if NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
6626 group_ourselves = 1;
6627# else
6628 group_ourselves = prec_ourselves;
6629# endif
6630 break;
6631 case 'f': case 'F': case 'g': case 'G':
6632# if NEED_PRINTF_FLAG_GROUPING
6633 group_ourselves = 1;
6634# else
6635 group_ourselves = prec_ourselves;
6636# endif
6637 break;
6638 default:
6639 group_ourselves = 0;
6640 break;
6641 }
6642 }
6643 else
6644 group_ourselves = 0;
6645#endif
6646
5757 /* Decide whether to perform the padding ourselves. */ 6647 /* Decide whether to perform the padding ourselves. */
5758#if !((WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST) && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION) 6648#if !((WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST) && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT)
5759 switch (dp->conversion) 6649 switch (dp->conversion)
5760 { 6650 {
5761# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO 6651# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
@@ -5772,7 +6662,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5772 pad_ourselves = 1; 6662 pad_ourselves = 1;
5773 break; 6663 break;
5774 default: 6664 default:
5775 pad_ourselves = prec_ourselves; 6665 pad_ourselves = prec_ourselves | group_ourselves;
5776 break; 6666 break;
5777 } 6667 }
5778#endif 6668#endif
@@ -5805,14 +6695,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5805 sprintf. */ 6695 sprintf. */
5806 fbp = buf; 6696 fbp = buf;
5807 *fbp++ = '%'; 6697 *fbp++ = '%';
5808#if NEED_PRINTF_FLAG_GROUPING 6698 if ((flags & FLAG_GROUP) && !group_ourselves)
5809 /* The underlying implementation doesn't support the ' flag.
5810 Produce no grouping characters in this case; this is
5811 acceptable because the grouping is locale dependent. */
5812#else
5813 if (flags & FLAG_GROUP)
5814 *fbp++ = '\''; 6699 *fbp++ = '\'';
5815#endif
5816 if (flags & FLAG_LEFT) 6700 if (flags & FLAG_LEFT)
5817 *fbp++ = '-'; 6701 *fbp++ = '-';
5818 if (flags & FLAG_SHOWSIGN) 6702 if (flags & FLAG_SHOWSIGN)
@@ -5832,6 +6716,43 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5832 if (dp->width_start != dp->width_end) 6716 if (dp->width_start != dp->width_end)
5833 { 6717 {
5834 size_t n = dp->width_end - dp->width_start; 6718 size_t n = dp->width_end - dp->width_start;
6719#if !WIDTH_IS_CHECKED
6720 size_t width;
6721 /* Reject an out-of-range width.
6722 The underlying SNPRINTF already does this on some
6723 platforms (glibc, musl, macOS, FreeBSD, NetBSD,
6724 OpenBSD, Cygwin, Solaris, MSVC). However, on others
6725 (AIX, mingw), it doesn't; thus this vasnprintf
6726 invocation would succeed and produce a wrong result.
6727 So, this is redundant on some platforms, but it's a
6728 quick check anyway. */
6729 if (dp->width_arg_index != ARG_NONE)
6730 {
6731 int arg;
6732
6733 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
6734 abort ();
6735 arg = a.arg[dp->width_arg_index].a.a_int;
6736 width = arg;
6737 if (arg < 0)
6738 {
6739 /* "A negative field width is taken as a '-' flag
6740 followed by a positive field width." */
6741 width = -width;
6742 }
6743 }
6744 else
6745 {
6746 const FCHAR_T *digitp = dp->width_start;
6747
6748 width = 0;
6749 do
6750 width = xsum (xtimes (width, 10), *digitp++ - '0');
6751 while (digitp != dp->width_end);
6752 }
6753 if (width > (size_t) INT_MAX)
6754 goto overflow;
6755#endif
5835 /* The width specification is known to consist only 6756 /* The width specification is known to consist only
5836 of standard ASCII characters. */ 6757 of standard ASCII characters. */
5837 if (sizeof (FCHAR_T) == sizeof (TCHAR_T)) 6758 if (sizeof (FCHAR_T) == sizeof (TCHAR_T))
@@ -5870,7 +6791,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5870 } 6791 }
5871 } 6792 }
5872 6793
5873 switch (type) 6794 switch (+type)
5874 { 6795 {
5875 case TYPE_LONGLONGINT: 6796 case TYPE_LONGLONGINT:
5876 case TYPE_ULONGLONGINT: 6797 case TYPE_ULONGLONGINT:
@@ -5984,9 +6905,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5984 #if HAVE_WINT_T 6905 #if HAVE_WINT_T
5985 case TYPE_WIDE_CHAR: 6906 case TYPE_WIDE_CHAR:
5986 #endif 6907 #endif
5987 #if HAVE_WCHAR_T
5988 case TYPE_WIDE_STRING: 6908 case TYPE_WIDE_STRING:
5989 #endif
5990 *fbp++ = 'l'; 6909 *fbp++ = 'l';
5991 break; 6910 break;
5992 case TYPE_LONGDOUBLE: 6911 case TYPE_LONGDOUBLE:
@@ -6168,7 +7087,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
6168#endif 7087#endif
6169 7088
6170 errno = 0; 7089 errno = 0;
6171 switch (type) 7090 switch (+type)
6172 { 7091 {
6173 case TYPE_SCHAR: 7092 case TYPE_SCHAR:
6174 { 7093 {
@@ -6358,14 +7277,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
6358 SNPRINTF_BUF (arg); 7277 SNPRINTF_BUF (arg);
6359 } 7278 }
6360 break; 7279 break;
6361#if HAVE_WCHAR_T
6362 case TYPE_WIDE_STRING: 7280 case TYPE_WIDE_STRING:
6363 { 7281 {
6364 const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string; 7282 const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
6365 SNPRINTF_BUF (arg); 7283 SNPRINTF_BUF (arg);
6366 } 7284 }
6367 break; 7285 break;
6368#endif
6369 case TYPE_POINTER: 7286 case TYPE_POINTER:
6370 { 7287 {
6371 void *arg = a.arg[dp->arg_index].a.a_pointer; 7288 void *arg = a.arg[dp->arg_index].a.a_pointer;
@@ -6539,10 +7456,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
6539 || *prec_ptr == ' ')) 7456 || *prec_ptr == ' '))
6540 prefix_count = 1; 7457 prefix_count = 1;
6541 /* Put the additional zeroes after the 0x prefix if 7458 /* Put the additional zeroes after the 0x prefix if
6542 (flags & FLAG_ALT) || (dp->conversion == 'p'). */ 7459 (flags & FLAG_ALT) || (dp->conversion == 'p'), or
7460 after the 0b prefix if (flags & FLAG_ALT). */
6543 else if (count >= 2 7461 else if (count >= 2
6544 && prec_ptr[0] == '0' 7462 && prec_ptr[0] == '0'
6545 && (prec_ptr[1] == 'x' || prec_ptr[1] == 'X')) 7463 && (prec_ptr[1] == 'x' || prec_ptr[1] == 'X'
7464 || prec_ptr[1] == 'b'
7465 || prec_ptr[1] == 'B'))
6546 prefix_count = 2; 7466 prefix_count = 2;
6547 7467
6548 move = count - prefix_count; 7468 move = count - prefix_count;
@@ -6591,6 +7511,135 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
6591 } 7511 }
6592#endif 7512#endif
6593 7513
7514#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
7515 if (group_ourselves) /* implies (flags & FLAG_GROUP) */
7516 /* Handle the grouping. */
7517 switch (dp->conversion)
7518 {
7519 /* These are the only conversion to which grouping
7520 applies. */
7521 case 'd': case 'i': case 'u':
7522 case 'f': case 'F': case 'g': case 'G':
7523 {
7524 /* Determine the thousands separator of the current
7525 locale. */
7526 const TCHAR_T *thousep;
7527 TCHAR_T thousep_buf[10];
7528
7529# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
7530 /* TCHAR_T is wchar_t. */
7531 thousep = thousands_separator_wchar (thousep_buf);
7532# else
7533 /* TCHAR_T is char. */
7534 thousep = thousands_separator_char (thousep_buf);
7535# endif
7536
7537 /* Nothing to do in locales where thousep is the empty
7538 string. */
7539 if (*thousep != 0)
7540 {
7541 /* Since FLAG_LOCALIZED is only supported on glibc
7542 systems, here we can assume that all digits are
7543 the ASCII digits '0'..'9'. */
7544 TCHAR_T *number_ptr =
7545# if USE_SNPRINTF
7546 (TCHAR_T *) (result + length);
7547# else
7548 tmp;
7549# endif
7550 TCHAR_T *end_ptr = number_ptr + count;
7551
7552 /* Find where the leading digits start. */
7553 TCHAR_T *digits_ptr = number_ptr;
7554 if (count >= 1
7555 && (*digits_ptr == '-' || *digits_ptr == '+'
7556 || *digits_ptr == ' '))
7557 digits_ptr++;
7558
7559 /* Find where the leading digits end. */
7560 TCHAR_T *digits_end_ptr;
7561 switch (dp->conversion)
7562 {
7563 case 'd': case 'i': case 'u':
7564 digits_end_ptr = end_ptr;
7565 break;
7566 case 'f': case 'F': case 'g': case 'G':
7567 {
7568 TCHAR_T decimal_point = decimal_point_char ();
7569 for (digits_end_ptr = digits_ptr;
7570 digits_end_ptr < end_ptr;
7571 digits_end_ptr++)
7572 if (*digits_end_ptr == decimal_point
7573 || *digits_end_ptr == 'e')
7574 break;
7575 }
7576 break;
7577 }
7578
7579 /* Determine the number of thousands separators
7580 to insert. */
7581 const signed char *grouping = grouping_rule ();
7582 size_t insert =
7583 num_thousands_separators (grouping, digits_end_ptr - digits_ptr);
7584 if (insert > 0)
7585 {
7586# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
7587# define thousep_len 1
7588# else
7589 size_t thousep_len = strlen (thousep);
7590# endif
7591# if USE_SNPRINTF
7592 size_t digits_offset = digits_ptr - number_ptr;
7593 size_t digits_end_offset = digits_end_ptr - number_ptr;
7594 size_t n =
7595 xsum (length,
7596 (count + insert * thousep_len + TCHARS_PER_DCHAR - 1)
7597 / TCHARS_PER_DCHAR);
7598 length += (count + TCHARS_PER_DCHAR - 1) / TCHARS_PER_DCHAR;
7599 ENSURE_ALLOCATION (n);
7600 length -= (count + TCHARS_PER_DCHAR - 1) / TCHARS_PER_DCHAR;
7601 number_ptr = (TCHAR_T *) (result + length);
7602 end_ptr = number_ptr + count;
7603 digits_ptr = number_ptr + digits_offset;
7604 digits_end_ptr = number_ptr + digits_end_offset;
7605# endif
7606
7607 count += insert * thousep_len;
7608
7609 const TCHAR_T *p = end_ptr;
7610 TCHAR_T *q = end_ptr + insert * thousep_len;
7611 while (p > digits_end_ptr)
7612 *--q = *--p;
7613 const signed char *g = grouping;
7614 for (;;)
7615 {
7616 int h = *g;
7617 if (h <= 0)
7618 abort ();
7619 int i = h;
7620 do
7621 *--q = *--p;
7622 while (--i > 0);
7623# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
7624 *--q = *thousep;
7625# else
7626 q -= thousep_len;
7627 memcpy (q, thousep, thousep_len);
7628# endif
7629 insert--;
7630 if (insert == 0)
7631 break;
7632 if (g[1] != 0)
7633 g++;
7634 }
7635 /* Here q == p. Done with the insertions. */
7636 }
7637 }
7638 }
7639 break;
7640 }
7641#endif
7642
6594#if !USE_SNPRINTF 7643#if !USE_SNPRINTF
6595 if (count >= tmp_length) 7644 if (count >= tmp_length)
6596 /* tmp_length was incorrectly calculated - fix the 7645 /* tmp_length was incorrectly calculated - fix the
@@ -6601,6 +7650,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
6601#if !DCHAR_IS_TCHAR 7650#if !DCHAR_IS_TCHAR
6602 /* Convert from TCHAR_T[] to DCHAR_T[]. */ 7651 /* Convert from TCHAR_T[] to DCHAR_T[]. */
6603 if (dp->conversion == 'c' || dp->conversion == 's' 7652 if (dp->conversion == 'c' || dp->conversion == 's'
7653 || (flags & FLAG_GROUP)
6604# if __GLIBC__ >= 2 && !defined __UCLIBC__ 7654# if __GLIBC__ >= 2 && !defined __UCLIBC__
6605 || (flags & FLAG_LOCALIZED) 7655 || (flags & FLAG_LOCALIZED)
6606# endif 7656# endif
@@ -6677,7 +7727,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
6677 goto fail_with_errno; 7727 goto fail_with_errno;
6678# endif 7728# endif
6679 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len), 7729 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
6680 { free (tmpdst); goto out_of_memory; }); 7730 { free (tmpdst); goto out_of_memory; });
6681 DCHAR_CPY (result + length, tmpdst, tmpdst_len); 7731 DCHAR_CPY (result + length, tmpdst, tmpdst_len);
6682 free (tmpdst); 7732 free (tmpdst);
6683 count = tmpdst_len; 7733 count = tmpdst_len;
@@ -6742,7 +7792,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
6742 /* Here count <= allocated - length. */ 7792 /* Here count <= allocated - length. */
6743 7793
6744 /* Perform padding. */ 7794 /* Perform padding. */
6745#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 7795#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION || NEED_PRINTF_FLAG_GROUPING || NEED_PRINTF_FLAG_GROUPING_INT
6746 if (pad_ourselves && has_width) 7796 if (pad_ourselves && has_width)
6747 { 7797 {
6748 size_t w; 7798 size_t w;
@@ -6751,6 +7801,23 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
6751 against the number of _characters_ of the converted 7801 against the number of _characters_ of the converted
6752 value. */ 7802 value. */
6753 w = DCHAR_MBSNLEN (result + length, count); 7803 w = DCHAR_MBSNLEN (result + length, count);
7804# elif __GLIBC__ >= 2
7805 /* glibc prefers to compare the width against the number
7806 of characters as well, but only for numeric conversion
7807 specifiers. See
7808 <https://sourceware.org/bugzilla/show_bug.cgi?id=28943>
7809 <https://sourceware.org/bugzilla/show_bug.cgi?id=30883>
7810 <https://sourceware.org/bugzilla/show_bug.cgi?id=31542> */
7811 switch (dp->conversion)
7812 {
7813 case 'd': case 'i': case 'u':
7814 case 'f': case 'F': case 'g': case 'G':
7815 w = DCHAR_MBSNLEN (result + length, count);
7816 break;
7817 default:
7818 w = count;
7819 break;
7820 }
6754# else 7821# else
6755 /* The width is compared against the number of _bytes_ 7822 /* The width is compared against the number of _bytes_
6756 of the converted value, says POSIX. */ 7823 of the converted value, says POSIX. */
@@ -6929,17 +7996,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
6929 not have this limitation. */ 7996 not have this limitation. */
6930 return result; 7997 return result;
6931 7998
6932#if USE_SNPRINTF
6933 overflow: 7999 overflow:
6934 errno = EOVERFLOW; 8000 errno = EOVERFLOW;
6935 goto fail_with_errno; 8001 goto fail_with_errno;
6936#endif
6937 8002
6938 out_of_memory: 8003 out_of_memory:
6939 errno = ENOMEM; 8004 errno = ENOMEM;
6940 goto fail_with_errno; 8005 goto fail_with_errno;
6941 8006
6942#if ENABLE_UNISTDIO || ((!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) || ((NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T && !WIDE_CHAR_VERSION) || (NEED_WPRINTF_DIRECTIVE_C && WIDE_CHAR_VERSION) 8007#if ENABLE_UNISTDIO || (WIDE_CHAR_VERSION || !USE_SNPRINTF || (PTRDIFF_MAX > INT_MAX) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) || ((NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T && !WIDE_CHAR_VERSION) || (NEED_WPRINTF_DIRECTIVE_C && WIDE_CHAR_VERSION)
6943 fail_with_EILSEQ: 8008 fail_with_EILSEQ:
6944 errno = EILSEQ; 8009 errno = EILSEQ;
6945 goto fail_with_errno; 8010 goto fail_with_errno;
diff --git a/gl/vasnprintf.h b/gl/vasnprintf.h
index 7ed9145c..ccd60e5e 100644
--- a/gl/vasnprintf.h
+++ b/gl/vasnprintf.h
@@ -1,5 +1,5 @@
1/* vsprintf with automatic memory allocation. 1/* vsprintf with automatic memory allocation.
2 Copyright (C) 2002-2004, 2007-2024 Free Software Foundation, Inc. 2 Copyright (C) 2002-2004, 2007-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/vasprintf.c b/gl/vasprintf.c
index e52aaca5..30aa4469 100644
--- a/gl/vasprintf.c
+++ b/gl/vasprintf.c
@@ -1,5 +1,5 @@
1/* Formatted output to strings. 1/* Formatted output to strings.
2 Copyright (C) 1999, 2002, 2006-2024 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2002, 2006-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -25,6 +25,7 @@
25 25
26#include <errno.h> 26#include <errno.h>
27#include <limits.h> 27#include <limits.h>
28#include <stdint.h>
28#include <stdlib.h> 29#include <stdlib.h>
29 30
30#include "vasnprintf.h" 31#include "vasnprintf.h"
@@ -37,12 +38,21 @@ vasprintf (char **resultp, const char *format, va_list args)
37 if (result == NULL) 38 if (result == NULL)
38 return -1; 39 return -1;
39 40
41#if PTRDIFF_MAX > INT_MAX
40 if (length > INT_MAX) 42 if (length > INT_MAX)
41 { 43 {
42 free (result); 44 free (result);
43 errno = EOVERFLOW; 45 errno = (length > PTRDIFF_MAX ? ENOMEM : EOVERFLOW);
44 return -1; 46 return -1;
45 } 47 }
48#else
49 if (length > PTRDIFF_MAX)
50 {
51 free (result);
52 errno = ENOMEM;
53 return -1;
54 }
55#endif
46 56
47 *resultp = result; 57 *resultp = result;
48 /* Return the number of resulting bytes, excluding the trailing NUL. */ 58 /* Return the number of resulting bytes, excluding the trailing NUL. */
diff --git a/gl/verify.h b/gl/verify.h
index 08268c24..3b01d7c2 100644
--- a/gl/verify.h
+++ b/gl/verify.h
@@ -1,6 +1,6 @@
1/* Compile-time assert-like macros. 1/* Compile-time assert-like macros.
2 2
3 Copyright (C) 2005-2006, 2009-2024 Free Software Foundation, Inc. 3 Copyright (C) 2005-2006, 2009-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -34,11 +34,12 @@
34#ifndef __cplusplus 34#ifndef __cplusplus
35# if (201112 <= __STDC_VERSION__ \ 35# if (201112 <= __STDC_VERSION__ \
36 || (!defined __STRICT_ANSI__ \ 36 || (!defined __STRICT_ANSI__ \
37 && (4 < __GNUC__ + (6 <= __GNUC_MINOR__) || 5 <= __clang_major__))) 37 && ((4 < __GNUC__ + (6 <= __GNUC_MINOR__) && !defined __clang__) \
38 || 5 <= __clang_major__)))
38# define _GL_HAVE__STATIC_ASSERT 1 39# define _GL_HAVE__STATIC_ASSERT 1
39# endif 40# endif
40# if (202311 <= __STDC_VERSION__ \ 41# if (202311 <= __STDC_VERSION__ \
41 || (!defined __STRICT_ANSI__ && 9 <= __GNUC__)) 42 || (!defined __STRICT_ANSI__ && 9 <= __GNUC__ && !defined __clang__))
42# define _GL_HAVE__STATIC_ASSERT1 1 43# define _GL_HAVE__STATIC_ASSERT1 1
43# endif 44# endif
44#endif 45#endif
@@ -156,9 +157,10 @@
156#define _GL_CONCAT0(x, y) x##y 157#define _GL_CONCAT0(x, y) x##y
157 158
158/* _GL_COUNTER is an integer, preferably one that changes each time we 159/* _GL_COUNTER is an integer, preferably one that changes each time we
159 use it. Use __COUNTER__ if it works, falling back on __LINE__ 160 use it. Use __COUNTER__ if it works (it does so with most compilers,
160 otherwise. __LINE__ isn't perfect, but it's better than a 161 see <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3457.htm>),
161 constant. */ 162 falling back on __LINE__ otherwise. __LINE__ isn't perfect, but it's
163 better than a constant. */
162#if defined __COUNTER__ && __COUNTER__ != __COUNTER__ 164#if defined __COUNTER__ && __COUNTER__ != __COUNTER__
163# define _GL_COUNTER __COUNTER__ 165# define _GL_COUNTER __COUNTER__
164#else 166#else
@@ -215,7 +217,7 @@ template <int w>
215# define _GL_VERIFY(R, DIAGNOSTIC, ...) \ 217# define _GL_VERIFY(R, DIAGNOSTIC, ...) \
216 extern int (*_GL_GENSYM (_gl_verify_function) (void)) \ 218 extern int (*_GL_GENSYM (_gl_verify_function) (void)) \
217 [_GL_VERIFY_TRUE (R, DIAGNOSTIC)] 219 [_GL_VERIFY_TRUE (R, DIAGNOSTIC)]
218# if 4 < __GNUC__ + (6 <= __GNUC_MINOR__) 220# if 4 < __GNUC__ + (6 <= __GNUC_MINOR__) && !defined __clang__
219# pragma GCC diagnostic ignored "-Wnested-externs" 221# pragma GCC diagnostic ignored "-Wnested-externs"
220# endif 222# endif
221#endif 223#endif
@@ -254,16 +256,32 @@ template <int w>
254# endif 256# endif
255# endif 257# endif
256/* Define static_assert if needed. */ 258/* Define static_assert if needed. */
259# if defined __cplusplus && defined __clang__ && __clang_major__ < 9
260/* clang++ before commit 5c739665a8721228cf6143fd4ef95870a59f55ae had a
261 two-arguments static_assert but not the one-argument static_assert. */
262# undef static_assert
263# endif
257# if (!defined static_assert \ 264# if (!defined static_assert \
258 && __STDC_VERSION__ < 202311 \ 265 && __STDC_VERSION__ < 202311 \
259 && (!defined __cplusplus \ 266 && (!defined __cplusplus \
260 || (__cpp_static_assert < 201411 \ 267 || (__cpp_static_assert < 201411 \
261 && __GNUG__ < 6 && __clang_major__ < 6 && _MSC_VER < 1910))) 268 && __GNUG__ < 6 && __clang_major__ < 6 && _MSC_VER < 1910)))
262# if defined __cplusplus && _MSC_VER >= 1900 && !defined __clang__ 269# if (defined __cplusplus && defined __GNUG__ && __GNUG__ < 6 \
270 && __cplusplus == 201103L && !defined __clang__)
271/* g++ >= 4.7, < 6 with option -std=c++11 or -std=gnu++11 supports the
272 two-arguments static_assert but not the one-argument static_assert, and
273 it does not support _Static_assert.
274 We have to play preprocessor tricks to distinguish the two cases. */
275# define _GL_SA1(a1) static_assert ((a1), "static assertion failed")
276# define _GL_SA2 static_assert
277# define _GL_SA3 static_assert
278# define _GL_SA_PICK(x1,x2,x3,x4,...) x4
279# define static_assert(...) _GL_SA_PICK(__VA_ARGS__,_GL_SA3,_GL_SA2,_GL_SA1) (__VA_ARGS__)
280# elif defined __cplusplus && _MSC_VER >= 1900 && !defined __clang__
263/* MSVC 14 in C++ mode supports the two-arguments static_assert but not 281/* MSVC 14 in C++ mode supports the two-arguments static_assert but not
264 the one-argument static_assert, and it does not support _Static_assert. 282 the one-argument static_assert, and it does not support _Static_assert.
265 We have to play preprocessor tricks to distinguish the two cases. 283 We have to play preprocessor tricks to distinguish the two cases.
266 Since the MSVC preprocessor is not ISO C compliant (see above),. 284 Since the MSVC preprocessor is not ISO C compliant (see above),
267 the solution is specific to MSVC. */ 285 the solution is specific to MSVC. */
268# define _GL_EXPAND(x) x 286# define _GL_EXPAND(x) x
269# define _GL_SA1(a1) static_assert ((a1), "static assertion failed") 287# define _GL_SA1(a1) static_assert ((a1), "static assertion failed")
@@ -294,7 +312,7 @@ template <int w>
294#ifndef _GL_HAS_BUILTIN_UNREACHABLE 312#ifndef _GL_HAS_BUILTIN_UNREACHABLE
295# if defined __clang_major__ && __clang_major__ < 5 313# if defined __clang_major__ && __clang_major__ < 5
296# define _GL_HAS_BUILTIN_UNREACHABLE 0 314# define _GL_HAS_BUILTIN_UNREACHABLE 0
297# elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__) 315# elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__) && !defined __clang__
298# define _GL_HAS_BUILTIN_UNREACHABLE 1 316# define _GL_HAS_BUILTIN_UNREACHABLE 1
299# elif defined __has_builtin 317# elif defined __has_builtin
300# define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable) 318# define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable)
diff --git a/gl/vsnprintf.c b/gl/vsnprintf.c
index e6676a1f..d3d7ef7a 100644
--- a/gl/vsnprintf.c
+++ b/gl/vsnprintf.c
@@ -1,6 +1,5 @@
1/* Formatted output to strings. 1/* Formatted output to strings.
2 Copyright (C) 2004, 2006-2024 Free Software Foundation, Inc. 2 Copyright (C) 2004, 2006-2025 Free Software Foundation, Inc.
3 Written by Simon Josefsson and Yoann Vandoorselaere <yoann@prelude-ids.org>.
4 3
5 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -25,46 +24,20 @@
25#include <errno.h> 24#include <errno.h>
26#include <limits.h> 25#include <limits.h>
27#include <stdarg.h> 26#include <stdarg.h>
28#include <stdlib.h> 27#include <stdint.h>
29#include <string.h>
30 28
31#include "vasnprintf.h"
32
33/* Print formatted output to string STR. Similar to vsprintf, but
34 additional length SIZE limit how much is written into STR. Returns
35 string length of formatted string (which may be larger than SIZE).
36 STR may be NULL, in which case nothing will be written. On error,
37 return a negative value. */
38int 29int
39vsnprintf (char *str, size_t size, const char *format, va_list args) 30vsnprintf (char *str, size_t size, const char *format, va_list args)
40{ 31{
41 char *output; 32 ptrdiff_t ret = vsnzprintf (str, size, format, args);
42 size_t len;
43 size_t lenbuf = size;
44
45 output = vasnprintf (str, &lenbuf, format, args);
46 len = lenbuf;
47
48 if (!output)
49 return -1;
50
51 if (output != str)
52 {
53 if (size)
54 {
55 size_t pruned_len = (len < size ? len : size - 1);
56 memcpy (str, output, pruned_len);
57 str[pruned_len] = '\0';
58 }
59
60 free (output);
61 }
62 33
63 if (len > INT_MAX) 34#if PTRDIFF_MAX > INT_MAX
35 if (ret > INT_MAX)
64 { 36 {
65 errno = EOVERFLOW; 37 errno = EOVERFLOW;
66 return -1; 38 return -1;
67 } 39 }
40#endif
68 41
69 return len; 42 return ret;
70} 43}
diff --git a/gl/vsnzprintf.c b/gl/vsnzprintf.c
new file mode 100644
index 00000000..f6e6b1d4
--- /dev/null
+++ b/gl/vsnzprintf.c
@@ -0,0 +1,65 @@
1/* Formatted output to strings.
2 Copyright (C) 2004, 2006-2025 Free Software Foundation, Inc.
3 Written by Simon Josefsson and Yoann Vandoorselaere <yoann@prelude-ids.org>.
4
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 This file 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22/* Specification. */
23#include <stdio.h>
24
25#include <errno.h>
26#include <stdarg.h>
27#include <stdint.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include "vasnprintf.h"
32
33ptrdiff_t
34vsnzprintf (char *str, size_t size, const char *format, va_list args)
35{
36 char *output;
37 size_t len;
38 size_t lenbuf = size;
39
40 output = vasnprintf (str, &lenbuf, format, args);
41 len = lenbuf;
42
43 if (!output)
44 return -1;
45
46 if (output != str)
47 {
48 if (size)
49 {
50 size_t pruned_len = (len < size ? len : size - 1);
51 memcpy (str, output, pruned_len);
52 str[pruned_len] = '\0';
53 }
54
55 free (output);
56 }
57
58 if (len > PTRDIFF_MAX)
59 {
60 errno = ENOMEM;
61 return -1;
62 }
63
64 return len;
65}
diff --git a/gl/w32sock.h b/gl/w32sock.h
index 166a5f77..d7087a28 100644
--- a/gl/w32sock.h
+++ b/gl/w32sock.h
@@ -1,6 +1,6 @@
1/* w32sock.h --- internal auxiliary functions for Windows socket functions 1/* w32sock.h --- internal auxiliary functions for Windows socket functions
2 2
3 Copyright (C) 2008-2024 Free Software Foundation, Inc. 3 Copyright (C) 2008-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/warn-on-use.h b/gl/warn-on-use.h
index 701013a0..c0072412 100644
--- a/gl/warn-on-use.h
+++ b/gl/warn-on-use.h
@@ -1,5 +1,5 @@
1/* A C macro for emitting warnings if a function is used. 1/* A C macro for emitting warnings if a function is used.
2 Copyright (C) 2010-2024 Free Software Foundation, Inc. 2 Copyright (C) 2010-2025 Free Software Foundation, Inc.
3 3
4 This program is free software: you can redistribute it and/or modify it 4 This program is free software: you can redistribute it and/or modify it
5 under the terms of the GNU Lesser General Public License as published 5 under the terms of the GNU Lesser General Public License as published
@@ -85,7 +85,7 @@
85 */ 85 */
86#ifndef _GL_WARN_ON_USE 86#ifndef _GL_WARN_ON_USE
87 87
88# if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) 88# if (4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)) && !defined __clang__
89/* A compiler attribute is available in gcc versions 4.3.0 and later. */ 89/* A compiler attribute is available in gcc versions 4.3.0 and later. */
90# define _GL_WARN_ON_USE(function, message) \ 90# define _GL_WARN_ON_USE(function, message) \
91_GL_WARN_EXTERN_C __typeof__ (function) function __attribute__ ((__warning__ (message))) 91_GL_WARN_EXTERN_C __typeof__ (function) function __attribute__ ((__warning__ (message)))
@@ -98,7 +98,7 @@ _GL_WARN_EXTERN_C __typeof__ (function) function \
98 __attribute__ ((__diagnose_if__ (1, message, "warning"))) 98 __attribute__ ((__diagnose_if__ (1, message, "warning")))
99# define _GL_WARN_ON_USE_ATTRIBUTE(message) \ 99# define _GL_WARN_ON_USE_ATTRIBUTE(message) \
100 __attribute__ ((__diagnose_if__ (1, message, "warning"))) 100 __attribute__ ((__diagnose_if__ (1, message, "warning")))
101# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING 101# elif (__GNUC__ >= 3 || defined __clang__) && GNULIB_STRICT_CHECKING
102/* Verify the existence of the function. */ 102/* Verify the existence of the function. */
103# define _GL_WARN_ON_USE(function, message) \ 103# define _GL_WARN_ON_USE(function, message) \
104_GL_WARN_EXTERN_C __typeof__ (function) function 104_GL_WARN_EXTERN_C __typeof__ (function) function
@@ -121,7 +121,7 @@ _GL_WARN_EXTERN_C int _gl_warn_on_use
121# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \ 121# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
122 _GL_WARN_ON_USE (function, msg) 122 _GL_WARN_ON_USE (function, msg)
123# else 123# else
124# if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) 124# if (4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)) && !defined __clang__
125/* A compiler attribute is available in gcc versions 4.3.0 and later. */ 125/* A compiler attribute is available in gcc versions 4.3.0 and later. */
126# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \ 126# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
127extern rettype_gcc function parameters_and_attributes \ 127extern rettype_gcc function parameters_and_attributes \
@@ -131,7 +131,7 @@ extern rettype_gcc function parameters_and_attributes \
131# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \ 131# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
132extern rettype_clang function parameters_and_attributes \ 132extern rettype_clang function parameters_and_attributes \
133 __attribute__ ((__diagnose_if__ (1, msg, "warning"))) 133 __attribute__ ((__diagnose_if__ (1, msg, "warning")))
134# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING 134# elif (__GNUC__ >= 3 || defined __clang__) && GNULIB_STRICT_CHECKING
135/* Verify the existence of the function. */ 135/* Verify the existence of the function. */
136# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \ 136# define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \
137extern rettype_gcc function parameters_and_attributes 137extern rettype_gcc function parameters_and_attributes
diff --git a/gl/wchar.in.h b/gl/wchar.in.h
index a33a10f7..a6c52eb9 100644
--- a/gl/wchar.in.h
+++ b/gl/wchar.in.h
@@ -1,6 +1,6 @@
1/* A substitute for ISO C99 <wchar.h>, for platforms that have issues. 1/* A substitute for ISO C99 <wchar.h>, for platforms that have issues.
2 2
3 Copyright (C) 2007-2024 Free Software Foundation, Inc. 3 Copyright (C) 2007-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -37,7 +37,7 @@
37 && !defined _GL_FINISHED_INCLUDING_SYSTEM_INTTYPES_H) \ 37 && !defined _GL_FINISHED_INCLUDING_SYSTEM_INTTYPES_H) \
38 || defined _GL_JUST_INCLUDE_SYSTEM_WCHAR_H)) \ 38 || defined _GL_JUST_INCLUDE_SYSTEM_WCHAR_H)) \
39 || (defined __MINGW32__ && defined __STRING_H_SOURCED__) \ 39 || (defined __MINGW32__ && defined __STRING_H_SOURCED__) \
40 || defined _GL_ALREADY_INCLUDING_WCHAR_H) 40 || defined _@GUARD_PREFIX@_ALREADY_INCLUDING_WCHAR_H)
41/* Special invocation convention: 41/* Special invocation convention:
42 - Inside glibc and uClibc header files, but not MinGW. 42 - Inside glibc and uClibc header files, but not MinGW.
43 - On HP-UX 11.00 we have a sequence of nested includes 43 - On HP-UX 11.00 we have a sequence of nested includes
@@ -53,13 +53,16 @@
53 <wctype.h> is completely included or is still being included. */ 53 <wctype.h> is completely included or is still being included. */
54 54
55#@INCLUDE_NEXT@ @NEXT_WCHAR_H@ 55#@INCLUDE_NEXT@ @NEXT_WCHAR_H@
56/* The glibc 2.5 /usr/include/wchar.h defines __need_wint_t but never undefines
57 it. We need to do that here. */
58#undef __need_wint_t
56 59
57#else 60#else
58/* Normal invocation convention. */ 61/* Normal invocation convention. */
59 62
60#ifndef _@GUARD_PREFIX@_WCHAR_H 63#ifndef _@GUARD_PREFIX@_WCHAR_H
61 64
62#define _GL_ALREADY_INCLUDING_WCHAR_H 65#define _@GUARD_PREFIX@_ALREADY_INCLUDING_WCHAR_H
63 66
64#if @HAVE_FEATURES_H@ 67#if @HAVE_FEATURES_H@
65# include <features.h> /* for __GLIBC__ */ 68# include <features.h> /* for __GLIBC__ */
@@ -79,7 +82,7 @@
79# @INCLUDE_NEXT@ @NEXT_WCHAR_H@ 82# @INCLUDE_NEXT@ @NEXT_WCHAR_H@
80#endif 83#endif
81 84
82#undef _GL_ALREADY_INCLUDING_WCHAR_H 85#undef _@GUARD_PREFIX@_ALREADY_INCLUDING_WCHAR_H
83 86
84#ifndef _@GUARD_PREFIX@_WCHAR_H 87#ifndef _@GUARD_PREFIX@_WCHAR_H
85#define _@GUARD_PREFIX@_WCHAR_H 88#define _@GUARD_PREFIX@_WCHAR_H
@@ -95,7 +98,7 @@
95 that can be freed by passing them as the Ith argument to the 98 that can be freed by passing them as the Ith argument to the
96 function F. */ 99 function F. */
97#ifndef _GL_ATTRIBUTE_DEALLOC 100#ifndef _GL_ATTRIBUTE_DEALLOC
98# if __GNUC__ >= 11 101# if __GNUC__ >= 11 && !defined __clang__
99# define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i))) 102# define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i)))
100# else 103# else
101# define _GL_ATTRIBUTE_DEALLOC(f, i) 104# define _GL_ATTRIBUTE_DEALLOC(f, i)
@@ -137,11 +140,23 @@
137# endif 140# endif
138#endif 141#endif
139 142
143/* _GL_ATTRIBUTE_NONNULL_IF_NONZERO (NP, NI) declares that the argument NP
144 (a pointer) must not be NULL if the argument NI (an integer) is != 0. */
145/* Applies to: functions. */
146#ifndef _GL_ATTRIBUTE_NONNULL_IF_NONZERO
147# if __GNUC__ >= 15 && !defined __clang__
148# define _GL_ATTRIBUTE_NONNULL_IF_NONZERO(np, ni) \
149 __attribute__ ((__nonnull_if_nonzero__ (np, ni)))
150# else
151# define _GL_ATTRIBUTE_NONNULL_IF_NONZERO(np, ni)
152# endif
153#endif
154
140/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions. 155/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions.
141 */ 156 */
142#ifndef _GL_ATTRIBUTE_NOTHROW 157#ifndef _GL_ATTRIBUTE_NOTHROW
143# if defined __cplusplus 158# if defined __cplusplus
144# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major >= 4 159# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major__ >= 4
145# if __cplusplus >= 201103L 160# if __cplusplus >= 201103L
146# define _GL_ATTRIBUTE_NOTHROW noexcept (true) 161# define _GL_ATTRIBUTE_NOTHROW noexcept (true)
147# else 162# else
@@ -198,11 +213,12 @@ typedef unsigned int rpl_wint_t;
198/* Override mbstate_t if it is too small. 213/* Override mbstate_t if it is too small.
199 On IRIX 6.5, sizeof (mbstate_t) == 1, which is not sufficient for 214 On IRIX 6.5, sizeof (mbstate_t) == 1, which is not sufficient for
200 implementing mbrtowc for encodings like UTF-8. 215 implementing mbrtowc for encodings like UTF-8.
201 On AIX and MSVC, mbrtowc needs to be overridden, but mbstate_t exists and is 216 On AIX, MSVC, and OpenBSD 6.0, mbrtowc needs to be overridden, but
202 large enough and overriding it would cause problems in C++ mode. */ 217 mbstate_t exists and is large enough and overriding it would cause problems
218 in C++ mode. */
203#if !(((defined _WIN32 && !defined __CYGWIN__) || @HAVE_MBSINIT@) && @HAVE_MBRTOWC@) || @REPLACE_MBSTATE_T@ 219#if !(((defined _WIN32 && !defined __CYGWIN__) || @HAVE_MBSINIT@) && @HAVE_MBRTOWC@) || @REPLACE_MBSTATE_T@
204# if !GNULIB_defined_mbstate_t 220# if !GNULIB_defined_mbstate_t
205# if !(defined _AIX || defined _MSC_VER) 221# if !(defined _AIX || defined _MSC_VER || defined __OpenBSD__)
206typedef int rpl_mbstate_t; 222typedef int rpl_mbstate_t;
207# undef mbstate_t 223# undef mbstate_t
208# define mbstate_t rpl_mbstate_t 224# define mbstate_t rpl_mbstate_t
@@ -262,6 +278,55 @@ _GL_EXTERN_C void free (void *);
262#endif 278#endif
263 279
264 280
281/* Declarations for ISO C N3322. */
282#if defined __GNUC__ && __GNUC__ >= 15 && !defined __clang__
283_GL_EXTERN_C wchar_t *wmemcpy (wchar_t *__dest, const wchar_t *__src, size_t __n)
284# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
285 _GL_ATTRIBUTE_NOTHROW
286# endif
287 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
288 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
289_GL_EXTERN_C wchar_t *wmemmove (wchar_t *__dest, const wchar_t *__src, size_t __n)
290# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
291 _GL_ATTRIBUTE_NOTHROW
292# endif
293 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
294 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
295_GL_EXTERN_C wchar_t *wcsncpy (wchar_t *__dest, const wchar_t *__src, size_t __n)
296# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
297 _GL_ATTRIBUTE_NOTHROW
298# endif
299 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
300 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
301_GL_EXTERN_C wchar_t *wcsncat (wchar_t *__dest, const wchar_t *__src, size_t __n)
302# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
303 _GL_ATTRIBUTE_NOTHROW
304# endif
305 _GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
306_GL_EXTERN_C int wmemcmp (const wchar_t *__s1, const wchar_t *__s2, size_t __n)
307# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
308 _GL_ATTRIBUTE_NOTHROW
309# endif
310 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
311 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
312_GL_EXTERN_C int wcsncmp (const wchar_t *__s1, const wchar_t *__s2, size_t __n)
313# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
314 _GL_ATTRIBUTE_NOTHROW
315# endif
316 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
317 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
318# ifndef __cplusplus
319_GL_EXTERN_C wchar_t *wmemchr (const wchar_t *__s, wchar_t __wc, size_t __n)
320 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3);
321# endif
322_GL_EXTERN_C wchar_t *wmemset (wchar_t *__s, wchar_t __wc, size_t __n)
323# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
324 _GL_ATTRIBUTE_NOTHROW
325# endif
326 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3);
327#endif
328
329
265/* Convert a single-byte character to a wide character. */ 330/* Convert a single-byte character to a wide character. */
266#if @GNULIB_BTOWC@ 331#if @GNULIB_BTOWC@
267# if @REPLACE_BTOWC@ 332# if @REPLACE_BTOWC@
@@ -269,11 +334,11 @@ _GL_EXTERN_C void free (void *);
269# undef btowc 334# undef btowc
270# define btowc rpl_btowc 335# define btowc rpl_btowc
271# endif 336# endif
272_GL_FUNCDECL_RPL (btowc, wint_t, (int c) _GL_ATTRIBUTE_PURE); 337_GL_FUNCDECL_RPL (btowc, wint_t, (int c), _GL_ATTRIBUTE_PURE);
273_GL_CXXALIAS_RPL (btowc, wint_t, (int c)); 338_GL_CXXALIAS_RPL (btowc, wint_t, (int c));
274# else 339# else
275# if !@HAVE_BTOWC@ 340# if !@HAVE_BTOWC@
276_GL_FUNCDECL_SYS (btowc, wint_t, (int c) _GL_ATTRIBUTE_PURE); 341_GL_FUNCDECL_SYS (btowc, wint_t, (int c), _GL_ATTRIBUTE_PURE);
277# endif 342# endif
278/* Need to cast, because on mingw, the return type is 'unsigned short'. */ 343/* Need to cast, because on mingw, the return type is 'unsigned short'. */
279_GL_CXXALIAS_SYS_CAST (btowc, wint_t, (int c)); 344_GL_CXXALIAS_SYS_CAST (btowc, wint_t, (int c));
@@ -297,12 +362,12 @@ _GL_WARN_ON_USE (btowc, "btowc is unportable - "
297# undef wctob 362# undef wctob
298# define wctob rpl_wctob 363# define wctob rpl_wctob
299# endif 364# endif
300_GL_FUNCDECL_RPL (wctob, int, (wint_t wc) _GL_ATTRIBUTE_PURE); 365_GL_FUNCDECL_RPL (wctob, int, (wint_t wc), _GL_ATTRIBUTE_PURE);
301_GL_CXXALIAS_RPL (wctob, int, (wint_t wc)); 366_GL_CXXALIAS_RPL (wctob, int, (wint_t wc));
302# else 367# else
303# if !defined wctob && !@HAVE_DECL_WCTOB@ 368# if !defined wctob && !@HAVE_DECL_WCTOB@
304/* wctob is provided by gnulib, or wctob exists but is not declared. */ 369/* wctob is provided by gnulib, or wctob exists but is not declared. */
305_GL_FUNCDECL_SYS (wctob, int, (wint_t wc) _GL_ATTRIBUTE_PURE); 370_GL_FUNCDECL_SYS (wctob, int, (wint_t wc), _GL_ATTRIBUTE_PURE);
306# endif 371# endif
307_GL_CXXALIAS_SYS (wctob, int, (wint_t wc)); 372_GL_CXXALIAS_SYS (wctob, int, (wint_t wc));
308# endif 373# endif
@@ -325,11 +390,11 @@ _GL_WARN_ON_USE (wctob, "wctob is unportable - "
325# undef mbsinit 390# undef mbsinit
326# define mbsinit rpl_mbsinit 391# define mbsinit rpl_mbsinit
327# endif 392# endif
328_GL_FUNCDECL_RPL (mbsinit, int, (const mbstate_t *ps)); 393_GL_FUNCDECL_RPL (mbsinit, int, (const mbstate_t *ps), );
329_GL_CXXALIAS_RPL (mbsinit, int, (const mbstate_t *ps)); 394_GL_CXXALIAS_RPL (mbsinit, int, (const mbstate_t *ps));
330# else 395# else
331# if !@HAVE_MBSINIT@ 396# if !@HAVE_MBSINIT@
332_GL_FUNCDECL_SYS (mbsinit, int, (const mbstate_t *ps)); 397_GL_FUNCDECL_SYS (mbsinit, int, (const mbstate_t *ps), );
333# endif 398# endif
334_GL_CXXALIAS_SYS (mbsinit, int, (const mbstate_t *ps)); 399_GL_CXXALIAS_SYS (mbsinit, int, (const mbstate_t *ps));
335# endif 400# endif
@@ -531,16 +596,19 @@ _GL_WARN_ON_USE (mbsinit, "mbsinit is unportable - "
531# define _GL_MBSTATE_ZERO_SIZE sizeof (mbstate_t) 596# define _GL_MBSTATE_ZERO_SIZE sizeof (mbstate_t)
532# endif 597# endif
533_GL_BEGIN_C_LINKAGE 598_GL_BEGIN_C_LINKAGE
534# if defined IN_MBSZERO 599# if !GNULIB_defined_mbszero
600# if defined IN_MBSZERO
535_GL_EXTERN_INLINE 601_GL_EXTERN_INLINE
536# else 602# else
537_GL_INLINE 603_GL_INLINE
538# endif 604# endif
539_GL_ARG_NONNULL ((1)) void 605_GL_ARG_NONNULL ((1)) void
540mbszero (mbstate_t *ps) 606mbszero (mbstate_t *ps)
541{ 607{
542 memset (ps, 0, _GL_MBSTATE_ZERO_SIZE); 608 memset (ps, 0, _GL_MBSTATE_ZERO_SIZE);
543} 609}
610# define GNULIB_defined_mbszero 1
611# endif
544_GL_END_C_LINKAGE 612_GL_END_C_LINKAGE
545_GL_CXXALIAS_SYS (mbszero, void, (mbstate_t *ps)); 613_GL_CXXALIAS_SYS (mbszero, void, (mbstate_t *ps));
546_GL_CXXALIASWARN (mbszero); 614_GL_CXXALIASWARN (mbszero);
@@ -556,7 +624,7 @@ _GL_CXXALIASWARN (mbszero);
556# endif 624# endif
557_GL_FUNCDECL_RPL (mbrtowc, size_t, 625_GL_FUNCDECL_RPL (mbrtowc, size_t,
558 (wchar_t *restrict pwc, const char *restrict s, size_t n, 626 (wchar_t *restrict pwc, const char *restrict s, size_t n,
559 mbstate_t *restrict ps)); 627 mbstate_t *restrict ps), );
560_GL_CXXALIAS_RPL (mbrtowc, size_t, 628_GL_CXXALIAS_RPL (mbrtowc, size_t,
561 (wchar_t *restrict pwc, const char *restrict s, size_t n, 629 (wchar_t *restrict pwc, const char *restrict s, size_t n,
562 mbstate_t *restrict ps)); 630 mbstate_t *restrict ps));
@@ -564,7 +632,7 @@ _GL_CXXALIAS_RPL (mbrtowc, size_t,
564# if !@HAVE_MBRTOWC@ 632# if !@HAVE_MBRTOWC@
565_GL_FUNCDECL_SYS (mbrtowc, size_t, 633_GL_FUNCDECL_SYS (mbrtowc, size_t,
566 (wchar_t *restrict pwc, const char *restrict s, size_t n, 634 (wchar_t *restrict pwc, const char *restrict s, size_t n,
567 mbstate_t *restrict ps)); 635 mbstate_t *restrict ps), );
568# endif 636# endif
569_GL_CXXALIAS_SYS (mbrtowc, size_t, 637_GL_CXXALIAS_SYS (mbrtowc, size_t,
570 (wchar_t *restrict pwc, const char *restrict s, size_t n, 638 (wchar_t *restrict pwc, const char *restrict s, size_t n,
@@ -590,13 +658,13 @@ _GL_WARN_ON_USE (mbrtowc, "mbrtowc is unportable - "
590# define mbrlen rpl_mbrlen 658# define mbrlen rpl_mbrlen
591# endif 659# endif
592_GL_FUNCDECL_RPL (mbrlen, size_t, 660_GL_FUNCDECL_RPL (mbrlen, size_t,
593 (const char *restrict s, size_t n, mbstate_t *restrict ps)); 661 (const char *restrict s, size_t n, mbstate_t *restrict ps), );
594_GL_CXXALIAS_RPL (mbrlen, size_t, 662_GL_CXXALIAS_RPL (mbrlen, size_t,
595 (const char *restrict s, size_t n, mbstate_t *restrict ps)); 663 (const char *restrict s, size_t n, mbstate_t *restrict ps));
596# else 664# else
597# if !@HAVE_MBRLEN@ 665# if !@HAVE_MBRLEN@
598_GL_FUNCDECL_SYS (mbrlen, size_t, 666_GL_FUNCDECL_SYS (mbrlen, size_t,
599 (const char *restrict s, size_t n, mbstate_t *restrict ps)); 667 (const char *restrict s, size_t n, mbstate_t *restrict ps), );
600# endif 668# endif
601_GL_CXXALIAS_SYS (mbrlen, size_t, 669_GL_CXXALIAS_SYS (mbrlen, size_t,
602 (const char *restrict s, size_t n, mbstate_t *restrict ps)); 670 (const char *restrict s, size_t n, mbstate_t *restrict ps));
@@ -623,7 +691,7 @@ _GL_WARN_ON_USE (mbrlen, "mbrlen is unportable - "
623_GL_FUNCDECL_RPL (mbsrtowcs, size_t, 691_GL_FUNCDECL_RPL (mbsrtowcs, size_t,
624 (wchar_t *restrict dest, 692 (wchar_t *restrict dest,
625 const char **restrict srcp, size_t len, 693 const char **restrict srcp, size_t len,
626 mbstate_t *restrict ps) 694 mbstate_t *restrict ps),
627 _GL_ARG_NONNULL ((2))); 695 _GL_ARG_NONNULL ((2)));
628_GL_CXXALIAS_RPL (mbsrtowcs, size_t, 696_GL_CXXALIAS_RPL (mbsrtowcs, size_t,
629 (wchar_t *restrict dest, 697 (wchar_t *restrict dest,
@@ -634,7 +702,7 @@ _GL_CXXALIAS_RPL (mbsrtowcs, size_t,
634_GL_FUNCDECL_SYS (mbsrtowcs, size_t, 702_GL_FUNCDECL_SYS (mbsrtowcs, size_t,
635 (wchar_t *restrict dest, 703 (wchar_t *restrict dest,
636 const char **restrict srcp, size_t len, 704 const char **restrict srcp, size_t len,
637 mbstate_t *restrict ps) 705 mbstate_t *restrict ps),
638 _GL_ARG_NONNULL ((2))); 706 _GL_ARG_NONNULL ((2)));
639# endif 707# endif
640_GL_CXXALIAS_SYS (mbsrtowcs, size_t, 708_GL_CXXALIAS_SYS (mbsrtowcs, size_t,
@@ -664,7 +732,7 @@ _GL_WARN_ON_USE (mbsrtowcs, "mbsrtowcs is unportable - "
664_GL_FUNCDECL_RPL (mbsnrtowcs, size_t, 732_GL_FUNCDECL_RPL (mbsnrtowcs, size_t,
665 (wchar_t *restrict dest, 733 (wchar_t *restrict dest,
666 const char **restrict srcp, size_t srclen, size_t len, 734 const char **restrict srcp, size_t srclen, size_t len,
667 mbstate_t *restrict ps) 735 mbstate_t *restrict ps),
668 _GL_ARG_NONNULL ((2))); 736 _GL_ARG_NONNULL ((2)));
669_GL_CXXALIAS_RPL (mbsnrtowcs, size_t, 737_GL_CXXALIAS_RPL (mbsnrtowcs, size_t,
670 (wchar_t *restrict dest, 738 (wchar_t *restrict dest,
@@ -675,7 +743,7 @@ _GL_CXXALIAS_RPL (mbsnrtowcs, size_t,
675_GL_FUNCDECL_SYS (mbsnrtowcs, size_t, 743_GL_FUNCDECL_SYS (mbsnrtowcs, size_t,
676 (wchar_t *restrict dest, 744 (wchar_t *restrict dest,
677 const char **restrict srcp, size_t srclen, size_t len, 745 const char **restrict srcp, size_t srclen, size_t len,
678 mbstate_t *restrict ps) 746 mbstate_t *restrict ps),
679 _GL_ARG_NONNULL ((2))); 747 _GL_ARG_NONNULL ((2)));
680# endif 748# endif
681_GL_CXXALIAS_SYS (mbsnrtowcs, size_t, 749_GL_CXXALIAS_SYS (mbsnrtowcs, size_t,
@@ -703,13 +771,13 @@ _GL_WARN_ON_USE (mbsnrtowcs, "mbsnrtowcs is unportable - "
703# define wcrtomb rpl_wcrtomb 771# define wcrtomb rpl_wcrtomb
704# endif 772# endif
705_GL_FUNCDECL_RPL (wcrtomb, size_t, 773_GL_FUNCDECL_RPL (wcrtomb, size_t,
706 (char *restrict s, wchar_t wc, mbstate_t *restrict ps)); 774 (char *restrict s, wchar_t wc, mbstate_t *restrict ps), );
707_GL_CXXALIAS_RPL (wcrtomb, size_t, 775_GL_CXXALIAS_RPL (wcrtomb, size_t,
708 (char *restrict s, wchar_t wc, mbstate_t *restrict ps)); 776 (char *restrict s, wchar_t wc, mbstate_t *restrict ps));
709# else 777# else
710# if !@HAVE_WCRTOMB@ 778# if !@HAVE_WCRTOMB@
711_GL_FUNCDECL_SYS (wcrtomb, size_t, 779_GL_FUNCDECL_SYS (wcrtomb, size_t,
712 (char *restrict s, wchar_t wc, mbstate_t *restrict ps)); 780 (char *restrict s, wchar_t wc, mbstate_t *restrict ps), );
713# endif 781# endif
714_GL_CXXALIAS_SYS (wcrtomb, size_t, 782_GL_CXXALIAS_SYS (wcrtomb, size_t,
715 (char *restrict s, wchar_t wc, mbstate_t *restrict ps)); 783 (char *restrict s, wchar_t wc, mbstate_t *restrict ps));
@@ -736,7 +804,7 @@ _GL_WARN_ON_USE (wcrtomb, "wcrtomb is unportable - "
736_GL_FUNCDECL_RPL (wcsrtombs, size_t, 804_GL_FUNCDECL_RPL (wcsrtombs, size_t,
737 (char *restrict dest, const wchar_t **restrict srcp, 805 (char *restrict dest, const wchar_t **restrict srcp,
738 size_t len, 806 size_t len,
739 mbstate_t *restrict ps) 807 mbstate_t *restrict ps),
740 _GL_ARG_NONNULL ((2))); 808 _GL_ARG_NONNULL ((2)));
741_GL_CXXALIAS_RPL (wcsrtombs, size_t, 809_GL_CXXALIAS_RPL (wcsrtombs, size_t,
742 (char *restrict dest, const wchar_t **restrict srcp, 810 (char *restrict dest, const wchar_t **restrict srcp,
@@ -747,7 +815,7 @@ _GL_CXXALIAS_RPL (wcsrtombs, size_t,
747_GL_FUNCDECL_SYS (wcsrtombs, size_t, 815_GL_FUNCDECL_SYS (wcsrtombs, size_t,
748 (char *restrict dest, const wchar_t **restrict srcp, 816 (char *restrict dest, const wchar_t **restrict srcp,
749 size_t len, 817 size_t len,
750 mbstate_t *restrict ps) 818 mbstate_t *restrict ps),
751 _GL_ARG_NONNULL ((2))); 819 _GL_ARG_NONNULL ((2)));
752# endif 820# endif
753_GL_CXXALIAS_SYS (wcsrtombs, size_t, 821_GL_CXXALIAS_SYS (wcsrtombs, size_t,
@@ -778,7 +846,7 @@ _GL_FUNCDECL_RPL (wcsnrtombs, size_t,
778 (char *restrict dest, 846 (char *restrict dest,
779 const wchar_t **restrict srcp, size_t srclen, 847 const wchar_t **restrict srcp, size_t srclen,
780 size_t len, 848 size_t len,
781 mbstate_t *restrict ps) 849 mbstate_t *restrict ps),
782 _GL_ARG_NONNULL ((2))); 850 _GL_ARG_NONNULL ((2)));
783_GL_CXXALIAS_RPL (wcsnrtombs, size_t, 851_GL_CXXALIAS_RPL (wcsnrtombs, size_t,
784 (char *restrict dest, 852 (char *restrict dest,
@@ -791,7 +859,7 @@ _GL_FUNCDECL_SYS (wcsnrtombs, size_t,
791 (char *restrict dest, 859 (char *restrict dest,
792 const wchar_t **restrict srcp, size_t srclen, 860 const wchar_t **restrict srcp, size_t srclen,
793 size_t len, 861 size_t len,
794 mbstate_t *restrict ps) 862 mbstate_t *restrict ps),
795 _GL_ARG_NONNULL ((2))); 863 _GL_ARG_NONNULL ((2)));
796# endif 864# endif
797_GL_CXXALIAS_SYS (wcsnrtombs, size_t, 865_GL_CXXALIAS_SYS (wcsnrtombs, size_t,
@@ -819,12 +887,12 @@ _GL_WARN_ON_USE (wcsnrtombs, "wcsnrtombs is unportable - "
819# undef wcwidth 887# undef wcwidth
820# define wcwidth rpl_wcwidth 888# define wcwidth rpl_wcwidth
821# endif 889# endif
822_GL_FUNCDECL_RPL (wcwidth, int, (wchar_t) _GL_ATTRIBUTE_PURE); 890_GL_FUNCDECL_RPL (wcwidth, int, (wchar_t), _GL_ATTRIBUTE_PURE);
823_GL_CXXALIAS_RPL (wcwidth, int, (wchar_t)); 891_GL_CXXALIAS_RPL (wcwidth, int, (wchar_t));
824# else 892# else
825# if !@HAVE_DECL_WCWIDTH@ 893# if !@HAVE_DECL_WCWIDTH@
826/* wcwidth exists but is not declared. */ 894/* wcwidth exists but is not declared. */
827_GL_FUNCDECL_SYS (wcwidth, int, (wchar_t) _GL_ATTRIBUTE_PURE); 895_GL_FUNCDECL_SYS (wcwidth, int, (wchar_t), _GL_ATTRIBUTE_PURE);
828# endif 896# endif
829_GL_CXXALIAS_SYS (wcwidth, int, (wchar_t)); 897_GL_CXXALIAS_SYS (wcwidth, int, (wchar_t));
830# endif 898# endif
@@ -843,8 +911,9 @@ _GL_WARN_ON_USE (wcwidth, "wcwidth is unportable - "
843/* Search N wide characters of S for C. */ 911/* Search N wide characters of S for C. */
844#if @GNULIB_WMEMCHR@ 912#if @GNULIB_WMEMCHR@
845# if !@HAVE_WMEMCHR@ 913# if !@HAVE_WMEMCHR@
846_GL_FUNCDECL_SYS (wmemchr, wchar_t *, (const wchar_t *s, wchar_t c, size_t n) 914_GL_FUNCDECL_SYS (wmemchr, wchar_t *,
847 _GL_ATTRIBUTE_PURE); 915 (const wchar_t *s, wchar_t c, size_t n),
916 _GL_ATTRIBUTE_PURE _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3));
848# endif 917# endif
849 /* On some systems, this function is defined as an overloaded function: 918 /* On some systems, this function is defined as an overloaded function:
850 extern "C++" { 919 extern "C++" {
@@ -855,11 +924,12 @@ _GL_CXXALIAS_SYS_CAST2 (wmemchr,
855 wchar_t *, (const wchar_t *, wchar_t, size_t), 924 wchar_t *, (const wchar_t *, wchar_t, size_t),
856 const wchar_t *, (const wchar_t *, wchar_t, size_t)); 925 const wchar_t *, (const wchar_t *, wchar_t, size_t));
857# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \ 926# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \
858 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) 927 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) \
928 && !defined __clang__
859_GL_CXXALIASWARN1 (wmemchr, wchar_t *, (wchar_t *s, wchar_t c, size_t n)); 929_GL_CXXALIASWARN1 (wmemchr, wchar_t *, (wchar_t *s, wchar_t c, size_t n));
860_GL_CXXALIASWARN1 (wmemchr, const wchar_t *, 930_GL_CXXALIASWARN1 (wmemchr, const wchar_t *,
861 (const wchar_t *s, wchar_t c, size_t n)); 931 (const wchar_t *s, wchar_t c, size_t n));
862# elif __GLIBC__ >= 2 932# elif __GLIBC__ >= 2 && !defined __CORRECT_ISO_CPP_WCHAR_H_PROTO
863_GL_CXXALIASWARN (wmemchr); 933_GL_CXXALIASWARN (wmemchr);
864# endif 934# endif
865#elif defined GNULIB_POSIXCHECK 935#elif defined GNULIB_POSIXCHECK
@@ -879,15 +949,19 @@ _GL_WARN_ON_USE (wmemchr, "wmemchr is unportable - "
879# define wmemcmp rpl_wmemcmp 949# define wmemcmp rpl_wmemcmp
880# endif 950# endif
881_GL_FUNCDECL_RPL (wmemcmp, int, 951_GL_FUNCDECL_RPL (wmemcmp, int,
882 (const wchar_t *s1, const wchar_t *s2, size_t n) 952 (const wchar_t *s1, const wchar_t *s2, size_t n),
883 _GL_ATTRIBUTE_PURE); 953 _GL_ATTRIBUTE_PURE
954 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
955 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3));
884_GL_CXXALIAS_RPL (wmemcmp, int, 956_GL_CXXALIAS_RPL (wmemcmp, int,
885 (const wchar_t *s1, const wchar_t *s2, size_t n)); 957 (const wchar_t *s1, const wchar_t *s2, size_t n));
886# else 958# else
887# if !@HAVE_WMEMCMP@ 959# if !@HAVE_WMEMCMP@
888_GL_FUNCDECL_SYS (wmemcmp, int, 960_GL_FUNCDECL_SYS (wmemcmp, int,
889 (const wchar_t *s1, const wchar_t *s2, size_t n) 961 (const wchar_t *s1, const wchar_t *s2, size_t n),
890 _GL_ATTRIBUTE_PURE); 962 _GL_ATTRIBUTE_PURE
963 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
964 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3));
891# endif 965# endif
892_GL_CXXALIAS_SYS (wmemcmp, int, 966_GL_CXXALIAS_SYS (wmemcmp, int,
893 (const wchar_t *s1, const wchar_t *s2, size_t n)); 967 (const wchar_t *s1, const wchar_t *s2, size_t n));
@@ -909,7 +983,9 @@ _GL_WARN_ON_USE (wmemcmp, "wmemcmp is unportable - "
909# if !@HAVE_WMEMCPY@ 983# if !@HAVE_WMEMCPY@
910_GL_FUNCDECL_SYS (wmemcpy, wchar_t *, 984_GL_FUNCDECL_SYS (wmemcpy, wchar_t *,
911 (wchar_t *restrict dest, 985 (wchar_t *restrict dest,
912 const wchar_t *restrict src, size_t n)); 986 const wchar_t *restrict src, size_t n),
987 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
988 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3));
913# endif 989# endif
914_GL_CXXALIAS_SYS (wmemcpy, wchar_t *, 990_GL_CXXALIAS_SYS (wmemcpy, wchar_t *,
915 (wchar_t *restrict dest, 991 (wchar_t *restrict dest,
@@ -931,7 +1007,9 @@ _GL_WARN_ON_USE (wmemcpy, "wmemcpy is unportable - "
931#if @GNULIB_WMEMMOVE@ 1007#if @GNULIB_WMEMMOVE@
932# if !@HAVE_WMEMMOVE@ 1008# if !@HAVE_WMEMMOVE@
933_GL_FUNCDECL_SYS (wmemmove, wchar_t *, 1009_GL_FUNCDECL_SYS (wmemmove, wchar_t *,
934 (wchar_t *dest, const wchar_t *src, size_t n)); 1010 (wchar_t *dest, const wchar_t *src, size_t n),
1011 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
1012 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3));
935# endif 1013# endif
936_GL_CXXALIAS_SYS (wmemmove, wchar_t *, 1014_GL_CXXALIAS_SYS (wmemmove, wchar_t *,
937 (wchar_t *dest, const wchar_t *src, size_t n)); 1015 (wchar_t *dest, const wchar_t *src, size_t n));
@@ -957,7 +1035,7 @@ _GL_WARN_ON_USE (wmemmove, "wmemmove is unportable - "
957# endif 1035# endif
958_GL_FUNCDECL_RPL (wmempcpy, wchar_t *, 1036_GL_FUNCDECL_RPL (wmempcpy, wchar_t *,
959 (wchar_t *restrict dest, 1037 (wchar_t *restrict dest,
960 const wchar_t *restrict src, size_t n)); 1038 const wchar_t *restrict src, size_t n), );
961_GL_CXXALIAS_RPL (wmempcpy, wchar_t *, 1039_GL_CXXALIAS_RPL (wmempcpy, wchar_t *,
962 (wchar_t *restrict dest, 1040 (wchar_t *restrict dest,
963 const wchar_t *restrict src, size_t n)); 1041 const wchar_t *restrict src, size_t n));
@@ -965,7 +1043,7 @@ _GL_CXXALIAS_RPL (wmempcpy, wchar_t *,
965# if !@HAVE_WMEMPCPY@ 1043# if !@HAVE_WMEMPCPY@
966_GL_FUNCDECL_SYS (wmempcpy, wchar_t *, 1044_GL_FUNCDECL_SYS (wmempcpy, wchar_t *,
967 (wchar_t *restrict dest, 1045 (wchar_t *restrict dest,
968 const wchar_t *restrict src, size_t n)); 1046 const wchar_t *restrict src, size_t n), );
969# endif 1047# endif
970_GL_CXXALIAS_SYS (wmempcpy, wchar_t *, 1048_GL_CXXALIAS_SYS (wmempcpy, wchar_t *,
971 (wchar_t *restrict dest, 1049 (wchar_t *restrict dest,
@@ -986,7 +1064,8 @@ _GL_WARN_ON_USE (wmempcpy, "wmempcpy is unportable - "
986/* Set N wide characters of S to C. */ 1064/* Set N wide characters of S to C. */
987#if @GNULIB_WMEMSET@ 1065#if @GNULIB_WMEMSET@
988# if !@HAVE_WMEMSET@ 1066# if !@HAVE_WMEMSET@
989_GL_FUNCDECL_SYS (wmemset, wchar_t *, (wchar_t *s, wchar_t c, size_t n)); 1067_GL_FUNCDECL_SYS (wmemset, wchar_t *, (wchar_t *s, wchar_t c, size_t n),
1068 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3));
990# endif 1069# endif
991_GL_CXXALIAS_SYS (wmemset, wchar_t *, (wchar_t *s, wchar_t c, size_t n)); 1070_GL_CXXALIAS_SYS (wmemset, wchar_t *, (wchar_t *s, wchar_t c, size_t n));
992# if __GLIBC__ >= 2 1071# if __GLIBC__ >= 2
@@ -1004,7 +1083,7 @@ _GL_WARN_ON_USE (wmemset, "wmemset is unportable - "
1004/* Return the number of wide characters in S. */ 1083/* Return the number of wide characters in S. */
1005#if @GNULIB_WCSLEN@ 1084#if @GNULIB_WCSLEN@
1006# if !@HAVE_WCSLEN@ 1085# if !@HAVE_WCSLEN@
1007_GL_FUNCDECL_SYS (wcslen, size_t, (const wchar_t *s) _GL_ATTRIBUTE_PURE); 1086_GL_FUNCDECL_SYS (wcslen, size_t, (const wchar_t *s), _GL_ATTRIBUTE_PURE);
1008# endif 1087# endif
1009_GL_CXXALIAS_SYS (wcslen, size_t, (const wchar_t *s)); 1088_GL_CXXALIAS_SYS (wcslen, size_t, (const wchar_t *s));
1010# if __GLIBC__ >= 2 1089# if __GLIBC__ >= 2
@@ -1025,7 +1104,7 @@ _GL_WARN_ON_USE (wcslen, "wcslen is unportable - "
1025 namespace, not in the global namespace. So, force a declaration in 1104 namespace, not in the global namespace. So, force a declaration in
1026 the global namespace. */ 1105 the global namespace. */
1027# if !@HAVE_WCSNLEN@ || (defined __sun && defined __cplusplus) 1106# if !@HAVE_WCSNLEN@ || (defined __sun && defined __cplusplus)
1028_GL_FUNCDECL_SYS (wcsnlen, size_t, (const wchar_t *s, size_t maxlen) 1107_GL_FUNCDECL_SYS (wcsnlen, size_t, (const wchar_t *s, size_t maxlen),
1029 _GL_ATTRIBUTE_PURE); 1108 _GL_ATTRIBUTE_PURE);
1030# endif 1109# endif
1031_GL_CXXALIAS_SYS (wcsnlen, size_t, (const wchar_t *s, size_t maxlen)); 1110_GL_CXXALIAS_SYS (wcsnlen, size_t, (const wchar_t *s, size_t maxlen));
@@ -1043,7 +1122,7 @@ _GL_WARN_ON_USE (wcsnlen, "wcsnlen is unportable - "
1043#if @GNULIB_WCSCPY@ 1122#if @GNULIB_WCSCPY@
1044# if !@HAVE_WCSCPY@ 1123# if !@HAVE_WCSCPY@
1045_GL_FUNCDECL_SYS (wcscpy, wchar_t *, 1124_GL_FUNCDECL_SYS (wcscpy, wchar_t *,
1046 (wchar_t *restrict dest, const wchar_t *restrict src)); 1125 (wchar_t *restrict dest, const wchar_t *restrict src), );
1047# endif 1126# endif
1048_GL_CXXALIAS_SYS (wcscpy, wchar_t *, 1127_GL_CXXALIAS_SYS (wcscpy, wchar_t *,
1049 (wchar_t *restrict dest, const wchar_t *restrict src)); 1128 (wchar_t *restrict dest, const wchar_t *restrict src));
@@ -1066,7 +1145,7 @@ _GL_WARN_ON_USE (wcscpy, "wcscpy is unportable - "
1066 the global namespace. */ 1145 the global namespace. */
1067# if !@HAVE_WCPCPY@ || (defined __sun && defined __cplusplus) 1146# if !@HAVE_WCPCPY@ || (defined __sun && defined __cplusplus)
1068_GL_FUNCDECL_SYS (wcpcpy, wchar_t *, 1147_GL_FUNCDECL_SYS (wcpcpy, wchar_t *,
1069 (wchar_t *restrict dest, const wchar_t *restrict src)); 1148 (wchar_t *restrict dest, const wchar_t *restrict src), );
1070# endif 1149# endif
1071_GL_CXXALIAS_SYS (wcpcpy, wchar_t *, 1150_GL_CXXALIAS_SYS (wcpcpy, wchar_t *,
1072 (wchar_t *restrict dest, const wchar_t *restrict src)); 1151 (wchar_t *restrict dest, const wchar_t *restrict src));
@@ -1085,7 +1164,9 @@ _GL_WARN_ON_USE (wcpcpy, "wcpcpy is unportable - "
1085# if !@HAVE_WCSNCPY@ 1164# if !@HAVE_WCSNCPY@
1086_GL_FUNCDECL_SYS (wcsncpy, wchar_t *, 1165_GL_FUNCDECL_SYS (wcsncpy, wchar_t *,
1087 (wchar_t *restrict dest, 1166 (wchar_t *restrict dest,
1088 const wchar_t *restrict src, size_t n)); 1167 const wchar_t *restrict src, size_t n),
1168 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
1169 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3));
1089# endif 1170# endif
1090_GL_CXXALIAS_SYS (wcsncpy, wchar_t *, 1171_GL_CXXALIAS_SYS (wcsncpy, wchar_t *,
1091 (wchar_t *restrict dest, 1172 (wchar_t *restrict dest,
@@ -1111,7 +1192,7 @@ _GL_WARN_ON_USE (wcsncpy, "wcsncpy is unportable - "
1111# if !@HAVE_WCPNCPY@ || (defined __sun && defined __cplusplus) 1192# if !@HAVE_WCPNCPY@ || (defined __sun && defined __cplusplus)
1112_GL_FUNCDECL_SYS (wcpncpy, wchar_t *, 1193_GL_FUNCDECL_SYS (wcpncpy, wchar_t *,
1113 (wchar_t *restrict dest, 1194 (wchar_t *restrict dest,
1114 const wchar_t *restrict src, size_t n)); 1195 const wchar_t *restrict src, size_t n), );
1115# endif 1196# endif
1116_GL_CXXALIAS_SYS (wcpncpy, wchar_t *, 1197_GL_CXXALIAS_SYS (wcpncpy, wchar_t *,
1117 (wchar_t *restrict dest, 1198 (wchar_t *restrict dest,
@@ -1130,7 +1211,7 @@ _GL_WARN_ON_USE (wcpncpy, "wcpncpy is unportable - "
1130#if @GNULIB_WCSCAT@ 1211#if @GNULIB_WCSCAT@
1131# if !@HAVE_WCSCAT@ 1212# if !@HAVE_WCSCAT@
1132_GL_FUNCDECL_SYS (wcscat, wchar_t *, 1213_GL_FUNCDECL_SYS (wcscat, wchar_t *,
1133 (wchar_t *restrict dest, const wchar_t *restrict src)); 1214 (wchar_t *restrict dest, const wchar_t *restrict src), );
1134# endif 1215# endif
1135_GL_CXXALIAS_SYS (wcscat, wchar_t *, 1216_GL_CXXALIAS_SYS (wcscat, wchar_t *,
1136 (wchar_t *restrict dest, const wchar_t *restrict src)); 1217 (wchar_t *restrict dest, const wchar_t *restrict src));
@@ -1148,14 +1229,31 @@ _GL_WARN_ON_USE (wcscat, "wcscat is unportable - "
1148 1229
1149/* Append no more than N wide characters of SRC onto DEST. */ 1230/* Append no more than N wide characters of SRC onto DEST. */
1150#if @GNULIB_WCSNCAT@ 1231#if @GNULIB_WCSNCAT@
1151# if !@HAVE_WCSNCAT@ 1232# if @REPLACE_WCSNCAT@
1152_GL_FUNCDECL_SYS (wcsncat, wchar_t *, 1233# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1234# undef wcsncat
1235# define wcsncat rpl_wcsncat
1236# endif
1237_GL_FUNCDECL_RPL (wcsncat, wchar_t *,
1238 (wchar_t *restrict dest, const wchar_t *restrict src,
1239 size_t n),
1240 _GL_ARG_NONNULL ((1))
1241 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3));
1242_GL_CXXALIAS_RPL (wcsncat, wchar_t *,
1153 (wchar_t *restrict dest, const wchar_t *restrict src, 1243 (wchar_t *restrict dest, const wchar_t *restrict src,
1154 size_t n)); 1244 size_t n));
1155# endif 1245# else
1246# if !@HAVE_WCSNCAT@
1247_GL_FUNCDECL_SYS (wcsncat, wchar_t *,
1248 (wchar_t *restrict dest, const wchar_t *restrict src,
1249 size_t n),
1250 _GL_ARG_NONNULL ((1))
1251 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3));
1252# endif
1156_GL_CXXALIAS_SYS (wcsncat, wchar_t *, 1253_GL_CXXALIAS_SYS (wcsncat, wchar_t *,
1157 (wchar_t *restrict dest, const wchar_t *restrict src, 1254 (wchar_t *restrict dest, const wchar_t *restrict src,
1158 size_t n)); 1255 size_t n));
1256# endif
1159# if __GLIBC__ >= 2 1257# if __GLIBC__ >= 2
1160_GL_CXXALIASWARN (wcsncat); 1258_GL_CXXALIASWARN (wcsncat);
1161# endif 1259# endif
@@ -1175,12 +1273,12 @@ _GL_WARN_ON_USE (wcsncat, "wcsncat is unportable - "
1175# undef wcscmp 1273# undef wcscmp
1176# define wcscmp rpl_wcscmp 1274# define wcscmp rpl_wcscmp
1177# endif 1275# endif
1178_GL_FUNCDECL_RPL (wcscmp, int, (const wchar_t *s1, const wchar_t *s2) 1276_GL_FUNCDECL_RPL (wcscmp, int, (const wchar_t *s1, const wchar_t *s2),
1179 _GL_ATTRIBUTE_PURE); 1277 _GL_ATTRIBUTE_PURE);
1180_GL_CXXALIAS_RPL (wcscmp, int, (const wchar_t *s1, const wchar_t *s2)); 1278_GL_CXXALIAS_RPL (wcscmp, int, (const wchar_t *s1, const wchar_t *s2));
1181# else 1279# else
1182# if !@HAVE_WCSCMP@ 1280# if !@HAVE_WCSCMP@
1183_GL_FUNCDECL_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2) 1281_GL_FUNCDECL_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2),
1184 _GL_ATTRIBUTE_PURE); 1282 _GL_ATTRIBUTE_PURE);
1185# endif 1283# endif
1186_GL_CXXALIAS_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2)); 1284_GL_CXXALIAS_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2));
@@ -1205,15 +1303,19 @@ _GL_WARN_ON_USE (wcscmp, "wcscmp is unportable - "
1205# define wcsncmp rpl_wcsncmp 1303# define wcsncmp rpl_wcsncmp
1206# endif 1304# endif
1207_GL_FUNCDECL_RPL (wcsncmp, int, 1305_GL_FUNCDECL_RPL (wcsncmp, int,
1208 (const wchar_t *s1, const wchar_t *s2, size_t n) 1306 (const wchar_t *s1, const wchar_t *s2, size_t n),
1209 _GL_ATTRIBUTE_PURE); 1307 _GL_ATTRIBUTE_PURE
1308 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
1309 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3));
1210_GL_CXXALIAS_RPL (wcsncmp, int, 1310_GL_CXXALIAS_RPL (wcsncmp, int,
1211 (const wchar_t *s1, const wchar_t *s2, size_t n)); 1311 (const wchar_t *s1, const wchar_t *s2, size_t n));
1212# else 1312# else
1213# if !@HAVE_WCSNCMP@ 1313# if !@HAVE_WCSNCMP@
1214_GL_FUNCDECL_SYS (wcsncmp, int, 1314_GL_FUNCDECL_SYS (wcsncmp, int,
1215 (const wchar_t *s1, const wchar_t *s2, size_t n) 1315 (const wchar_t *s1, const wchar_t *s2, size_t n),
1216 _GL_ATTRIBUTE_PURE); 1316 _GL_ATTRIBUTE_PURE
1317 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
1318 _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3));
1217# endif 1319# endif
1218_GL_CXXALIAS_SYS (wcsncmp, int, 1320_GL_CXXALIAS_SYS (wcsncmp, int,
1219 (const wchar_t *s1, const wchar_t *s2, size_t n)); 1321 (const wchar_t *s1, const wchar_t *s2, size_t n));
@@ -1236,7 +1338,7 @@ _GL_WARN_ON_USE (wcsncmp, "wcsncmp is unportable - "
1236 namespace, not in the global namespace. So, force a declaration in 1338 namespace, not in the global namespace. So, force a declaration in
1237 the global namespace. */ 1339 the global namespace. */
1238# if !@HAVE_WCSCASECMP@ || (defined __sun && defined __cplusplus) 1340# if !@HAVE_WCSCASECMP@ || (defined __sun && defined __cplusplus)
1239_GL_FUNCDECL_SYS (wcscasecmp, int, (const wchar_t *s1, const wchar_t *s2) 1341_GL_FUNCDECL_SYS (wcscasecmp, int, (const wchar_t *s1, const wchar_t *s2),
1240 _GL_ATTRIBUTE_PURE); 1342 _GL_ATTRIBUTE_PURE);
1241# endif 1343# endif
1242_GL_CXXALIAS_SYS (wcscasecmp, int, (const wchar_t *s1, const wchar_t *s2)); 1344_GL_CXXALIAS_SYS (wcscasecmp, int, (const wchar_t *s1, const wchar_t *s2));
@@ -1257,7 +1359,7 @@ _GL_WARN_ON_USE (wcscasecmp, "wcscasecmp is unportable - "
1257 the global namespace. */ 1359 the global namespace. */
1258# if !@HAVE_WCSNCASECMP@ || (defined __sun && defined __cplusplus) 1360# if !@HAVE_WCSNCASECMP@ || (defined __sun && defined __cplusplus)
1259_GL_FUNCDECL_SYS (wcsncasecmp, int, 1361_GL_FUNCDECL_SYS (wcsncasecmp, int,
1260 (const wchar_t *s1, const wchar_t *s2, size_t n) 1362 (const wchar_t *s1, const wchar_t *s2, size_t n),
1261 _GL_ATTRIBUTE_PURE); 1363 _GL_ATTRIBUTE_PURE);
1262# endif 1364# endif
1263_GL_CXXALIAS_SYS (wcsncasecmp, int, 1365_GL_CXXALIAS_SYS (wcsncasecmp, int,
@@ -1276,7 +1378,7 @@ _GL_WARN_ON_USE (wcsncasecmp, "wcsncasecmp is unportable - "
1276 category of the current locale. */ 1378 category of the current locale. */
1277#if @GNULIB_WCSCOLL@ 1379#if @GNULIB_WCSCOLL@
1278# if !@HAVE_WCSCOLL@ 1380# if !@HAVE_WCSCOLL@
1279_GL_FUNCDECL_SYS (wcscoll, int, (const wchar_t *s1, const wchar_t *s2)); 1381_GL_FUNCDECL_SYS (wcscoll, int, (const wchar_t *s1, const wchar_t *s2), );
1280# endif 1382# endif
1281_GL_CXXALIAS_SYS (wcscoll, int, (const wchar_t *s1, const wchar_t *s2)); 1383_GL_CXXALIAS_SYS (wcscoll, int, (const wchar_t *s1, const wchar_t *s2));
1282# if __GLIBC__ >= 2 1384# if __GLIBC__ >= 2
@@ -1297,7 +1399,7 @@ _GL_WARN_ON_USE (wcscoll, "wcscoll is unportable - "
1297#if @GNULIB_WCSXFRM@ 1399#if @GNULIB_WCSXFRM@
1298# if !@HAVE_WCSXFRM@ 1400# if !@HAVE_WCSXFRM@
1299_GL_FUNCDECL_SYS (wcsxfrm, size_t, 1401_GL_FUNCDECL_SYS (wcsxfrm, size_t,
1300 (wchar_t *restrict s1, const wchar_t *restrict s2, size_t n)); 1402 (wchar_t *restrict s1, const wchar_t *restrict s2, size_t n), );
1301# endif 1403# endif
1302_GL_CXXALIAS_SYS (wcsxfrm, size_t, 1404_GL_CXXALIAS_SYS (wcsxfrm, size_t,
1303 (wchar_t *restrict s1, const wchar_t *restrict s2, size_t n)); 1405 (wchar_t *restrict s1, const wchar_t *restrict s2, size_t n));
@@ -1325,15 +1427,16 @@ _GL_CXXALIAS_MDA (wcsdup, wchar_t *, (const wchar_t *s));
1325/* On Solaris 11.3, the header files declare the function in the std:: 1427/* On Solaris 11.3, the header files declare the function in the std::
1326 namespace, not in the global namespace. So, force a declaration in 1428 namespace, not in the global namespace. So, force a declaration in
1327 the global namespace. */ 1429 the global namespace. */
1328# if !@HAVE_WCSDUP@ || (defined __sun && defined __cplusplus) || __GNUC__ >= 11 1430# if !@HAVE_WCSDUP@ || (defined __sun && defined __cplusplus) \
1431 || (__GNUC__ >= 11 && !defined __clang__)
1329# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2 1432# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
1330_GL_FUNCDECL_SYS (wcsdup, wchar_t *, 1433_GL_FUNCDECL_SYS (wcsdup, wchar_t *,
1331 (const wchar_t *s) 1434 (const wchar_t *s),
1332 _GL_ATTRIBUTE_NOTHROW 1435 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE)
1333 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 1436 _GL_ATTRIBUTE_NOTHROW;
1334# else 1437# else
1335_GL_FUNCDECL_SYS (wcsdup, wchar_t *, 1438_GL_FUNCDECL_SYS (wcsdup, wchar_t *,
1336 (const wchar_t *s) 1439 (const wchar_t *s),
1337 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 1440 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
1338# endif 1441# endif
1339# endif 1442# endif
@@ -1341,16 +1444,16 @@ _GL_CXXALIAS_SYS (wcsdup, wchar_t *, (const wchar_t *s));
1341# endif 1444# endif
1342_GL_CXXALIASWARN (wcsdup); 1445_GL_CXXALIASWARN (wcsdup);
1343#else 1446#else
1344# if __GNUC__ >= 11 && !defined wcsdup 1447# if (__GNUC__ >= 11 && !defined __clang__) && !defined wcsdup
1345/* For -Wmismatched-dealloc: Associate wcsdup with free or rpl_free. */ 1448/* For -Wmismatched-dealloc: Associate wcsdup with free or rpl_free. */
1346# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2 1449# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
1347_GL_FUNCDECL_SYS (wcsdup, wchar_t *, 1450_GL_FUNCDECL_SYS (wcsdup, wchar_t *,
1348 (const wchar_t *s) 1451 (const wchar_t *s),
1349 _GL_ATTRIBUTE_NOTHROW 1452 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE)
1350 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 1453 _GL_ATTRIBUTE_NOTHROW;
1351# else 1454# else
1352_GL_FUNCDECL_SYS (wcsdup, wchar_t *, 1455_GL_FUNCDECL_SYS (wcsdup, wchar_t *,
1353 (const wchar_t *s) 1456 (const wchar_t *s),
1354 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 1457 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
1355# endif 1458# endif
1356# endif 1459# endif
@@ -1373,12 +1476,12 @@ _GL_CXXALIAS_MDA (wcsdup, wchar_t *, (const wchar_t *s));
1373# else 1476# else
1374# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2 1477# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
1375_GL_FUNCDECL_SYS (wcsdup, wchar_t *, 1478_GL_FUNCDECL_SYS (wcsdup, wchar_t *,
1376 (const wchar_t *s) 1479 (const wchar_t *s),
1377 _GL_ATTRIBUTE_NOTHROW 1480 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE)
1378 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 1481 _GL_ATTRIBUTE_NOTHROW;
1379# else 1482# else
1380_GL_FUNCDECL_SYS (wcsdup, wchar_t *, 1483_GL_FUNCDECL_SYS (wcsdup, wchar_t *,
1381 (const wchar_t *s) 1484 (const wchar_t *s),
1382 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 1485 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
1383# endif 1486# endif
1384# if @HAVE_DECL_WCSDUP@ 1487# if @HAVE_DECL_WCSDUP@
@@ -1395,7 +1498,7 @@ _GL_CXXALIASWARN (wcsdup);
1395/* Find the first occurrence of WC in WCS. */ 1498/* Find the first occurrence of WC in WCS. */
1396#if @GNULIB_WCSCHR@ 1499#if @GNULIB_WCSCHR@
1397# if !@HAVE_WCSCHR@ 1500# if !@HAVE_WCSCHR@
1398_GL_FUNCDECL_SYS (wcschr, wchar_t *, (const wchar_t *wcs, wchar_t wc) 1501_GL_FUNCDECL_SYS (wcschr, wchar_t *, (const wchar_t *wcs, wchar_t wc),
1399 _GL_ATTRIBUTE_PURE); 1502 _GL_ATTRIBUTE_PURE);
1400# endif 1503# endif
1401 /* On some systems, this function is defined as an overloaded function: 1504 /* On some systems, this function is defined as an overloaded function:
@@ -1407,10 +1510,11 @@ _GL_CXXALIAS_SYS_CAST2 (wcschr,
1407 wchar_t *, (const wchar_t *, wchar_t), 1510 wchar_t *, (const wchar_t *, wchar_t),
1408 const wchar_t *, (const wchar_t *, wchar_t)); 1511 const wchar_t *, (const wchar_t *, wchar_t));
1409# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \ 1512# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \
1410 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) 1513 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) \
1514 && !defined __clang__
1411_GL_CXXALIASWARN1 (wcschr, wchar_t *, (wchar_t *wcs, wchar_t wc)); 1515_GL_CXXALIASWARN1 (wcschr, wchar_t *, (wchar_t *wcs, wchar_t wc));
1412_GL_CXXALIASWARN1 (wcschr, const wchar_t *, (const wchar_t *wcs, wchar_t wc)); 1516_GL_CXXALIASWARN1 (wcschr, const wchar_t *, (const wchar_t *wcs, wchar_t wc));
1413# elif __GLIBC__ >= 2 1517# elif __GLIBC__ >= 2 && !defined __CORRECT_ISO_CPP_WCHAR_H_PROTO
1414_GL_CXXALIASWARN (wcschr); 1518_GL_CXXALIASWARN (wcschr);
1415# endif 1519# endif
1416#elif defined GNULIB_POSIXCHECK 1520#elif defined GNULIB_POSIXCHECK
@@ -1425,7 +1529,7 @@ _GL_WARN_ON_USE (wcschr, "wcschr is unportable - "
1425/* Find the last occurrence of WC in WCS. */ 1529/* Find the last occurrence of WC in WCS. */
1426#if @GNULIB_WCSRCHR@ 1530#if @GNULIB_WCSRCHR@
1427# if !@HAVE_WCSRCHR@ 1531# if !@HAVE_WCSRCHR@
1428_GL_FUNCDECL_SYS (wcsrchr, wchar_t *, (const wchar_t *wcs, wchar_t wc) 1532_GL_FUNCDECL_SYS (wcsrchr, wchar_t *, (const wchar_t *wcs, wchar_t wc),
1429 _GL_ATTRIBUTE_PURE); 1533 _GL_ATTRIBUTE_PURE);
1430# endif 1534# endif
1431 /* On some systems, this function is defined as an overloaded function: 1535 /* On some systems, this function is defined as an overloaded function:
@@ -1437,10 +1541,11 @@ _GL_CXXALIAS_SYS_CAST2 (wcsrchr,
1437 wchar_t *, (const wchar_t *, wchar_t), 1541 wchar_t *, (const wchar_t *, wchar_t),
1438 const wchar_t *, (const wchar_t *, wchar_t)); 1542 const wchar_t *, (const wchar_t *, wchar_t));
1439# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \ 1543# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \
1440 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) 1544 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) \
1545 && !defined __clang__
1441_GL_CXXALIASWARN1 (wcsrchr, wchar_t *, (wchar_t *wcs, wchar_t wc)); 1546_GL_CXXALIASWARN1 (wcsrchr, wchar_t *, (wchar_t *wcs, wchar_t wc));
1442_GL_CXXALIASWARN1 (wcsrchr, const wchar_t *, (const wchar_t *wcs, wchar_t wc)); 1547_GL_CXXALIASWARN1 (wcsrchr, const wchar_t *, (const wchar_t *wcs, wchar_t wc));
1443# elif __GLIBC__ >= 2 1548# elif __GLIBC__ >= 2 && !defined __CORRECT_ISO_CPP_WCHAR_H_PROTO
1444_GL_CXXALIASWARN (wcsrchr); 1549_GL_CXXALIASWARN (wcsrchr);
1445# endif 1550# endif
1446#elif defined GNULIB_POSIXCHECK 1551#elif defined GNULIB_POSIXCHECK
@@ -1456,7 +1561,7 @@ _GL_WARN_ON_USE (wcsrchr, "wcsrchr is unportable - "
1456 of wide characters not in REJECT. */ 1561 of wide characters not in REJECT. */
1457#if @GNULIB_WCSCSPN@ 1562#if @GNULIB_WCSCSPN@
1458# if !@HAVE_WCSCSPN@ 1563# if !@HAVE_WCSCSPN@
1459_GL_FUNCDECL_SYS (wcscspn, size_t, (const wchar_t *wcs, const wchar_t *reject) 1564_GL_FUNCDECL_SYS (wcscspn, size_t, (const wchar_t *wcs, const wchar_t *reject),
1460 _GL_ATTRIBUTE_PURE); 1565 _GL_ATTRIBUTE_PURE);
1461# endif 1566# endif
1462_GL_CXXALIAS_SYS (wcscspn, size_t, (const wchar_t *wcs, const wchar_t *reject)); 1567_GL_CXXALIAS_SYS (wcscspn, size_t, (const wchar_t *wcs, const wchar_t *reject));
@@ -1476,7 +1581,7 @@ _GL_WARN_ON_USE (wcscspn, "wcscspn is unportable - "
1476 of wide characters in ACCEPT. */ 1581 of wide characters in ACCEPT. */
1477#if @GNULIB_WCSSPN@ 1582#if @GNULIB_WCSSPN@
1478# if !@HAVE_WCSSPN@ 1583# if !@HAVE_WCSSPN@
1479_GL_FUNCDECL_SYS (wcsspn, size_t, (const wchar_t *wcs, const wchar_t *accept) 1584_GL_FUNCDECL_SYS (wcsspn, size_t, (const wchar_t *wcs, const wchar_t *accept),
1480 _GL_ATTRIBUTE_PURE); 1585 _GL_ATTRIBUTE_PURE);
1481# endif 1586# endif
1482_GL_CXXALIAS_SYS (wcsspn, size_t, (const wchar_t *wcs, const wchar_t *accept)); 1587_GL_CXXALIAS_SYS (wcsspn, size_t, (const wchar_t *wcs, const wchar_t *accept));
@@ -1496,7 +1601,7 @@ _GL_WARN_ON_USE (wcsspn, "wcsspn is unportable - "
1496#if @GNULIB_WCSPBRK@ 1601#if @GNULIB_WCSPBRK@
1497# if !@HAVE_WCSPBRK@ 1602# if !@HAVE_WCSPBRK@
1498_GL_FUNCDECL_SYS (wcspbrk, wchar_t *, 1603_GL_FUNCDECL_SYS (wcspbrk, wchar_t *,
1499 (const wchar_t *wcs, const wchar_t *accept) 1604 (const wchar_t *wcs, const wchar_t *accept),
1500 _GL_ATTRIBUTE_PURE); 1605 _GL_ATTRIBUTE_PURE);
1501# endif 1606# endif
1502 /* On some systems, this function is defined as an overloaded function: 1607 /* On some systems, this function is defined as an overloaded function:
@@ -1508,12 +1613,13 @@ _GL_CXXALIAS_SYS_CAST2 (wcspbrk,
1508 wchar_t *, (const wchar_t *, const wchar_t *), 1613 wchar_t *, (const wchar_t *, const wchar_t *),
1509 const wchar_t *, (const wchar_t *, const wchar_t *)); 1614 const wchar_t *, (const wchar_t *, const wchar_t *));
1510# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \ 1615# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \
1511 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) 1616 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) \
1617 && !defined __clang__
1512_GL_CXXALIASWARN1 (wcspbrk, wchar_t *, 1618_GL_CXXALIASWARN1 (wcspbrk, wchar_t *,
1513 (wchar_t *wcs, const wchar_t *accept)); 1619 (wchar_t *wcs, const wchar_t *accept));
1514_GL_CXXALIASWARN1 (wcspbrk, const wchar_t *, 1620_GL_CXXALIASWARN1 (wcspbrk, const wchar_t *,
1515 (const wchar_t *wcs, const wchar_t *accept)); 1621 (const wchar_t *wcs, const wchar_t *accept));
1516# elif __GLIBC__ >= 2 1622# elif __GLIBC__ >= 2 && !defined __CORRECT_ISO_CPP_WCHAR_H_PROTO
1517_GL_CXXALIASWARN (wcspbrk); 1623_GL_CXXALIASWARN (wcspbrk);
1518# endif 1624# endif
1519#elif defined GNULIB_POSIXCHECK 1625#elif defined GNULIB_POSIXCHECK
@@ -1534,7 +1640,7 @@ _GL_WARN_ON_USE (wcspbrk, "wcspbrk is unportable - "
1534# endif 1640# endif
1535_GL_FUNCDECL_RPL (wcsstr, wchar_t *, 1641_GL_FUNCDECL_RPL (wcsstr, wchar_t *,
1536 (const wchar_t *restrict haystack, 1642 (const wchar_t *restrict haystack,
1537 const wchar_t *restrict needle) 1643 const wchar_t *restrict needle),
1538 _GL_ATTRIBUTE_PURE); 1644 _GL_ATTRIBUTE_PURE);
1539_GL_CXXALIAS_RPL (wcsstr, wchar_t *, 1645_GL_CXXALIAS_RPL (wcsstr, wchar_t *,
1540 (const wchar_t *restrict haystack, 1646 (const wchar_t *restrict haystack,
@@ -1543,7 +1649,7 @@ _GL_CXXALIAS_RPL (wcsstr, wchar_t *,
1543# if !@HAVE_WCSSTR@ 1649# if !@HAVE_WCSSTR@
1544_GL_FUNCDECL_SYS (wcsstr, wchar_t *, 1650_GL_FUNCDECL_SYS (wcsstr, wchar_t *,
1545 (const wchar_t *restrict haystack, 1651 (const wchar_t *restrict haystack,
1546 const wchar_t *restrict needle) 1652 const wchar_t *restrict needle),
1547 _GL_ATTRIBUTE_PURE); 1653 _GL_ATTRIBUTE_PURE);
1548# endif 1654# endif
1549 /* On some systems, this function is defined as an overloaded function: 1655 /* On some systems, this function is defined as an overloaded function:
@@ -1558,14 +1664,15 @@ _GL_CXXALIAS_SYS_CAST2 (wcsstr,
1558 (const wchar_t *restrict, const wchar_t *restrict)); 1664 (const wchar_t *restrict, const wchar_t *restrict));
1559# endif 1665# endif
1560# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \ 1666# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \
1561 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) 1667 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) \
1668 && !defined __clang__
1562_GL_CXXALIASWARN1 (wcsstr, wchar_t *, 1669_GL_CXXALIASWARN1 (wcsstr, wchar_t *,
1563 (wchar_t *restrict haystack, 1670 (wchar_t *restrict haystack,
1564 const wchar_t *restrict needle)); 1671 const wchar_t *restrict needle));
1565_GL_CXXALIASWARN1 (wcsstr, const wchar_t *, 1672_GL_CXXALIASWARN1 (wcsstr, const wchar_t *,
1566 (const wchar_t *restrict haystack, 1673 (const wchar_t *restrict haystack,
1567 const wchar_t *restrict needle)); 1674 const wchar_t *restrict needle));
1568# elif __GLIBC__ >= 2 1675# elif __GLIBC__ >= 2 && !defined __CORRECT_ISO_CPP_WCHAR_H_PROTO
1569_GL_CXXALIASWARN (wcsstr); 1676_GL_CXXALIASWARN (wcsstr);
1570# endif 1677# endif
1571#elif defined GNULIB_POSIXCHECK 1678#elif defined GNULIB_POSIXCHECK
@@ -1586,7 +1693,7 @@ _GL_WARN_ON_USE (wcsstr, "wcsstr is unportable - "
1586# endif 1693# endif
1587_GL_FUNCDECL_RPL (wcstok, wchar_t *, 1694_GL_FUNCDECL_RPL (wcstok, wchar_t *,
1588 (wchar_t *restrict wcs, const wchar_t *restrict delim, 1695 (wchar_t *restrict wcs, const wchar_t *restrict delim,
1589 wchar_t **restrict ptr)); 1696 wchar_t **restrict ptr), );
1590_GL_CXXALIAS_RPL (wcstok, wchar_t *, 1697_GL_CXXALIAS_RPL (wcstok, wchar_t *,
1591 (wchar_t *restrict wcs, const wchar_t *restrict delim, 1698 (wchar_t *restrict wcs, const wchar_t *restrict delim,
1592 wchar_t **restrict ptr)); 1699 wchar_t **restrict ptr));
@@ -1594,7 +1701,7 @@ _GL_CXXALIAS_RPL (wcstok, wchar_t *,
1594# if !@HAVE_WCSTOK@ 1701# if !@HAVE_WCSTOK@
1595_GL_FUNCDECL_SYS (wcstok, wchar_t *, 1702_GL_FUNCDECL_SYS (wcstok, wchar_t *,
1596 (wchar_t *restrict wcs, const wchar_t *restrict delim, 1703 (wchar_t *restrict wcs, const wchar_t *restrict delim,
1597 wchar_t **restrict ptr)); 1704 wchar_t **restrict ptr), );
1598# endif 1705# endif
1599_GL_CXXALIAS_SYS (wcstok, wchar_t *, 1706_GL_CXXALIAS_SYS (wcstok, wchar_t *,
1600 (wchar_t *restrict wcs, const wchar_t *restrict delim, 1707 (wchar_t *restrict wcs, const wchar_t *restrict delim,
@@ -1620,12 +1727,12 @@ _GL_WARN_ON_USE (wcstok, "wcstok is unportable - "
1620# undef wcswidth 1727# undef wcswidth
1621# define wcswidth rpl_wcswidth 1728# define wcswidth rpl_wcswidth
1622# endif 1729# endif
1623_GL_FUNCDECL_RPL (wcswidth, int, (const wchar_t *s, size_t n) 1730_GL_FUNCDECL_RPL (wcswidth, int, (const wchar_t *s, size_t n),
1624 _GL_ATTRIBUTE_PURE); 1731 _GL_ATTRIBUTE_PURE);
1625_GL_CXXALIAS_RPL (wcswidth, int, (const wchar_t *s, size_t n)); 1732_GL_CXXALIAS_RPL (wcswidth, int, (const wchar_t *s, size_t n));
1626# else 1733# else
1627# if !@HAVE_WCSWIDTH@ 1734# if !@HAVE_WCSWIDTH@
1628_GL_FUNCDECL_SYS (wcswidth, int, (const wchar_t *s, size_t n) 1735_GL_FUNCDECL_SYS (wcswidth, int, (const wchar_t *s, size_t n),
1629 _GL_ATTRIBUTE_PURE); 1736 _GL_ATTRIBUTE_PURE);
1630# endif 1737# endif
1631_GL_CXXALIAS_SYS (wcswidth, int, (const wchar_t *s, size_t n)); 1738_GL_CXXALIAS_SYS (wcswidth, int, (const wchar_t *s, size_t n));
@@ -1653,7 +1760,7 @@ _GL_WARN_ON_USE (wcswidth, "wcswidth is unportable - "
1653_GL_FUNCDECL_RPL (wcsftime, size_t, 1760_GL_FUNCDECL_RPL (wcsftime, size_t,
1654 (wchar_t *restrict __buf, size_t __bufsize, 1761 (wchar_t *restrict __buf, size_t __bufsize,
1655 const wchar_t *restrict __fmt, 1762 const wchar_t *restrict __fmt,
1656 const struct tm *restrict __tp) 1763 const struct tm *restrict __tp),
1657 _GL_ARG_NONNULL ((1, 3, 4))); 1764 _GL_ARG_NONNULL ((1, 3, 4)));
1658_GL_CXXALIAS_RPL (wcsftime, size_t, 1765_GL_CXXALIAS_RPL (wcsftime, size_t,
1659 (wchar_t *restrict __buf, size_t __bufsize, 1766 (wchar_t *restrict __buf, size_t __bufsize,
@@ -1664,7 +1771,7 @@ _GL_CXXALIAS_RPL (wcsftime, size_t,
1664_GL_FUNCDECL_SYS (wcsftime, size_t, 1771_GL_FUNCDECL_SYS (wcsftime, size_t,
1665 (wchar_t *restrict __buf, size_t __bufsize, 1772 (wchar_t *restrict __buf, size_t __bufsize,
1666 const wchar_t *restrict __fmt, 1773 const wchar_t *restrict __fmt,
1667 const struct tm *restrict __tp) 1774 const struct tm *restrict __tp),
1668 _GL_ARG_NONNULL ((1, 3, 4))); 1775 _GL_ARG_NONNULL ((1, 3, 4)));
1669# endif 1776# endif
1670_GL_CXXALIAS_SYS (wcsftime, size_t, 1777_GL_CXXALIAS_SYS (wcsftime, size_t,
@@ -1698,7 +1805,7 @@ _GL_WARN_ON_USE (wcsftime, "wcsftime is unportable - "
1698 Possible errno values include: 1805 Possible errno values include:
1699 - ERANGE if SIZE is too small. 1806 - ERANGE if SIZE is too small.
1700 - ENOMEM if the memory could no be allocated. */ 1807 - ENOMEM if the memory could no be allocated. */
1701_GL_FUNCDECL_SYS (wgetcwd, wchar_t *, (wchar_t *buf, size_t size)); 1808_GL_FUNCDECL_SYS (wgetcwd, wchar_t *, (wchar_t *buf, size_t size), );
1702#endif 1809#endif
1703 1810
1704 1811
diff --git a/gl/wcrtomb.c b/gl/wcrtomb.c
index 197b020e..c9ebcf0c 100644
--- a/gl/wcrtomb.c
+++ b/gl/wcrtomb.c
@@ -1,5 +1,5 @@
1/* Convert wide character to multibyte character. 1/* Convert wide character to multibyte character.
2 Copyright (C) 2008-2024 Free Software Foundation, Inc. 2 Copyright (C) 2008-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2008. 3 Written by Bruno Haible <bruno@clisp.org>, 2008.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/wctype-h.c b/gl/wctype-h.c
index 7e4ff13a..098014a9 100644
--- a/gl/wctype-h.c
+++ b/gl/wctype-h.c
@@ -1,6 +1,6 @@
1/* Inline functions for <wctype.h>. 1/* Inline functions for <wctype.h>.
2 2
3 Copyright (C) 2012-2024 Free Software Foundation, Inc. 3 Copyright (C) 2012-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -17,7 +17,7 @@
17 17
18/* Normally this would be wctype.c, but that name's already taken. */ 18/* Normally this would be wctype.c, but that name's already taken. */
19 19
20#define _GL_WCTYPE_INLINE _GL_EXTERN_INLINE
20#include <config.h> 21#include <config.h>
21 22
22#define _GL_WCTYPE_INLINE _GL_EXTERN_INLINE
23#include <wctype.h> 23#include <wctype.h>
diff --git a/gl/wctype-impl.h b/gl/wctype-impl.h
index 26d68b41..8bb83be7 100644
--- a/gl/wctype-impl.h
+++ b/gl/wctype-impl.h
@@ -1,5 +1,5 @@
1/* Get descriptor for a wide character property. 1/* Get descriptor for a wide character property.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 2 Copyright (C) 2011-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2011. 3 Written by Bruno Haible <bruno@clisp.org>, 2011.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/wctype.c b/gl/wctype.c
index 914f6847..b421ad38 100644
--- a/gl/wctype.c
+++ b/gl/wctype.c
@@ -1,5 +1,5 @@
1/* Get descriptor for a wide character property. 1/* Get descriptor for a wide character property.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 2 Copyright (C) 2011-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2011. 3 Written by Bruno Haible <bruno@clisp.org>, 2011.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
diff --git a/gl/wctype.in.h b/gl/wctype.in.h
index 851c4f4e..aa4a8e7d 100644
--- a/gl/wctype.in.h
+++ b/gl/wctype.in.h
@@ -1,6 +1,6 @@
1/* A substitute for ISO C99 <wctype.h>, for platforms that lack it. 1/* A substitute for ISO C99 <wctype.h>, for platforms that lack it.
2 2
3 Copyright (C) 2006-2024 Free Software Foundation, Inc. 3 Copyright (C) 2006-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -478,9 +478,9 @@ towupper
478# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 478# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
479# define iswblank rpl_iswblank 479# define iswblank rpl_iswblank
480# endif 480# endif
481_GL_FUNCDECL_RPL (iswblank, int, (wint_t wc)); 481_GL_FUNCDECL_RPL (iswblank, int, (wint_t wc), );
482# else 482# else
483_GL_FUNCDECL_SYS (iswblank, int, (wint_t wc)); 483_GL_FUNCDECL_SYS (iswblank, int, (wint_t wc), );
484# endif 484# endif
485# endif 485# endif
486 486
@@ -490,7 +490,7 @@ _GL_FUNCDECL_SYS (iswblank, int, (wint_t wc));
490# undef iswdigit 490# undef iswdigit
491# define iswdigit rpl_iswdigit 491# define iswdigit rpl_iswdigit
492# endif 492# endif
493_GL_FUNCDECL_RPL (iswdigit, int, (wint_t wc)); 493_GL_FUNCDECL_RPL (iswdigit, int, (wint_t wc), );
494# endif 494# endif
495# endif 495# endif
496 496
@@ -500,7 +500,7 @@ _GL_FUNCDECL_RPL (iswdigit, int, (wint_t wc));
500# undef iswpunct 500# undef iswpunct
501# define iswpunct rpl_iswpunct 501# define iswpunct rpl_iswpunct
502# endif 502# endif
503_GL_FUNCDECL_RPL (iswpunct, int, (wint_t wc)); 503_GL_FUNCDECL_RPL (iswpunct, int, (wint_t wc), );
504# endif 504# endif
505# endif 505# endif
506 506
@@ -510,7 +510,7 @@ _GL_FUNCDECL_RPL (iswpunct, int, (wint_t wc));
510# undef iswxdigit 510# undef iswxdigit
511# define iswxdigit rpl_iswxdigit 511# define iswxdigit rpl_iswxdigit
512# endif 512# endif
513_GL_FUNCDECL_RPL (iswxdigit, int, (wint_t wc)); 513_GL_FUNCDECL_RPL (iswxdigit, int, (wint_t wc), );
514# endif 514# endif
515# endif 515# endif
516 516
@@ -659,12 +659,12 @@ typedef void *rpl_wctype_t;
659# undef wctype 659# undef wctype
660# define wctype rpl_wctype 660# define wctype rpl_wctype
661# endif 661# endif
662_GL_FUNCDECL_RPL (wctype, wctype_t, (const char *name) 662_GL_FUNCDECL_RPL (wctype, wctype_t, (const char *name),
663 _GL_ARG_NONNULL ((1))); 663 _GL_ARG_NONNULL ((1)));
664_GL_CXXALIAS_RPL (wctype, wctype_t, (const char *name)); 664_GL_CXXALIAS_RPL (wctype, wctype_t, (const char *name));
665# else 665# else
666# if !@HAVE_WCTYPE_T@ 666# if !@HAVE_WCTYPE_T@
667_GL_FUNCDECL_SYS (wctype, wctype_t, (const char *name) 667_GL_FUNCDECL_SYS (wctype, wctype_t, (const char *name),
668 _GL_ARG_NONNULL ((1))); 668 _GL_ARG_NONNULL ((1)));
669# endif 669# endif
670_GL_CXXALIAS_SYS (wctype, wctype_t, (const char *name)); 670_GL_CXXALIAS_SYS (wctype, wctype_t, (const char *name));
@@ -689,11 +689,11 @@ _GL_WARN_ON_USE (wctype, "wctype is unportable - "
689# undef iswctype 689# undef iswctype
690# define iswctype rpl_iswctype 690# define iswctype rpl_iswctype
691# endif 691# endif
692_GL_FUNCDECL_RPL (iswctype, int, (wint_t wc, wctype_t desc)); 692_GL_FUNCDECL_RPL (iswctype, int, (wint_t wc, wctype_t desc), );
693_GL_CXXALIAS_RPL (iswctype, int, (wint_t wc, wctype_t desc)); 693_GL_CXXALIAS_RPL (iswctype, int, (wint_t wc, wctype_t desc));
694# else 694# else
695# if !@HAVE_WCTYPE_T@ 695# if !@HAVE_WCTYPE_T@
696_GL_FUNCDECL_SYS (iswctype, int, (wint_t wc, wctype_t desc)); 696_GL_FUNCDECL_SYS (iswctype, int, (wint_t wc, wctype_t desc), );
697# endif 697# endif
698_GL_CXXALIAS_SYS (iswctype, int, (wint_t wc, wctype_t desc)); 698_GL_CXXALIAS_SYS (iswctype, int, (wint_t wc, wctype_t desc));
699# endif 699# endif
@@ -741,12 +741,12 @@ typedef void *rpl_wctrans_t;
741# undef wctrans 741# undef wctrans
742# define wctrans rpl_wctrans 742# define wctrans rpl_wctrans
743# endif 743# endif
744_GL_FUNCDECL_RPL (wctrans, wctrans_t, (const char *name) 744_GL_FUNCDECL_RPL (wctrans, wctrans_t, (const char *name),
745 _GL_ARG_NONNULL ((1))); 745 _GL_ARG_NONNULL ((1)));
746_GL_CXXALIAS_RPL (wctrans, wctrans_t, (const char *name)); 746_GL_CXXALIAS_RPL (wctrans, wctrans_t, (const char *name));
747# else 747# else
748# if !@HAVE_WCTRANS_T@ 748# if !@HAVE_WCTRANS_T@
749_GL_FUNCDECL_SYS (wctrans, wctrans_t, (const char *name) 749_GL_FUNCDECL_SYS (wctrans, wctrans_t, (const char *name),
750 _GL_ARG_NONNULL ((1))); 750 _GL_ARG_NONNULL ((1)));
751# endif 751# endif
752_GL_CXXALIAS_SYS (wctrans, wctrans_t, (const char *name)); 752_GL_CXXALIAS_SYS (wctrans, wctrans_t, (const char *name));
@@ -771,11 +771,11 @@ _GL_WARN_ON_USE (wctrans, "wctrans is unportable - "
771# undef towctrans 771# undef towctrans
772# define towctrans rpl_towctrans 772# define towctrans rpl_towctrans
773# endif 773# endif
774_GL_FUNCDECL_RPL (towctrans, wint_t, (wint_t wc, wctrans_t desc)); 774_GL_FUNCDECL_RPL (towctrans, wint_t, (wint_t wc, wctrans_t desc), );
775_GL_CXXALIAS_RPL (towctrans, wint_t, (wint_t wc, wctrans_t desc)); 775_GL_CXXALIAS_RPL (towctrans, wint_t, (wint_t wc, wctrans_t desc));
776# else 776# else
777# if !@HAVE_WCTRANS_T@ 777# if !@HAVE_WCTRANS_T@
778_GL_FUNCDECL_SYS (towctrans, wint_t, (wint_t wc, wctrans_t desc)); 778_GL_FUNCDECL_SYS (towctrans, wint_t, (wint_t wc, wctrans_t desc), );
779# endif 779# endif
780_GL_CXXALIAS_SYS (towctrans, wint_t, (wint_t wc, wctrans_t desc)); 780_GL_CXXALIAS_SYS (towctrans, wint_t, (wint_t wc, wctrans_t desc));
781# endif 781# endif
diff --git a/gl/wcwidth.c b/gl/wcwidth.c
new file mode 100644
index 00000000..6e7141d0
--- /dev/null
+++ b/gl/wcwidth.c
@@ -0,0 +1,73 @@
1/* Determine the number of screen columns needed for a character.
2 Copyright (C) 2006-2007, 2010-2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19/* Specification. */
20#include <wchar.h>
21
22/* Get iswprint. */
23#include <wctype.h>
24
25#include "localcharset.h"
26#include "streq.h"
27#include "uniwidth.h"
28
29/* Returns 1 if the current locale is an UTF-8 locale, 0 otherwise. */
30static inline int
31is_locale_utf8 (void)
32{
33 const char *encoding = locale_charset ();
34 return STREQ_OPT (encoding, "UTF-8", 'U', 'T', 'F', '-', '8', 0, 0, 0, 0);
35}
36
37#if GNULIB_WCHAR_SINGLE_LOCALE
38/* When we know that the locale does not change, provide a speedup by
39 caching the value of is_locale_utf8. */
40static int cached_is_locale_utf8 = -1;
41static inline int
42is_locale_utf8_cached (void)
43{
44 if (cached_is_locale_utf8 < 0)
45 cached_is_locale_utf8 = is_locale_utf8 ();
46 return cached_is_locale_utf8;
47}
48#else
49/* By default, don't make assumptions, hence no caching. */
50# define is_locale_utf8_cached is_locale_utf8
51#endif
52
53int
54wcwidth (wchar_t wc)
55#undef wcwidth
56{
57 /* In UTF-8 locales, use a Unicode aware width function. */
58 if (is_locale_utf8_cached ())
59 {
60 /* We assume that in a UTF-8 locale, a wide character is the same as a
61 Unicode character. */
62 return uc_width (wc, "UTF-8");
63 }
64 else
65 {
66 /* Otherwise, fall back to the system's wcwidth function. */
67#if HAVE_WCWIDTH
68 return wcwidth (wc);
69#else
70 return wc == 0 ? 0 : iswprint (wc) ? 1 : -1;
71#endif
72 }
73}
diff --git a/gl/windows-initguard.h b/gl/windows-initguard.h
index 6bace3f0..4f45e5bb 100644
--- a/gl/windows-initguard.h
+++ b/gl/windows-initguard.h
@@ -1,5 +1,5 @@
1/* Init guards, somewhat like spinlocks (native Windows implementation). 1/* Init guards, somewhat like spinlocks (native Windows implementation).
2 Copyright (C) 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/windows-mutex.c b/gl/windows-mutex.c
index b112e13b..87b75735 100644
--- a/gl/windows-mutex.c
+++ b/gl/windows-mutex.c
@@ -1,5 +1,5 @@
1/* Plain mutexes (native Windows implementation). 1/* Plain mutexes (native Windows implementation).
2 Copyright (C) 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -23,10 +23,12 @@
23#include "windows-mutex.h" 23#include "windows-mutex.h"
24 24
25#include <errno.h> 25#include <errno.h>
26#include <stdlib.h>
26 27
27void 28void
28glwthread_mutex_init (glwthread_mutex_t *mutex) 29glwthread_mutex_init (glwthread_mutex_t *mutex)
29{ 30{
31 mutex->owner = 0;
30 InitializeCriticalSection (&mutex->lock); 32 InitializeCriticalSection (&mutex->lock);
31 mutex->guard.done = 1; 33 mutex->guard.done = 1;
32} 34}
@@ -49,7 +51,13 @@ glwthread_mutex_lock (glwthread_mutex_t *mutex)
49 Sleep (0); 51 Sleep (0);
50 } 52 }
51 } 53 }
54 /* If this thread already owns the mutex, POSIX pthread_mutex_lock() is
55 required to deadlock here. But let's not do that on purpose. */
52 EnterCriticalSection (&mutex->lock); 56 EnterCriticalSection (&mutex->lock);
57 {
58 DWORD self = GetCurrentThreadId ();
59 mutex->owner = self;
60 }
53 return 0; 61 return 0;
54} 62}
55 63
@@ -72,6 +80,21 @@ glwthread_mutex_trylock (glwthread_mutex_t *mutex)
72 } 80 }
73 if (!TryEnterCriticalSection (&mutex->lock)) 81 if (!TryEnterCriticalSection (&mutex->lock))
74 return EBUSY; 82 return EBUSY;
83 {
84 DWORD self = GetCurrentThreadId ();
85 /* TryEnterCriticalSection succeeded. This means that the mutex was either
86 previously unlocked (and thus mutex->owner == 0) or previously locked by
87 this thread (and thus mutex->owner == self). Since the mutex is meant to
88 be plain, we need to fail in the latter case. */
89 if (mutex->owner == self)
90 {
91 LeaveCriticalSection (&mutex->lock);
92 return EBUSY;
93 }
94 if (mutex->owner != 0)
95 abort ();
96 mutex->owner = self;
97 }
75 return 0; 98 return 0;
76} 99}
77 100
@@ -80,6 +103,7 @@ glwthread_mutex_unlock (glwthread_mutex_t *mutex)
80{ 103{
81 if (!mutex->guard.done) 104 if (!mutex->guard.done)
82 return EINVAL; 105 return EINVAL;
106 mutex->owner = 0;
83 LeaveCriticalSection (&mutex->lock); 107 LeaveCriticalSection (&mutex->lock);
84 return 0; 108 return 0;
85} 109}
diff --git a/gl/windows-mutex.h b/gl/windows-mutex.h
index 88de4bdc..dc6b41e0 100644
--- a/gl/windows-mutex.h
+++ b/gl/windows-mutex.h
@@ -1,5 +1,5 @@
1/* Plain mutexes (native Windows implementation). 1/* Plain mutexes (native Windows implementation).
2 Copyright (C) 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -28,6 +28,7 @@
28typedef struct 28typedef struct
29 { 29 {
30 glwthread_initguard_t guard; /* protects the initialization */ 30 glwthread_initguard_t guard; /* protects the initialization */
31 DWORD owner;
31 CRITICAL_SECTION lock; 32 CRITICAL_SECTION lock;
32 } 33 }
33 glwthread_mutex_t; 34 glwthread_mutex_t;
diff --git a/gl/windows-once.c b/gl/windows-once.c
index 17854f5c..bd9e672a 100644
--- a/gl/windows-once.c
+++ b/gl/windows-once.c
@@ -1,5 +1,5 @@
1/* Once-only control (native Windows implementation). 1/* Once-only control (native Windows implementation).
2 Copyright (C) 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -29,7 +29,9 @@ glwthread_once (glwthread_once_t *once_control, void (*initfunction) (void))
29{ 29{
30 if (once_control->inited <= 0) 30 if (once_control->inited <= 0)
31 { 31 {
32 if (InterlockedIncrement (&once_control->started) == 0) 32 InterlockedIncrement (&once_control->num_threads);
33 /* If once_control->started is == -1, set it to 0. */
34 if (InterlockedCompareExchange (&once_control->started, 0, -1) < 0)
33 { 35 {
34 /* This thread is the first one to come to this once_control. */ 36 /* This thread is the first one to come to this once_control. */
35 InitializeCriticalSection (&once_control->lock); 37 InitializeCriticalSection (&once_control->lock);
@@ -41,8 +43,6 @@ glwthread_once (glwthread_once_t *once_control, void (*initfunction) (void))
41 } 43 }
42 else 44 else
43 { 45 {
44 /* Don't let once_control->started grow and wrap around. */
45 InterlockedDecrement (&once_control->started);
46 /* Some other thread has already started the initialization. 46 /* Some other thread has already started the initialization.
47 Yield the CPU while waiting for the other thread to finish 47 Yield the CPU while waiting for the other thread to finish
48 initializing and taking the lock. */ 48 initializing and taking the lock. */
@@ -58,5 +58,48 @@ glwthread_once (glwthread_once_t *once_control, void (*initfunction) (void))
58 abort (); 58 abort ();
59 } 59 }
60 } 60 }
61 /* Here once_control->started == 0 and once_control->inited > 0. */
62 if (InterlockedDecrement (&once_control->num_threads) == 0)
63 /* once_control->num_threads is now zero, and
64 once_control->started == 0 and once_control->inited > 0.
65 No other thread will need to use the lock.
66 We can therefore destroy the lock, to free resources. */
67 /* If once_control->inited is == 1, set it to 2. */
68 if (InterlockedCompareExchange (&once_control->inited, 2, 1) == 1)
69 DeleteCriticalSection (&once_control->lock);
61 } 70 }
71 /* Proof of correctness:
72 * num_threads is incremented and then decremented by some threads.
73 Therefore, num_threads always stays >= 0, and is == 0 at the end.
74 * The first thread to go through the once_control->started fence
75 initializes the lock and moves inited from <= 0 to > 0. The other
76 threads don't move inited from <= 0 to > 0.
77 * started, once == 0, stays == 0.
78 * inited, once > 0, stays > 0 (since at the place where it is assigned 0,
79 it cannot be > 0).
80 * inited does not change any more once it is 2.
81 Therefore, it can be changed from 1 to 2 only once.
82 * DeleteCriticalSection gets invoked right after inited has been changed
83 from 1 to 2. Therefore, DeleteCriticalSection gets invoked only once.
84 * After a moment where num_threads was 0 and started was 0 and
85 inited was > 0, no thread can reach an InitializeCriticalSection or
86 EnterCriticalSection invocation. Proof:
87 - At such a moment, no thread is in the code range between
88 InterlockedIncrement (&once_control->num_threads)
89 and
90 InterlockedDecrement (&once_control->num_threads)
91 - After such a moment, some thread can increment num_threads, but from
92 there they cannot reach the InitializeCriticalSection invocation,
93 because the once_control->started test prevents that, and they cannot
94 reach the EnterCriticalSection invocation in the other branch because
95 the
96 if (once_control->inited <= 0)
97 test prevents that.
98 * From this it follows that:
99 - DeleteCriticalSection cannot be executed while the lock is taken
100 (because DeleteCriticalSection is only executed after a moment where
101 num_threads was 0 and started was 0 and inited was > 0).
102 - Once DeleteCriticalSection has been executed, the lock is not used any
103 more.
104 */
62} 105}
diff --git a/gl/windows-once.h b/gl/windows-once.h
index c5bbcd57..b27ae538 100644
--- a/gl/windows-once.h
+++ b/gl/windows-once.h
@@ -1,5 +1,5 @@
1/* Once-only control (native Windows implementation). 1/* Once-only control (native Windows implementation).
2 Copyright (C) 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -25,13 +25,14 @@
25 25
26typedef struct 26typedef struct
27 { 27 {
28 volatile int inited; 28 volatile LONG inited;
29 volatile LONG num_threads;
29 volatile LONG started; 30 volatile LONG started;
30 CRITICAL_SECTION lock; 31 CRITICAL_SECTION lock;
31 } 32 }
32 glwthread_once_t; 33 glwthread_once_t;
33 34
34#define GLWTHREAD_ONCE_INIT { -1, -1 } 35#define GLWTHREAD_ONCE_INIT { -1, 0, -1 }
35 36
36#ifdef __cplusplus 37#ifdef __cplusplus
37extern "C" { 38extern "C" {
diff --git a/gl/windows-recmutex.c b/gl/windows-recmutex.c
index e5672baf..09341d56 100644
--- a/gl/windows-recmutex.c
+++ b/gl/windows-recmutex.c
@@ -1,5 +1,5 @@
1/* Plain recursive mutexes (native Windows implementation). 1/* Plain recursive mutexes (native Windows implementation).
2 Copyright (C) 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/windows-recmutex.h b/gl/windows-recmutex.h
index 9fa445b3..25a883d4 100644
--- a/gl/windows-recmutex.h
+++ b/gl/windows-recmutex.h
@@ -1,5 +1,5 @@
1/* Plain recursive mutexes (native Windows implementation). 1/* Plain recursive mutexes (native Windows implementation).
2 Copyright (C) 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/windows-rwlock.c b/gl/windows-rwlock.c
index e60c4efc..313f14ca 100644
--- a/gl/windows-rwlock.c
+++ b/gl/windows-rwlock.c
@@ -1,5 +1,5 @@
1/* Read-write locks (native Windows implementation). 1/* Read-write locks (native Windows implementation).
2 Copyright (C) 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/windows-rwlock.h b/gl/windows-rwlock.h
index 08d67750..b1b4063a 100644
--- a/gl/windows-rwlock.h
+++ b/gl/windows-rwlock.h
@@ -1,5 +1,5 @@
1/* Read-write locks (native Windows implementation). 1/* Read-write locks (native Windows implementation).
2 Copyright (C) 2005-2024 Free Software Foundation, Inc. 2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/xalloc-die.c b/gl/xalloc-die.c
index c053c7a8..db1ee8ff 100644
--- a/gl/xalloc-die.c
+++ b/gl/xalloc-die.c
@@ -1,6 +1,6 @@
1/* Report a memory allocation failure and exit. 1/* Report a memory allocation failure and exit.
2 2
3 Copyright (C) 1997-2000, 2002-2004, 2006, 2009-2024 Free Software 3 Copyright (C) 1997-2000, 2002-2004, 2006, 2009-2025 Free Software
4 Foundation, Inc. 4 Foundation, Inc.
5 5
6 This program is free software: you can redistribute it and/or modify 6 This program is free software: you can redistribute it and/or modify
@@ -26,7 +26,7 @@
26#include "exitfail.h" 26#include "exitfail.h"
27 27
28#include "gettext.h" 28#include "gettext.h"
29#define _(msgid) gettext (msgid) 29#define _(msgid) dgettext ("gnulib", msgid)
30 30
31void 31void
32xalloc_die (void) 32xalloc_die (void)
diff --git a/gl/xalloc-oversized.h b/gl/xalloc-oversized.h
index 7f30f83e..0f66bd06 100644
--- a/gl/xalloc-oversized.h
+++ b/gl/xalloc-oversized.h
@@ -1,6 +1,6 @@
1/* xalloc-oversized.h -- memory allocation size checking 1/* xalloc-oversized.h -- memory allocation size checking
2 2
3 Copyright (C) 1990-2000, 2003-2004, 2006-2024 Free Software Foundation, Inc. 3 Copyright (C) 1990-2000, 2003-2004, 2006-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -47,7 +47,8 @@
47#if 7 <= __GNUC__ && !defined __clang__ && PTRDIFF_MAX < SIZE_MAX 47#if 7 <= __GNUC__ && !defined __clang__ && PTRDIFF_MAX < SIZE_MAX
48# define xalloc_oversized(n, s) \ 48# define xalloc_oversized(n, s) \
49 __builtin_mul_overflow_p (n, s, (ptrdiff_t) 1) 49 __builtin_mul_overflow_p (n, s, (ptrdiff_t) 1)
50#elif 5 <= __GNUC__ && !defined __ICC && PTRDIFF_MAX < SIZE_MAX 50#elif 5 <= __GNUC__ && !defined __clang__ && !defined __ICC \
51 && PTRDIFF_MAX < SIZE_MAX
51# define xalloc_oversized(n, s) \ 52# define xalloc_oversized(n, s) \
52 (__builtin_constant_p (n) && __builtin_constant_p (s) \ 53 (__builtin_constant_p (n) && __builtin_constant_p (s) \
53 ? __xalloc_oversized (n, s) \ 54 ? __xalloc_oversized (n, s) \
diff --git a/gl/xalloc.h b/gl/xalloc.h
index 75a5db30..438e5caa 100644
--- a/gl/xalloc.h
+++ b/gl/xalloc.h
@@ -1,6 +1,6 @@
1/* xalloc.h -- malloc with out-of-memory checking 1/* xalloc.h -- malloc with out-of-memory checking
2 2
3 Copyright (C) 1990-2000, 2003-2004, 2006-2024 Free Software Foundation, Inc. 3 Copyright (C) 1990-2000, 2003-2004, 2006-2025 Free Software Foundation, Inc.
4 4
5 This program is free software: you can redistribute it and/or modify 5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
diff --git a/gl/xmalloc.c b/gl/xmalloc.c
index 5befdab7..8a715807 100644
--- a/gl/xmalloc.c
+++ b/gl/xmalloc.c
@@ -1,6 +1,6 @@
1/* xmalloc.c -- malloc with out of memory checking 1/* xmalloc.c -- malloc with out of memory checking
2 2
3 Copyright (C) 1990-2000, 2002-2006, 2008-2024 Free Software Foundation, Inc. 3 Copyright (C) 1990-2000, 2002-2006, 2008-2025 Free Software Foundation, Inc.
4 4
5 This program is free software: you can redistribute it and/or modify 5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
@@ -64,7 +64,7 @@ void *
64xrealloc (void *p, size_t s) 64xrealloc (void *p, size_t s)
65{ 65{
66 void *r = realloc (p, s); 66 void *r = realloc (p, s);
67 if (!r && (!p || s)) 67 if (!r)
68 xalloc_die (); 68 xalloc_die ();
69 return r; 69 return r;
70} 70}
@@ -82,7 +82,7 @@ void *
82xreallocarray (void *p, size_t n, size_t s) 82xreallocarray (void *p, size_t n, size_t s)
83{ 83{
84 void *r = reallocarray (p, n, s); 84 void *r = reallocarray (p, n, s);
85 if (!r && (!p || (n && s))) 85 if (!r)
86 xalloc_die (); 86 xalloc_die ();
87 return r; 87 return r;
88} 88}
diff --git a/gl/xsize.c b/gl/xsize.c
index 87744675..cd75b606 100644
--- a/gl/xsize.c
+++ b/gl/xsize.c
@@ -1,6 +1,6 @@
1/* Checked size_t computations. 1/* Checked size_t computations.
2 2
3 Copyright (C) 2012-2024 Free Software Foundation, Inc. 3 Copyright (C) 2012-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
diff --git a/gl/xsize.h b/gl/xsize.h
index 619c0edc..ee9c5680 100644
--- a/gl/xsize.h
+++ b/gl/xsize.h
@@ -1,6 +1,6 @@
1/* xsize.h -- Checked size_t computations. 1/* xsize.h -- Checked size_t computations.
2 2
3 Copyright (C) 2003, 2008-2024 Free Software Foundation, Inc. 3 Copyright (C) 2003, 2008-2025 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -26,7 +26,7 @@
26/* Get size_t. */ 26/* Get size_t. */
27#include <stddef.h> 27#include <stddef.h>
28 28
29/* Get SIZE_MAX. */ 29/* Get INT_MAX, SIZE_MAX. */
30#include <limits.h> 30#include <limits.h>
31#if HAVE_STDINT_H 31#if HAVE_STDINT_H
32# include <stdint.h> 32# include <stdint.h>
@@ -61,7 +61,8 @@ extern "C" {
61 void *p = (size_in_bounds_p (size) ? malloc (size) : NULL); 61 void *p = (size_in_bounds_p (size) ? malloc (size) : NULL);
62*/ 62*/
63 63
64/* Convert an arbitrary value >= 0 to type size_t. */ 64/* Convert an arbitrary N >= 0 to type size_t.
65 N should not have side effects. */
65#define xcast_size_t(N) \ 66#define xcast_size_t(N) \
66 ((N) <= SIZE_MAX ? (size_t) (N) : SIZE_MAX) 67 ((N) <= SIZE_MAX ? (size_t) (N) : SIZE_MAX)
67 68
@@ -69,8 +70,15 @@ extern "C" {
69XSIZE_INLINE size_t ATTRIBUTE_PURE 70XSIZE_INLINE size_t ATTRIBUTE_PURE
70xsum (size_t size1, size_t size2) 71xsum (size_t size1, size_t size2)
71{ 72{
72 size_t sum = size1 + size2; 73 if (INT_MAX < SIZE_MAX)
73 return (sum >= size1 ? sum : SIZE_MAX); 74 {
75 /* Optimize for the common case where size_t arithmetic wraps
76 around without undefined behavior. */
77 size_t sum = size1 + size2;
78 return size1 <= sum ? sum : SIZE_MAX;
79 }
80
81 return size1 <= SIZE_MAX - size2 ? size1 + size2 : SIZE_MAX;
74} 82}
75 83
76/* Sum of three sizes, with overflow check. */ 84/* Sum of three sizes, with overflow check. */
@@ -98,6 +106,8 @@ xmax (size_t size1, size_t size2)
98 106
99/* Multiplication of a count with an element size, with overflow check. 107/* Multiplication of a count with an element size, with overflow check.
100 The count must be >= 0 and the element size must be > 0. 108 The count must be >= 0 and the element size must be > 0.
109 Arguments should not have side effects.
110 The element size's type should be no wider than size_t.
101 This is a macro, not a function, so that it works correctly even 111 This is a macro, not a function, so that it works correctly even
102 when N is of a wider type and N > SIZE_MAX. */ 112 when N is of a wider type and N > SIZE_MAX. */
103#define xtimes(N, ELSIZE) \ 113#define xtimes(N, ELSIZE) \
diff --git a/lib/Makefile.am b/lib/Makefile.am
index e41201c4..27a08278 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -4,13 +4,12 @@ SUBDIRS = . tests
4 4
5noinst_LIBRARIES = libmonitoringplug.a 5noinst_LIBRARIES = libmonitoringplug.a
6 6
7AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ 7AM_CPPFLAGS = \
8 -I$(srcdir) -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins 8 -I$(srcdir) -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins
9 9
10libmonitoringplug_a_SOURCES = utils_base.c utils_disk.c utils_tcp.c utils_cmd.c maxfd.c output.c perfdata.c output.c thresholds.c vendor/cJSON/cJSON.c 10libmonitoringplug_a_SOURCES = utils_base.c utils_tcp.c utils_cmd.c maxfd.c output.c perfdata.c output.c thresholds.c vendor/cJSON/cJSON.c
11 11
12EXTRA_DIST = utils_base.h \ 12EXTRA_DIST = utils_base.h \
13 utils_disk.h \
14 utils_tcp.h \ 13 utils_tcp.h \
15 utils_cmd.h \ 14 utils_cmd.h \
16 parse_ini.h \ 15 parse_ini.h \
diff --git a/lib/extra_opts.c b/lib/extra_opts.c
index 88787336..3fe69014 100644
--- a/lib/extra_opts.c
+++ b/lib/extra_opts.c
@@ -27,27 +27,32 @@
27 27
28/* FIXME: copied from utils.h; we should move a bunch of libs! */ 28/* FIXME: copied from utils.h; we should move a bunch of libs! */
29bool is_option2(char *str) { 29bool is_option2(char *str) {
30 if (!str) 30 if (!str) {
31 return false; 31 return false;
32 else if (strspn(str, "-") == 1 || strspn(str, "-") == 2) 32 }
33
34 if (strspn(str, "-") == 1 || strspn(str, "-") == 2) {
33 return true; 35 return true;
34 else 36 }
35 return false; 37
38 return false;
36} 39}
37 40
38/* this is the externally visible function used by plugins */ 41/* this is the externally visible function used by plugins */
39char **np_extra_opts(int *argc, char **argv, const char *plugin_name) { 42char **np_extra_opts(int *argc, char **argv, const char *plugin_name) {
40 np_arg_list *extra_args = NULL, *ea1 = NULL, *ea_tmp = NULL;
41 char **argv_new = NULL;
42 char *argptr = NULL;
43 int i, j, optfound, argc_new, ea_num = *argc;
44
45 if (*argc < 2) { 43 if (*argc < 2) {
46 /* No arguments provided */ 44 /* No arguments provided */
47 return argv; 45 return argv;
48 } 46 }
49 47
50 for (i = 1; i < *argc; i++) { 48 np_arg_list *extra_args = NULL;
49 np_arg_list *ea1 = NULL;
50 np_arg_list *ea_tmp = NULL;
51 char *argptr = NULL;
52 int optfound;
53 size_t ea_num = (size_t)*argc;
54
55 for (int i = 1; i < *argc; i++) {
51 argptr = NULL; 56 argptr = NULL;
52 optfound = 0; 57 optfound = 0;
53 58
@@ -56,8 +61,10 @@ char **np_extra_opts(int *argc, char **argv, const char *plugin_name) {
56 /* It is a single argument with value */ 61 /* It is a single argument with value */
57 argptr = argv[i] + 13; 62 argptr = argv[i] + 13;
58 /* Delete the extra opts argument */ 63 /* Delete the extra opts argument */
59 for (j = i; j < *argc; j++) 64 for (int j = i; j < *argc; j++) {
60 argv[j] = argv[j + 1]; 65 argv[j] = argv[j + 1];
66 }
67
61 i--; 68 i--;
62 *argc -= 1; 69 *argc -= 1;
63 } else if (strcmp(argv[i], "--extra-opts") == 0) { 70 } else if (strcmp(argv[i], "--extra-opts") == 0) {
@@ -65,8 +72,10 @@ char **np_extra_opts(int *argc, char **argv, const char *plugin_name) {
65 /* It is a argument with separate value */ 72 /* It is a argument with separate value */
66 argptr = argv[i + 1]; 73 argptr = argv[i + 1];
67 /* Delete the extra-opts argument/value */ 74 /* Delete the extra-opts argument/value */
68 for (j = i; j < *argc - 1; j++) 75 for (int j = i; j < *argc - 1; j++) {
69 argv[j] = argv[j + 2]; 76 argv[j] = argv[j + 2];
77 }
78
70 i -= 2; 79 i -= 2;
71 *argc -= 2; 80 *argc -= 2;
72 ea_num--; 81 ea_num--;
@@ -74,8 +83,10 @@ char **np_extra_opts(int *argc, char **argv, const char *plugin_name) {
74 /* It has no value */ 83 /* It has no value */
75 optfound = 1; 84 optfound = 1;
76 /* Delete the extra opts argument */ 85 /* Delete the extra opts argument */
77 for (j = i; j < *argc; j++) 86 for (int j = i; j < *argc; j++) {
78 argv[j] = argv[j + 1]; 87 argv[j] = argv[j + 1];
88 }
89
79 i--; 90 i--;
80 *argc -= 1; 91 *argc -= 1;
81 } 92 }
@@ -94,34 +105,37 @@ char **np_extra_opts(int *argc, char **argv, const char *plugin_name) {
94 /* append the list to extra_args */ 105 /* append the list to extra_args */
95 if (extra_args == NULL) { 106 if (extra_args == NULL) {
96 extra_args = ea1; 107 extra_args = ea1;
97 while ((ea1 = ea1->next)) 108 while ((ea1 = ea1->next)) {
98 ea_num++; 109 ea_num++;
110 }
99 } else { 111 } else {
100 ea_tmp = extra_args; 112 ea_tmp = extra_args;
101 while (ea_tmp->next) { 113 while (ea_tmp->next) {
102 ea_tmp = ea_tmp->next; 114 ea_tmp = ea_tmp->next;
103 } 115 }
104 ea_tmp->next = ea1; 116 ea_tmp->next = ea1;
105 while ((ea1 = ea1->next)) 117 while ((ea1 = ea1->next)) {
106 ea_num++; 118 ea_num++;
119 }
107 } 120 }
108 ea1 = ea_tmp = NULL; 121 ea1 = ea_tmp = NULL;
109 } 122 }
110 } /* lather, rince, repeat */ 123 } /* lather, rince, repeat */
111 124
112 if (ea_num == *argc && extra_args == NULL) { 125 if (ea_num == (size_t)*argc && extra_args == NULL) {
113 /* No extra-opts */ 126 /* No extra-opts */
114 return argv; 127 return argv;
115 } 128 }
116 129
117 /* done processing arguments. now create a new argv array... */ 130 /* done processing arguments. now create a new argv array... */
118 argv_new = (char **)malloc((ea_num + 1) * sizeof(char **)); 131 char **argv_new = (char **)malloc((ea_num + 1) * sizeof(char **));
119 if (argv_new == NULL) 132 if (argv_new == NULL) {
120 die(STATE_UNKNOWN, _("malloc() failed!\n")); 133 die(STATE_UNKNOWN, _("malloc() failed!\n"));
134 }
121 135
122 /* starting with program name */ 136 /* starting with program name */
123 argv_new[0] = argv[0]; 137 argv_new[0] = argv[0];
124 argc_new = 1; 138 int argc_new = 1;
125 /* then parsed ini opts (frying them up in the same run) */ 139 /* then parsed ini opts (frying them up in the same run) */
126 while (extra_args) { 140 while (extra_args) {
127 argv_new[argc_new++] = extra_args->arg; 141 argv_new[argc_new++] = extra_args->arg;
@@ -130,8 +144,9 @@ char **np_extra_opts(int *argc, char **argv, const char *plugin_name) {
130 free(ea1); 144 free(ea1);
131 } 145 }
132 /* finally the rest of the argv array */ 146 /* finally the rest of the argv array */
133 for (i = 1; i < *argc; i++) 147 for (int i = 1; i < *argc; i++) {
134 argv_new[argc_new++] = argv[i]; 148 argv_new[argc_new++] = argv[i];
149 }
135 *argc = argc_new; 150 *argc = argc_new;
136 /* and terminate. */ 151 /* and terminate. */
137 argv_new[argc_new] = NULL; 152 argv_new[argc_new] = NULL;
diff --git a/lib/maxfd.c b/lib/maxfd.c
index ca5b6e54..a0f79949 100644
--- a/lib/maxfd.c
+++ b/lib/maxfd.c
@@ -19,7 +19,6 @@
19 *****************************************************************************/ 19 *****************************************************************************/
20 20
21#include "./maxfd.h" 21#include "./maxfd.h"
22#include <errno.h>
23 22
24long mp_open_max(void) { 23long mp_open_max(void) {
25 long maxfd = 0L; 24 long maxfd = 0L;
@@ -31,10 +30,11 @@ long mp_open_max(void) {
31#ifdef _SC_OPEN_MAX 30#ifdef _SC_OPEN_MAX
32 errno = 0; 31 errno = 0;
33 if ((maxfd = sysconf(_SC_OPEN_MAX)) < 0) { 32 if ((maxfd = sysconf(_SC_OPEN_MAX)) < 0) {
34 if (errno == 0) 33 if (errno == 0) {
35 maxfd = DEFAULT_MAXFD; /* it's indeterminate */ 34 maxfd = DEFAULT_MAXFD; /* it's indeterminate */
36 else 35 } else {
37 die(STATE_UNKNOWN, _("sysconf error for _SC_OPEN_MAX\n")); 36 die(STATE_UNKNOWN, _("sysconf error for _SC_OPEN_MAX\n"));
37 }
38 } 38 }
39#elif defined(OPEN_MAX) 39#elif defined(OPEN_MAX)
40 return OPEN_MAX 40 return OPEN_MAX
diff --git a/lib/output.c b/lib/output.c
index 61fbf832..62e1366d 100644
--- a/lib/output.c
+++ b/lib/output.c
@@ -13,9 +13,11 @@
13 13
14// == Global variables 14// == Global variables
15static mp_output_format output_format = MP_FORMAT_DEFAULT; 15static mp_output_format output_format = MP_FORMAT_DEFAULT;
16static mp_output_detail_level level_of_detail = MP_DETAIL_ALL;
16 17
17// == Prototypes == 18// == Prototypes ==
18static char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check, unsigned int indentation); 19static char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check,
20 unsigned int indentation);
19static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck); 21static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck);
20 22
21// == Implementation == 23// == Implementation ==
@@ -40,7 +42,7 @@ static inline char *fmt_subcheck_perfdata(mp_subcheck check) {
40 42
41 while (subchecks != NULL) { 43 while (subchecks != NULL) {
42 if (added > 0) { 44 if (added > 0) {
43 added = asprintf(&result, "%s%s", result, fmt_subcheck_perfdata(subchecks->subcheck)); 45 added = asprintf(&result, "%s %s", result, fmt_subcheck_perfdata(subchecks->subcheck));
44 } else { 46 } else {
45 // TODO free previous result here? 47 // TODO free previous result here?
46 added = asprintf(&result, "%s", fmt_subcheck_perfdata(subchecks->subcheck)); 48 added = asprintf(&result, "%s", fmt_subcheck_perfdata(subchecks->subcheck));
@@ -57,7 +59,9 @@ static inline char *fmt_subcheck_perfdata(mp_subcheck check) {
57 * It sets useful defaults 59 * It sets useful defaults
58 */ 60 */
59mp_check mp_check_init(void) { 61mp_check mp_check_init(void) {
60 mp_check check = {0}; 62 mp_check check = {
63 .evaluation_function = &mp_eval_check_default,
64 };
61 return check; 65 return check;
62} 66}
63 67
@@ -120,7 +124,8 @@ void mp_add_perfdata_to_subcheck(mp_subcheck check[static 1], const mp_perfdata
120 */ 124 */
121int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck subcheck) { 125int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck subcheck) {
122 if (subcheck.output == NULL) { 126 if (subcheck.output == NULL) {
123 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "Sub check output is NULL"); 127 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__,
128 "Sub check output is NULL");
124 } 129 }
125 130
126 mp_subcheck_list *tmp = NULL; 131 mp_subcheck_list *tmp = NULL;
@@ -193,16 +198,33 @@ char *get_subcheck_summary(mp_check check) {
193 return result; 198 return result;
194} 199}
195 200
201mp_state_enum mp_compute_subcheck_state(const mp_subcheck subcheck) {
202 if (subcheck.evaluation_function == NULL) {
203 return mp_eval_subcheck_default(subcheck);
204 }
205 return subcheck.evaluation_function(subcheck);
206}
207
196/* 208/*
197 * Generate the result state of a mp_subcheck object based on it's own state and it's subchecks states 209 * Generate the result state of a mp_subcheck object based on its own state and its subchecks
210 * states
198 */ 211 */
199mp_state_enum mp_compute_subcheck_state(const mp_subcheck check) { 212mp_state_enum mp_eval_subcheck_default(mp_subcheck subcheck) {
200 if (check.state_set_explicitly) { 213 if (subcheck.evaluation_function != NULL) {
201 return check.state; 214 return subcheck.evaluation_function(subcheck);
202 } 215 }
203 216
204 mp_subcheck_list *scl = check.subchecks; 217 if (subcheck.state_set_explicitly) {
205 mp_state_enum result = check.default_state; 218 return subcheck.state;
219 }
220
221 mp_subcheck_list *scl = subcheck.subchecks;
222
223 if (scl == NULL) {
224 return subcheck.default_state;
225 }
226
227 mp_state_enum result = STATE_OK;
206 228
207 while (scl != NULL) { 229 while (scl != NULL) {
208 result = max_state_alt(result, mp_compute_subcheck_state(scl->subcheck)); 230 result = max_state_alt(result, mp_compute_subcheck_state(scl->subcheck));
@@ -212,10 +234,18 @@ mp_state_enum mp_compute_subcheck_state(const mp_subcheck check) {
212 return result; 234 return result;
213} 235}
214 236
237mp_state_enum mp_compute_check_state(const mp_check check) {
238 // just a safety check
239 if (check.evaluation_function == NULL) {
240 return mp_eval_check_default(check);
241 }
242 return check.evaluation_function(check);
243}
244
215/* 245/*
216 * Generate the result state of a mp_check object based on it's own state and it's subchecks states 246 * Generate the result state of a mp_check object based on it's own state and it's subchecks states
217 */ 247 */
218mp_state_enum mp_compute_check_state(const mp_check check) { 248mp_state_enum mp_eval_check_default(const mp_check check) {
219 assert(check.subchecks != NULL); // a mp_check without subchecks is invalid, die here 249 assert(check.subchecks != NULL); // a mp_check without subchecks is invalid, die here
220 250
221 mp_subcheck_list *scl = check.subchecks; 251 mp_subcheck_list *scl = check.subchecks;
@@ -247,7 +277,11 @@ char *mp_fmt_output(mp_check check) {
247 mp_subcheck_list *subchecks = check.subchecks; 277 mp_subcheck_list *subchecks = check.subchecks;
248 278
249 while (subchecks != NULL) { 279 while (subchecks != NULL) {
250 asprintf(&result, "%s\n%s", result, fmt_subcheck_output(MP_FORMAT_MULTI_LINE, subchecks->subcheck, 1)); 280 if (level_of_detail == MP_DETAIL_ALL ||
281 mp_compute_subcheck_state(subchecks->subcheck) != STATE_OK) {
282 asprintf(&result, "%s\n%s", result,
283 fmt_subcheck_output(MP_FORMAT_MULTI_LINE, subchecks->subcheck, 1));
284 }
251 subchecks = subchecks->next; 285 subchecks = subchecks->next;
252 } 286 }
253 287
@@ -258,7 +292,8 @@ char *mp_fmt_output(mp_check check) {
258 if (pd_string == NULL) { 292 if (pd_string == NULL) {
259 asprintf(&pd_string, "%s", fmt_subcheck_perfdata(subchecks->subcheck)); 293 asprintf(&pd_string, "%s", fmt_subcheck_perfdata(subchecks->subcheck));
260 } else { 294 } else {
261 asprintf(&pd_string, "%s %s", pd_string, fmt_subcheck_perfdata(subchecks->subcheck)); 295 asprintf(&pd_string, "%s %s", pd_string,
296 fmt_subcheck_perfdata(subchecks->subcheck));
262 } 297 }
263 298
264 subchecks = subchecks->next; 299 subchecks = subchecks->next;
@@ -327,22 +362,58 @@ static char *generate_indentation_string(unsigned int indentation) {
327/* 362/*
328 * Helper function to generate the output string of mp_subcheck 363 * Helper function to generate the output string of mp_subcheck
329 */ 364 */
330static inline char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check, unsigned int indentation) { 365static inline char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check,
366 unsigned int indentation) {
331 char *result = NULL; 367 char *result = NULL;
332 mp_subcheck_list *subchecks = NULL; 368 mp_subcheck_list *subchecks = NULL;
333 369
334 switch (output_format) { 370 switch (output_format) {
335 case MP_FORMAT_MULTI_LINE: 371 case MP_FORMAT_MULTI_LINE: {
336 asprintf(&result, "%s\\_[%s] - %s", generate_indentation_string(indentation), state_text(mp_compute_subcheck_state(check)), 372 char *tmp_string = NULL;
337 check.output); 373 if ((tmp_string = strchr(check.output, '\n')) != NULL) {
374 // This is a multiline string, put the correct indentation in before proceeding
375 char *intermediate_string = "";
376 bool have_residual_chars = false;
377
378 while (tmp_string != NULL) {
379 *tmp_string = '\0';
380 asprintf(&intermediate_string, "%s%s\n%s", intermediate_string, check.output,
381 generate_indentation_string(
382 indentation + 1)); // one more indentation to make it look better
383
384 if (*(tmp_string + 1) != '\0') {
385 check.output = tmp_string + 1;
386 have_residual_chars = true;
387 } else {
388 // Null after the \n, so this is the end
389 have_residual_chars = false;
390 break;
391 }
392
393 tmp_string = strchr(check.output, '\n');
394 }
395
396 // add the rest (if any)
397 if (have_residual_chars) {
398 char *tmp = check.output;
399 xasprintf(&check.output, "%s\n%s%s", intermediate_string,
400 generate_indentation_string(indentation + 1), tmp);
401 } else {
402 check.output = intermediate_string;
403 }
404 }
405 asprintf(&result, "%s\\_[%s] - %s", generate_indentation_string(indentation),
406 state_text(mp_compute_subcheck_state(check)), check.output);
338 407
339 subchecks = check.subchecks; 408 subchecks = check.subchecks;
340 409
341 while (subchecks != NULL) { 410 while (subchecks != NULL) {
342 asprintf(&result, "%s\n%s", result, fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1)); 411 asprintf(&result, "%s\n%s", result,
412 fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1));
343 subchecks = subchecks->next; 413 subchecks = subchecks->next;
344 } 414 }
345 return result; 415 return result;
416 }
346 default: 417 default:
347 die(STATE_UNKNOWN, "Invalid format"); 418 die(STATE_UNKNOWN, "Invalid format");
348 } 419 }
@@ -539,3 +610,27 @@ parsed_output_format mp_parse_output_format(char *format_string) {
539void mp_set_format(mp_output_format format) { output_format = format; } 610void mp_set_format(mp_output_format format) { output_format = format; }
540 611
541mp_output_format mp_get_format(void) { return output_format; } 612mp_output_format mp_get_format(void) { return output_format; }
613
614void mp_set_level_of_detail(mp_output_detail_level level) { level_of_detail = level; }
615
616mp_output_detail_level mp_get_level_of_detail(void) { return level_of_detail; }
617
618mp_state_enum mp_eval_ok(mp_check overall) {
619 (void)overall;
620 return STATE_OK;
621}
622
623mp_state_enum mp_eval_warning(mp_check overall) {
624 (void)overall;
625 return STATE_WARNING;
626}
627
628mp_state_enum mp_eval_critical(mp_check overall) {
629 (void)overall;
630 return STATE_CRITICAL;
631}
632
633mp_state_enum mp_eval_unknown(mp_check overall) {
634 (void)overall;
635 return STATE_UNKNOWN;
636}
diff --git a/lib/output.h b/lib/output.h
index 2bdfa074..c63c8e3f 100644
--- a/lib/output.h
+++ b/lib/output.h
@@ -7,15 +7,21 @@
7/* 7/*
8 * A partial check result 8 * A partial check result
9 */ 9 */
10typedef struct { 10typedef struct mp_subcheck mp_subcheck;
11struct mp_subcheck {
11 mp_state_enum state; // OK, Warning, Critical ... set explicitly 12 mp_state_enum state; // OK, Warning, Critical ... set explicitly
12 mp_state_enum default_state; // OK, Warning, Critical .. if not set explicitly 13 mp_state_enum default_state; // OK, Warning, Critical .. if not set explicitly
13 bool state_set_explicitly; // was the state set explicitly (or should it be derived from subchecks) 14 bool state_set_explicitly; // was the state set explicitly (or should it be derived from
15 // subchecks)
14 16
15 char *output; // Text output for humans ("Filesystem xyz is fine", "Could not create TCP connection to..") 17 char *output; // Text output for humans ("Filesystem xyz is fine", "Could not create TCP
16 pd_list *perfdata; // Performance data for this check 18 // connection to..")
19 pd_list *perfdata; // Performance data for this check
17 struct subcheck_list *subchecks; // subchecks deeper in the hierarchy 20 struct subcheck_list *subchecks; // subchecks deeper in the hierarchy
18} mp_subcheck; 21
22 // the evaluation_functions computes the state of subcheck
23 mp_state_enum (*evaluation_function)(mp_subcheck);
24};
19 25
20/* 26/*
21 * A list of subchecks, used in subchecks and the main check 27 * A list of subchecks, used in subchecks and the main check
@@ -38,8 +44,18 @@ typedef enum output_format {
38/* 44/*
39 * Format related functions 45 * Format related functions
40 */ 46 */
41 void mp_set_format(mp_output_format format); 47void mp_set_format(mp_output_format format);
42 mp_output_format mp_get_format(void); 48mp_output_format mp_get_format(void);
49
50// Output detail level
51
52typedef enum output_detail_level {
53 MP_DETAIL_ALL,
54 MP_DETAIL_NON_OK_ONLY,
55} mp_output_detail_level;
56
57void mp_set_level_of_detail(mp_output_detail_level level);
58mp_output_detail_level mp_get_level_of_detail(void);
43 59
44/* 60/*
45 * The main state object of a plugin. Exists only ONCE per plugin. 61 * The main state object of a plugin. Exists only ONCE per plugin.
@@ -47,10 +63,14 @@ typedef enum output_format {
47 * The final result is always derived from the children and the "worst" state 63 * The final result is always derived from the children and the "worst" state
48 * in the first layer of subchecks 64 * in the first layer of subchecks
49 */ 65 */
50typedef struct { 66typedef struct mp_check mp_check;
51 char *summary; // Overall summary, if not set a summary will be automatically generated 67struct mp_check {
68 char *summary; // Overall summary, if not set a summary will be automatically generated
52 mp_subcheck_list *subchecks; 69 mp_subcheck_list *subchecks;
53} mp_check; 70
71 // the evaluation_functions computes the state of check
72 mp_state_enum (*evaluation_function)(mp_check);
73};
54 74
55mp_check mp_check_init(void); 75mp_check mp_check_init(void);
56mp_subcheck mp_subcheck_init(void); 76mp_subcheck mp_subcheck_init(void);
@@ -68,6 +88,13 @@ void mp_add_summary(mp_check check[static 1], char *summary);
68mp_state_enum mp_compute_check_state(mp_check); 88mp_state_enum mp_compute_check_state(mp_check);
69mp_state_enum mp_compute_subcheck_state(mp_subcheck); 89mp_state_enum mp_compute_subcheck_state(mp_subcheck);
70 90
91mp_state_enum mp_eval_ok(mp_check overall);
92mp_state_enum mp_eval_warning(mp_check overall);
93mp_state_enum mp_eval_critical(mp_check overall);
94mp_state_enum mp_eval_unknown(mp_check overall);
95mp_state_enum mp_eval_check_default(mp_check check);
96mp_state_enum mp_eval_subcheck_default(mp_subcheck subcheck);
97
71typedef struct { 98typedef struct {
72 bool parsing_success; 99 bool parsing_success;
73 mp_output_format output_format; 100 mp_output_format output_format;
diff --git a/lib/parse_ini.c b/lib/parse_ini.c
index 1289aae2..db337622 100644
--- a/lib/parse_ini.c
+++ b/lib/parse_ini.c
@@ -40,26 +40,29 @@ typedef struct {
40 char *stanza; 40 char *stanza;
41} np_ini_info; 41} np_ini_info;
42 42
43static char *default_ini_file_names[] = {"monitoring-plugins.ini", "plugins.ini", "nagios-plugins.ini", NULL}; 43static char *default_ini_file_names[] = {"monitoring-plugins.ini", "plugins.ini",
44 "nagios-plugins.ini", NULL};
44 45
45static char *default_ini_path_names[] = { 46static char *default_ini_path_names[] = {
46 "/usr/local/etc/monitoring-plugins/monitoring-plugins.ini", "/usr/local/etc/monitoring-plugins.ini", 47 "/usr/local/etc/monitoring-plugins/monitoring-plugins.ini",
47 "/etc/monitoring-plugins/monitoring-plugins.ini", "/etc/monitoring-plugins.ini", 48 "/usr/local/etc/monitoring-plugins.ini", "/etc/monitoring-plugins/monitoring-plugins.ini",
49 "/etc/monitoring-plugins.ini",
48 /* deprecated path names (for backward compatibility): */ 50 /* deprecated path names (for backward compatibility): */
49 "/etc/nagios/plugins.ini", "/usr/local/nagios/etc/plugins.ini", "/usr/local/etc/nagios/plugins.ini", "/etc/opt/nagios/plugins.ini", 51 "/etc/nagios/plugins.ini", "/usr/local/nagios/etc/plugins.ini",
50 "/etc/nagios-plugins.ini", "/usr/local/etc/nagios-plugins.ini", "/etc/opt/nagios-plugins.ini", NULL}; 52 "/usr/local/etc/nagios/plugins.ini", "/etc/opt/nagios/plugins.ini", "/etc/nagios-plugins.ini",
53 "/usr/local/etc/nagios-plugins.ini", "/etc/opt/nagios-plugins.ini", NULL};
51 54
52/* eat all characters from a FILE pointer until n is encountered */ 55/* eat all characters from a FILE pointer until n is encountered */
53#define GOBBLE_TO(f, c, n) \ 56#define GOBBLE_TO(f, c, n) \
54 do { \ 57 do { \
55 (c) = fgetc((f)); \ 58 (c) = fgetc((f)); \
56 } while ((c) != EOF && (c) != (n)) 59 } while ((c) != EOF && (c) != (n))
57 60
58/* internal function that returns the constructed defaults options */ 61/* internal function that returns the constructed defaults options */
59static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts); 62static bool read_defaults(FILE *defaults_file, const char *stanza, np_arg_list **opts);
60 63
61/* internal function that converts a single line into options format */ 64/* internal function that converts a single line into options format */
62static int add_option(FILE *f, np_arg_list **optlst); 65static int add_option(FILE *filePointer, np_arg_list **optlst);
63 66
64/* internal functions to find default file */ 67/* internal functions to find default file */
65static char *default_file(void); 68static char *default_file(void);
@@ -71,7 +74,8 @@ static char *default_file_in_path(void);
71 * into its separate parts. 74 * into its separate parts.
72 */ 75 */
73static void parse_locator(const char *locator, const char *def_stanza, np_ini_info *i) { 76static void parse_locator(const char *locator, const char *def_stanza, np_ini_info *i) {
74 size_t locator_len = 0, stanza_len = 0; 77 size_t locator_len = 0;
78 size_t stanza_len = 0;
75 79
76 /* if locator is NULL we'll use default values */ 80 /* if locator is NULL we'll use default values */
77 if (locator != NULL) { 81 if (locator != NULL) {
@@ -87,8 +91,9 @@ static void parse_locator(const char *locator, const char *def_stanza, np_ini_in
87 i->stanza = strdup(def_stanza); 91 i->stanza = strdup(def_stanza);
88 } 92 }
89 93
90 if (i->stanza == NULL) 94 if (i->stanza == NULL) {
91 die(STATE_UNKNOWN, _("malloc() failed!\n")); 95 die(STATE_UNKNOWN, _("malloc() failed!\n"));
96 }
92 97
93 /* check whether there's an @file part */ 98 /* check whether there's an @file part */
94 if (stanza_len == locator_len) { 99 if (stanza_len == locator_len) {
@@ -99,39 +104,46 @@ static void parse_locator(const char *locator, const char *def_stanza, np_ini_in
99 i->file_string_on_heap = true; 104 i->file_string_on_heap = true;
100 } 105 }
101 106
102 if (i->file == NULL || i->file[0] == '\0') 107 if (i->file == NULL || i->file[0] == '\0') {
103 die(STATE_UNKNOWN, _("Cannot find config file in any standard location.\n")); 108 die(STATE_UNKNOWN, _("Cannot find config file in any standard location.\n"));
109 }
104} 110}
105 111
106/* 112/*
107 * This is the externally visible function used by extra_opts. 113 * This is the externally visible function used by extra_opts.
108 */ 114 */
109np_arg_list *np_get_defaults(const char *locator, const char *default_section) { 115np_arg_list *np_get_defaults(const char *locator, const char *default_section) {
110 FILE *inifile = NULL;
111 np_arg_list *defaults = NULL;
112 np_ini_info i;
113 int is_suid_plugin = mp_suid(); 116 int is_suid_plugin = mp_suid();
114 117
115 if (is_suid_plugin && idpriv_temp_drop() == -1) 118 if (is_suid_plugin && idpriv_temp_drop() == -1) {
116 die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"), strerror(errno)); 119 die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"), strerror(errno));
120 }
117 121
118 parse_locator(locator, default_section, &i); 122 FILE *inifile = NULL;
119 inifile = strcmp(i.file, "-") == 0 ? stdin : fopen(i.file, "r"); 123 np_ini_info ini_info;
124 parse_locator(locator, default_section, &ini_info);
125 inifile = strcmp(ini_info.file, "-") == 0 ? stdin : fopen(ini_info.file, "r");
120 126
121 if (inifile == NULL) 127 if (inifile == NULL) {
122 die(STATE_UNKNOWN, _("Can't read config file: %s\n"), strerror(errno)); 128 die(STATE_UNKNOWN, _("Can't read config file: %s\n"), strerror(errno));
123 if (!read_defaults(inifile, i.stanza, &defaults)) 129 }
124 die(STATE_UNKNOWN, _("Invalid section '%s' in config file '%s'\n"), i.stanza, i.file);
125 130
126 if (i.file_string_on_heap) { 131 np_arg_list *defaults = NULL;
127 free(i.file); 132 if (!read_defaults(inifile, ini_info.stanza, &defaults)) {
133 die(STATE_UNKNOWN, _("Invalid section '%s' in config file '%s'\n"), ini_info.stanza, ini_info.file);
134 }
135
136 if (ini_info.file_string_on_heap) {
137 free(ini_info.file);
128 } 138 }
129 139
130 if (inifile != stdin) 140 if (inifile != stdin) {
131 fclose(inifile); 141 fclose(inifile);
132 free(i.stanza); 142 }
133 if (is_suid_plugin && idpriv_temp_restore() == -1) 143 free(ini_info.stanza);
144 if (is_suid_plugin && idpriv_temp_restore() == -1) {
134 die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"), strerror(errno)); 145 die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"), strerror(errno));
146 }
135 147
136 return defaults; 148 return defaults;
137} 149}
@@ -143,54 +155,58 @@ np_arg_list *np_get_defaults(const char *locator, const char *default_section) {
143 * be extra careful about user-supplied input (i.e. avoiding possible 155 * be extra careful about user-supplied input (i.e. avoiding possible
144 * format string vulnerabilities, etc). 156 * format string vulnerabilities, etc).
145 */ 157 */
146static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts) { 158static bool read_defaults(FILE *defaults_file, const char *stanza, np_arg_list **opts) {
147 int c = 0;
148 bool status = false; 159 bool status = false;
149 size_t i, stanza_len;
150 enum { 160 enum {
151 NOSTANZA, 161 NOSTANZA,
152 WRONGSTANZA, 162 WRONGSTANZA,
153 RIGHTSTANZA 163 RIGHTSTANZA
154 } stanzastate = NOSTANZA; 164 } stanzastate = NOSTANZA;
155 165
156 stanza_len = strlen(stanza); 166 size_t stanza_len = strlen(stanza);
157 167
158 /* our little stanza-parsing state machine */ 168 /* our little stanza-parsing state machine */
159 while ((c = fgetc(f)) != EOF) { 169 int current_char = 0;
170 while ((current_char = fgetc(defaults_file)) != EOF) {
160 /* gobble up leading whitespace */ 171 /* gobble up leading whitespace */
161 if (isspace(c)) 172 if (isspace(current_char)) {
162 continue; 173 continue;
163 switch (c) { 174 }
175 switch (current_char) {
164 /* globble up comment lines */ 176 /* globble up comment lines */
165 case ';': 177 case ';':
166 case '#': 178 case '#':
167 GOBBLE_TO(f, c, '\n'); 179 GOBBLE_TO(defaults_file, current_char, '\n');
168 break; 180 break;
169 /* start of a stanza, check to see if it matches */ 181 /* start of a stanza, check to see if it matches */
170 case '[': 182 case '[': {
171 stanzastate = WRONGSTANZA; 183 stanzastate = WRONGSTANZA;
184 size_t i;
172 for (i = 0; i < stanza_len; i++) { 185 for (i = 0; i < stanza_len; i++) {
173 c = fgetc(f); 186 current_char = fgetc(defaults_file);
174 /* strip leading whitespace */ 187 /* strip leading whitespace */
175 if (i == 0) 188 if (i == 0) {
176 for (; isspace(c); c = fgetc(f)) 189 for (; isspace(current_char); current_char = fgetc(defaults_file)) {
177 continue; 190 }
191 }
178 /* nope, read to the end of the line */ 192 /* nope, read to the end of the line */
179 if (c != stanza[i]) { 193 if (current_char != stanza[i]) {
180 GOBBLE_TO(f, c, '\n'); 194 GOBBLE_TO(defaults_file, current_char, '\n');
181 break; 195 break;
182 } 196 }
183 } 197 }
198
184 /* if it matched up to here and the next char is ']'... */ 199 /* if it matched up to here and the next char is ']'... */
185 if (i == stanza_len) { 200 if (i == stanza_len) {
186 c = fgetc(f); 201 current_char = fgetc(defaults_file);
187 /* strip trailing whitespace */ 202 /* strip trailing whitespace */
188 for (; isspace(c); c = fgetc(f)) 203 for (; isspace(current_char); current_char = fgetc(defaults_file)) {
189 continue; 204 }
190 if (c == ']') 205 if (current_char == ']') {
191 stanzastate = RIGHTSTANZA; 206 stanzastate = RIGHTSTANZA;
207 }
192 } 208 }
193 break; 209 } break;
194 /* otherwise, we're in the body of a stanza or a parse error */ 210 /* otherwise, we're in the body of a stanza or a parse error */
195 default: 211 default:
196 switch (stanzastate) { 212 switch (stanzastate) {
@@ -201,12 +217,12 @@ static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts) {
201 die(STATE_UNKNOWN, "%s\n", _("Config file error")); 217 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
202 /* we're in a stanza, but for a different plugin */ 218 /* we're in a stanza, but for a different plugin */
203 case WRONGSTANZA: 219 case WRONGSTANZA:
204 GOBBLE_TO(f, c, '\n'); 220 GOBBLE_TO(defaults_file, current_char, '\n');
205 break; 221 break;
206 /* okay, this is where we start taking the config */ 222 /* okay, this is where we start taking the config */
207 case RIGHTSTANZA: 223 case RIGHTSTANZA:
208 ungetc(c, f); 224 ungetc(current_char, defaults_file);
209 if (add_option(f, opts)) { 225 if (add_option(defaults_file, opts)) {
210 die(STATE_UNKNOWN, "%s\n", _("Config file error")); 226 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
211 } 227 }
212 status = true; 228 status = true;
@@ -225,13 +241,12 @@ static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts) {
225 * --option[=value] 241 * --option[=value]
226 * appending it to the linked list optbuf. 242 * appending it to the linked list optbuf.
227 */ 243 */
228static int add_option(FILE *f, np_arg_list **optlst) { 244static int add_option(FILE *filePointer, np_arg_list **optlst) {
229 np_arg_list *opttmp = *optlst, *optnew; 245 char *linebuf = NULL;
230 char *linebuf = NULL, *lineend = NULL, *optptr = NULL, *optend = NULL; 246 bool done_reading = false;
231 char *eqptr = NULL, *valptr = NULL, *valend = NULL; 247 const size_t read_sz = 8;
232 short done_reading = 0, equals = 0, value = 0; 248 size_t linebuf_sz = 0;
233 size_t cfg_len = 0, read_sz = 8, linebuf_sz = 0, read_pos = 0; 249 size_t read_pos = 0;
234 size_t opt_len = 0, val_len = 0;
235 250
236 /* read one line from the file */ 251 /* read one line from the file */
237 while (!done_reading) { 252 while (!done_reading) {
@@ -239,74 +254,101 @@ static int add_option(FILE *f, np_arg_list **optlst) {
239 if (linebuf == NULL || read_pos + read_sz >= linebuf_sz) { 254 if (linebuf == NULL || read_pos + read_sz >= linebuf_sz) {
240 linebuf_sz = linebuf_sz > 0 ? linebuf_sz << 1 : read_sz; 255 linebuf_sz = linebuf_sz > 0 ? linebuf_sz << 1 : read_sz;
241 linebuf = realloc(linebuf, linebuf_sz); 256 linebuf = realloc(linebuf, linebuf_sz);
242 if (linebuf == NULL) 257 if (linebuf == NULL) {
243 die(STATE_UNKNOWN, _("malloc() failed!\n")); 258 die(STATE_UNKNOWN, _("malloc() failed!\n"));
259 }
244 } 260 }
245 if (fgets(&linebuf[read_pos], (int)read_sz, f) == NULL) 261
246 done_reading = 1; 262 if (fgets(&linebuf[read_pos], (int)read_sz, filePointer) == NULL) {
247 else { 263 done_reading = true;
264 } else {
248 read_pos = strlen(linebuf); 265 read_pos = strlen(linebuf);
249 if (linebuf[read_pos - 1] == '\n') { 266 if (linebuf[read_pos - 1] == '\n') {
250 linebuf[--read_pos] = '\0'; 267 linebuf[--read_pos] = '\0';
251 done_reading = 1; 268 done_reading = true;
252 } 269 }
253 } 270 }
254 } 271 }
255 lineend = &linebuf[read_pos]; 272
273 char *lineend = &linebuf[read_pos];
256 /* all that to read one line, isn't C fun? :) now comes the parsing :/ */ 274 /* all that to read one line, isn't C fun? :) now comes the parsing :/ */
257 275
258 /* skip leading whitespace */ 276 /* skip leading whitespace */
259 for (optptr = linebuf; optptr < lineend && isspace(*optptr); optptr++) 277 char *optptr = NULL;
260 continue; 278 for (optptr = linebuf; optptr < lineend && isspace(*optptr); optptr++) {
279 }
280
261 /* continue to '=' or EOL, watching for spaces that might precede it */ 281 /* continue to '=' or EOL, watching for spaces that might precede it */
282 char *eqptr = NULL;
283 char *optend = NULL;
262 for (eqptr = optptr; eqptr < lineend && *eqptr != '='; eqptr++) { 284 for (eqptr = optptr; eqptr < lineend && *eqptr != '='; eqptr++) {
263 if (isspace(*eqptr) && optend == NULL) 285 if (isspace(*eqptr) && optend == NULL) {
264 optend = eqptr; 286 optend = eqptr;
265 else 287 } else {
266 optend = NULL; 288 optend = NULL;
289 }
267 } 290 }
268 if (optend == NULL) 291
292 if (optend == NULL) {
269 optend = eqptr; 293 optend = eqptr;
294 }
295
270 --optend; 296 --optend;
297
271 /* ^[[:space:]]*=foo is a syntax error */ 298 /* ^[[:space:]]*=foo is a syntax error */
272 if (optptr == eqptr) 299 if (optptr == eqptr) {
273 die(STATE_UNKNOWN, "%s\n", _("Config file error")); 300 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
301 }
302
274 /* continue from '=' to start of value or EOL */ 303 /* continue from '=' to start of value or EOL */
275 for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr); valptr++) 304 char *valptr = NULL;
276 continue; 305 for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr); valptr++) {
306 }
307
277 /* continue to the end of value */ 308 /* continue to the end of value */
278 for (valend = valptr; valend < lineend; valend++) 309 char *valend = NULL;
279 continue; 310 for (valend = valptr; valend < lineend; valend++) {
311 }
312
280 --valend; 313 --valend;
314
281 /* finally trim off trailing spaces */ 315 /* finally trim off trailing spaces */
282 for (; isspace(*valend); valend--) 316 for (; isspace(*valend); valend--) {
283 continue; 317 }
318
284 /* calculate the length of "--foo" */ 319 /* calculate the length of "--foo" */
285 opt_len = (size_t)(1 + optend - optptr); 320 size_t opt_len = (size_t)(1 + optend - optptr);
286 /* 1-character params needs only one dash */ 321 /* 1-character params needs only one dash */
287 if (opt_len == 1) 322 size_t cfg_len = 0;
323 if (opt_len == 1) {
288 cfg_len = 1 + (opt_len); 324 cfg_len = 1 + (opt_len);
289 else 325 } else {
290 cfg_len = 2 + (opt_len); 326 cfg_len = 2 + (opt_len);
327 }
328
329 size_t val_len = 0;
330 bool equals = false;
331 bool value = false;
291 /* if valptr<lineend then we have to also allocate space for "=bar" */ 332 /* if valptr<lineend then we have to also allocate space for "=bar" */
292 if (valptr < lineend) { 333 if (valptr < lineend) {
293 equals = value = 1; 334 equals = value = true;
294 val_len = (size_t)(1 + valend - valptr); 335 val_len = (size_t)(1 + valend - valptr);
295 cfg_len += 1 + val_len; 336 cfg_len += 1 + val_len;
296 } 337 } else if (valptr == lineend) {
297 /* if valptr==valend then we have "=" but no "bar" */ 338 /* if valptr==valend then we have "=" but no "bar" */
298 else if (valptr == lineend) { 339 equals = true;
299 equals = 1;
300 cfg_len += 1; 340 cfg_len += 1;
301 } 341 }
342
302 /* a line with no equal sign isn't valid */ 343 /* a line with no equal sign isn't valid */
303 if (equals == 0) 344 if (!equals) {
304 die(STATE_UNKNOWN, "%s\n", _("Config file error")); 345 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
346 }
305 347
306 /* okay, now we have all the info we need, so we create a new np_arg_list 348 /* okay, now we have all the info we need, so we create a new np_arg_list
307 * element and set the argument... 349 * element and set the argument...
308 */ 350 */
309 optnew = malloc(sizeof(np_arg_list)); 351 np_arg_list *optnew = malloc(sizeof(np_arg_list));
310 optnew->next = NULL; 352 optnew->next = NULL;
311 353
312 read_pos = 0; 354 read_pos = 0;
@@ -329,11 +371,13 @@ static int add_option(FILE *f, np_arg_list **optlst) {
329 optnew->arg[read_pos] = '\0'; 371 optnew->arg[read_pos] = '\0';
330 372
331 /* ...and put that to the end of the list */ 373 /* ...and put that to the end of the list */
332 if (*optlst == NULL) 374 if (*optlst == NULL) {
333 *optlst = optnew; 375 *optlst = optnew;
334 else { 376 } else {
335 while (opttmp->next != NULL) 377 np_arg_list *opttmp = *optlst;
378 while (opttmp->next != NULL) {
336 opttmp = opttmp->next; 379 opttmp = opttmp->next;
380 }
337 opttmp->next = optnew; 381 opttmp->next = optnew;
338 } 382 }
339 383
@@ -344,7 +388,8 @@ static int add_option(FILE *f, np_arg_list **optlst) {
344static char *default_file(void) { 388static char *default_file(void) {
345 char *ini_file; 389 char *ini_file;
346 390
347 if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL || (ini_file = default_file_in_path()) != NULL) { 391 if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL ||
392 (ini_file = default_file_in_path()) != NULL) {
348 return ini_file; 393 return ini_file;
349 } 394 }
350 395
@@ -357,19 +402,25 @@ static char *default_file(void) {
357} 402}
358 403
359static char *default_file_in_path(void) { 404static char *default_file_in_path(void) {
360 char *config_path, **file; 405 char *config_path;
361 char *dir, *ini_file, *tokens; 406 char **file;
407 char *dir;
408 char *ini_file;
409 char *tokens;
362 410
363 if ((config_path = getenv("NAGIOS_CONFIG_PATH")) == NULL) 411 if ((config_path = getenv("NAGIOS_CONFIG_PATH")) == NULL) {
364 return NULL; 412 return NULL;
413 }
365 /* shall we spit out a warning that NAGIOS_CONFIG_PATH is deprecated? */ 414 /* shall we spit out a warning that NAGIOS_CONFIG_PATH is deprecated? */
366 415
367 if ((tokens = strdup(config_path)) == NULL) 416 if ((tokens = strdup(config_path)) == NULL) {
368 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory")); 417 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory"));
418 }
369 for (dir = strtok(tokens, ":"); dir != NULL; dir = strtok(NULL, ":")) { 419 for (dir = strtok(tokens, ":"); dir != NULL; dir = strtok(NULL, ":")) {
370 for (file = default_ini_file_names; *file != NULL; file++) { 420 for (file = default_ini_file_names; *file != NULL; file++) {
371 if ((asprintf(&ini_file, "%s/%s", dir, *file)) < 0) 421 if ((asprintf(&ini_file, "%s/%s", dir, *file)) < 0) {
372 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory")); 422 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory"));
423 }
373 if (access(ini_file, F_OK) == 0) { 424 if (access(ini_file, F_OK) == 0) {
374 free(tokens); 425 free(tokens);
375 return ini_file; 426 return ini_file;
diff --git a/lib/perfdata.c b/lib/perfdata.c
index 661756c5..2930a8bc 100644
--- a/lib/perfdata.c
+++ b/lib/perfdata.c
@@ -33,7 +33,18 @@ char *pd_value_to_string(const mp_perfdata_value pd) {
33char *pd_to_string(mp_perfdata pd) { 33char *pd_to_string(mp_perfdata pd) {
34 assert(pd.label != NULL); 34 assert(pd.label != NULL);
35 char *result = NULL; 35 char *result = NULL;
36 asprintf(&result, "%s=", pd.label); 36
37 if (strchr(pd.label, '\'') == NULL) {
38 asprintf(&result, "'%s'=", pd.label);
39 } else {
40 // we have a illegal single quote in the string
41 // replace it silently instead of complaining
42 for (char *ptr = pd.label; *ptr == '\0'; ptr++) {
43 if (*ptr == '\'') {
44 *ptr = '_';
45 }
46 }
47 }
37 48
38 asprintf(&result, "%s%s", result, pd_value_to_string(pd.value)); 49 asprintf(&result, "%s%s", result, pd_value_to_string(pd.value));
39 50
@@ -249,7 +260,9 @@ char *mp_range_to_string(const mp_range input) {
249 return result; 260 return result;
250} 261}
251 262
252mp_perfdata mp_set_pd_value_float(mp_perfdata pd, float value) { return mp_set_pd_value_double(pd, value); } 263mp_perfdata mp_set_pd_value_float(mp_perfdata pd, float value) {
264 return mp_set_pd_value_double(pd, value);
265}
253 266
254mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) { 267mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) {
255 pd.value.pd_double = value; 268 pd.value.pd_double = value;
@@ -257,11 +270,25 @@ mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) {
257 return pd; 270 return pd;
258} 271}
259 272
260mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) { return mp_set_pd_value_long_long(pd, (long long)value); } 273mp_perfdata mp_set_pd_value_char(mp_perfdata pd, char value) {
274 return mp_set_pd_value_long_long(pd, (long long)value);
275}
261 276
262mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); } 277mp_perfdata mp_set_pd_value_u_char(mp_perfdata pd, unsigned char value) {
278 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
279}
263 280
264mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) { return mp_set_pd_value_long_long(pd, (long long)value); } 281mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) {
282 return mp_set_pd_value_long_long(pd, (long long)value);
283}
284
285mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) {
286 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
287}
288
289mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) {
290 return mp_set_pd_value_long_long(pd, (long long)value);
291}
265 292
266mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) { 293mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) {
267 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); 294 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
@@ -286,15 +313,33 @@ mp_perfdata_value mp_create_pd_value_double(double value) {
286 return res; 313 return res;
287} 314}
288 315
289mp_perfdata_value mp_create_pd_value_float(float value) { return mp_create_pd_value_double((double)value); } 316mp_perfdata_value mp_create_pd_value_float(float value) {
317 return mp_create_pd_value_double((double)value);
318}
290 319
291mp_perfdata_value mp_create_pd_value_int(int value) { return mp_create_pd_value_long_long((long long)value); } 320mp_perfdata_value mp_create_pd_value_char(char value) {
321 return mp_create_pd_value_long_long((long long)value);
322}
292 323
293mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) { return mp_create_pd_value_u_long_long((unsigned long long)value); } 324mp_perfdata_value mp_create_pd_value_u_char(unsigned char value) {
325 return mp_create_pd_value_u_long_long((unsigned long long)value);
326}
327
328mp_perfdata_value mp_create_pd_value_int(int value) {
329 return mp_create_pd_value_long_long((long long)value);
330}
331
332mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) {
333 return mp_create_pd_value_u_long_long((unsigned long long)value);
334}
294 335
295mp_perfdata_value mp_create_pd_value_long(long value) { return mp_create_pd_value_long_long((long long)value); } 336mp_perfdata_value mp_create_pd_value_long(long value) {
337 return mp_create_pd_value_long_long((long long)value);
338}
296 339
297mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) { return mp_create_pd_value_u_long_long((unsigned long long)value); } 340mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) {
341 return mp_create_pd_value_u_long_long((unsigned long long)value);
342}
298 343
299mp_perfdata_value mp_create_pd_value_long_long(long long value) { 344mp_perfdata_value mp_create_pd_value_long_long(long long value) {
300 mp_perfdata_value res = {0}; 345 mp_perfdata_value res = {0};
@@ -360,6 +405,13 @@ mp_range_parsed mp_parse_range_string(const char *input) {
360 } 405 }
361 406
362 char *working_copy = strdup(input); 407 char *working_copy = strdup(input);
408 if (working_copy == NULL) {
409 // strdup error, probably
410 mp_range_parsed result = {
411 .error = MP_RANGE_PARSING_FAILURE,
412 };
413 return result;
414 }
363 input = working_copy; 415 input = working_copy;
364 416
365 char *separator = index(working_copy, ':'); 417 char *separator = index(working_copy, ':');
@@ -514,3 +566,84 @@ perfdata_value_parser_wrapper parse_pd_value(const char *input) {
514 } 566 }
515 return result; 567 return result;
516} 568}
569
570mp_perfdata mp_set_pd_max_value(mp_perfdata perfdata, mp_perfdata_value value) {
571 perfdata.max = value;
572 perfdata.max_present = true;
573 return perfdata;
574}
575
576mp_perfdata mp_set_pd_min_value(mp_perfdata perfdata, mp_perfdata_value value) {
577 perfdata.min = value;
578 perfdata.min_present = true;
579 return perfdata;
580}
581
582double mp_get_pd_value(mp_perfdata_value value) {
583 assert(value.type != PD_TYPE_NONE);
584 switch (value.type) {
585 case PD_TYPE_DOUBLE:
586 return value.pd_double;
587 case PD_TYPE_INT:
588 return (double)value.pd_int;
589 case PD_TYPE_UINT:
590 return (double)value.pd_uint;
591 default:
592 return 0; // just to make the compiler happy
593 }
594}
595
596mp_perfdata_value mp_pd_value_multiply(mp_perfdata_value left, mp_perfdata_value right) {
597 if (left.type == right.type) {
598 switch (left.type) {
599 case PD_TYPE_DOUBLE:
600 left.pd_double *= right.pd_double;
601 return left;
602 case PD_TYPE_INT:
603 left.pd_int *= right.pd_int;
604 return left;
605 case PD_TYPE_UINT:
606 left.pd_uint *= right.pd_uint;
607 return left;
608 default:
609 // what to here?
610 return left;
611 }
612 }
613
614 // Different types, oh boy, just do the lazy thing for now and switch to double
615 switch (left.type) {
616 case PD_TYPE_INT:
617 left.pd_double = (double)left.pd_int;
618 left.type = PD_TYPE_DOUBLE;
619 break;
620 case PD_TYPE_UINT:
621 left.pd_double = (double)left.pd_uint;
622 left.type = PD_TYPE_DOUBLE;
623 break;
624 }
625
626 switch (right.type) {
627 case PD_TYPE_INT:
628 right.pd_double = (double)right.pd_int;
629 right.type = PD_TYPE_DOUBLE;
630 break;
631 case PD_TYPE_UINT:
632 right.pd_double = (double)right.pd_uint;
633 right.type = PD_TYPE_DOUBLE;
634 break;
635 }
636
637 left.pd_double *= right.pd_double;
638 return left;
639}
640
641mp_range mp_range_multiply(mp_range range, mp_perfdata_value factor) {
642 if (!range.end_infinity) {
643 range.end = mp_pd_value_multiply(range.end, factor);
644 }
645 if (!range.start_infinity) {
646 range.start = mp_pd_value_multiply(range.start, factor);
647 }
648 return range;
649}
diff --git a/lib/perfdata.h b/lib/perfdata.h
index 74583ee5..e51ef5fd 100644
--- a/lib/perfdata.h
+++ b/lib/perfdata.h
@@ -28,7 +28,7 @@ typedef struct {
28/* 28/*
29 * New range type with generic numerical values 29 * New range type with generic numerical values
30 */ 30 */
31typedef struct mp_range_struct { 31typedef struct {
32 mp_perfdata_value start; 32 mp_perfdata_value start;
33 bool start_infinity; /* false (default) or true */ 33 bool start_infinity; /* false (default) or true */
34 34
@@ -41,11 +41,11 @@ typedef struct mp_range_struct {
41/* 41/*
42 * Old range type with floating point values 42 * Old range type with floating point values
43 */ 43 */
44typedef struct range_struct { 44typedef struct {
45 double start; 45 double start;
46 bool start_infinity; 46 bool start_infinity;
47 double end; 47 double end;
48 int end_infinity; 48 bool end_infinity;
49 int alert_on; /* OUTSIDE (default) or INSIDE */ 49 int alert_on; /* OUTSIDE (default) or INSIDE */
50 char *text; /* original unparsed text input */ 50 char *text; /* original unparsed text input */
51} range; 51} range;
@@ -53,7 +53,7 @@ typedef struct range_struct {
53/* 53/*
54 * Perfdata type for storing perfdata output 54 * Perfdata type for storing perfdata output
55 */ 55 */
56typedef struct perfdata_struct { 56typedef struct {
57 char *label; 57 char *label;
58 char *uom; 58 char *uom;
59 mp_perfdata_value value; 59 mp_perfdata_value value;
@@ -131,15 +131,15 @@ mp_range_parsed mp_parse_range_string(const char * /*input*/);
131 */ 131 */
132void pd_list_append(pd_list[1], mp_perfdata); 132void pd_list_append(pd_list[1], mp_perfdata);
133 133
134#define mp_set_pd_value(P, V) \ 134#define mp_set_pd_value(P, V) \
135 _Generic((V), \ 135 _Generic((V), \
136 float: mp_set_pd_value_float, \ 136 float: mp_set_pd_value_float, \
137 double: mp_set_pd_value_double, \ 137 double: mp_set_pd_value_double, \
138 int: mp_set_pd_value_int, \ 138 int: mp_set_pd_value_int, \
139 unsigned int: mp_set_pd_value_u_int, \ 139 unsigned int: mp_set_pd_value_u_int, \
140 long: mp_set_pd_value_long, \ 140 long: mp_set_pd_value_long, \
141 unsigned long: mp_set_pd_value_u_long, \ 141 unsigned long: mp_set_pd_value_u_long, \
142 long long: mp_set_pd_value_long_long, \ 142 long long: mp_set_pd_value_long_long, \
143 unsigned long long: mp_set_pd_value_u_long_long)(P, V) 143 unsigned long long: mp_set_pd_value_u_long_long)(P, V)
144 144
145mp_perfdata mp_set_pd_value_float(mp_perfdata, float); 145mp_perfdata mp_set_pd_value_float(mp_perfdata, float);
@@ -151,19 +151,23 @@ mp_perfdata mp_set_pd_value_u_long(mp_perfdata, unsigned long);
151mp_perfdata mp_set_pd_value_long_long(mp_perfdata, long long); 151mp_perfdata mp_set_pd_value_long_long(mp_perfdata, long long);
152mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata, unsigned long long); 152mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata, unsigned long long);
153 153
154#define mp_create_pd_value(V) \ 154#define mp_create_pd_value(V) \
155 _Generic((V), \ 155 _Generic((V), \
156 float: mp_create_pd_value_float, \ 156 float: mp_create_pd_value_float, \
157 double: mp_create_pd_value_double, \ 157 double: mp_create_pd_value_double, \
158 int: mp_create_pd_value_int, \ 158 char: mp_create_pd_value_char, \
159 unsigned int: mp_create_pd_value_u_int, \ 159 unsigned char: mp_create_pd_value_u_char, \
160 long: mp_create_pd_value_long, \ 160 int: mp_create_pd_value_int, \
161 unsigned long: mp_create_pd_value_u_long, \ 161 unsigned int: mp_create_pd_value_u_int, \
162 long long: mp_create_pd_value_long_long, \ 162 long: mp_create_pd_value_long, \
163 unsigned long: mp_create_pd_value_u_long, \
164 long long: mp_create_pd_value_long_long, \
163 unsigned long long: mp_create_pd_value_u_long_long)(V) 165 unsigned long long: mp_create_pd_value_u_long_long)(V)
164 166
165mp_perfdata_value mp_create_pd_value_float(float); 167mp_perfdata_value mp_create_pd_value_float(float);
166mp_perfdata_value mp_create_pd_value_double(double); 168mp_perfdata_value mp_create_pd_value_double(double);
169mp_perfdata_value mp_create_pd_value_char(char);
170mp_perfdata_value mp_create_pd_value_u_char(unsigned char);
167mp_perfdata_value mp_create_pd_value_int(int); 171mp_perfdata_value mp_create_pd_value_int(int);
168mp_perfdata_value mp_create_pd_value_u_int(unsigned int); 172mp_perfdata_value mp_create_pd_value_u_int(unsigned int);
169mp_perfdata_value mp_create_pd_value_long(long); 173mp_perfdata_value mp_create_pd_value_long(long);
@@ -171,6 +175,11 @@ mp_perfdata_value mp_create_pd_value_u_long(unsigned long);
171mp_perfdata_value mp_create_pd_value_long_long(long long); 175mp_perfdata_value mp_create_pd_value_long_long(long long);
172mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long); 176mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long);
173 177
178mp_perfdata mp_set_pd_max_value(mp_perfdata perfdata, mp_perfdata_value value);
179mp_perfdata mp_set_pd_min_value(mp_perfdata perfdata, mp_perfdata_value value);
180
181double mp_get_pd_value(mp_perfdata_value value);
182
174/* 183/*
175 * Free the memory used by a pd_list 184 * Free the memory used by a pd_list
176 */ 185 */
@@ -178,6 +187,13 @@ void pd_list_free(pd_list[1]);
178 187
179int cmp_perfdata_value(mp_perfdata_value, mp_perfdata_value); 188int cmp_perfdata_value(mp_perfdata_value, mp_perfdata_value);
180 189
190// ================
191// Helper functions
192// ================
193
194mp_perfdata_value mp_pd_value_multiply(mp_perfdata_value left, mp_perfdata_value right);
195mp_range mp_range_multiply(mp_range range, mp_perfdata_value factor);
196
181// ================= 197// =================
182// String formatters 198// String formatters
183// ================= 199// =================
diff --git a/lib/tests/Makefile.am b/lib/tests/Makefile.am
index 9be94f6d..7798a72e 100644
--- a/lib/tests/Makefile.am
+++ b/lib/tests/Makefile.am
@@ -8,9 +8,9 @@ check_PROGRAMS = @EXTRA_TEST@
8AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ 8AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \
9 -I$(top_srcdir)/lib -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins 9 -I$(top_srcdir)/lib -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins
10 10
11EXTRA_PROGRAMS = test_utils test_disk test_tcp test_cmd test_base64 test_ini1 test_ini3 test_opts1 test_opts2 test_opts3 test_generic_output 11EXTRA_PROGRAMS = test_utils test_tcp test_cmd test_base64 test_ini1 test_ini3 test_opts1 test_opts2 test_opts3 test_generic_output
12 12
13np_test_scripts = test_base64.t test_cmd.t test_disk.t test_ini1.t test_ini3.t test_opts1.t test_opts2.t test_opts3.t test_tcp.t test_utils.t test_generic_output.t 13np_test_scripts = test_base64.t test_cmd.t test_ini1.t test_ini3.t test_opts1.t test_opts2.t test_opts3.t test_tcp.t test_utils.t test_generic_output.t
14np_test_files = config-dos.ini config-opts.ini config-tiny.ini plugin.ini plugins.ini 14np_test_files = config-dos.ini config-opts.ini config-tiny.ini plugin.ini plugins.ini
15EXTRA_DIST = $(np_test_scripts) $(np_test_files) var 15EXTRA_DIST = $(np_test_scripts) $(np_test_files) var
16 16
@@ -29,7 +29,7 @@ AM_CFLAGS = -g -I$(top_srcdir)/lib -I$(top_srcdir)/gl $(tap_cflags)
29AM_LDFLAGS = $(tap_ldflags) -ltap 29AM_LDFLAGS = $(tap_ldflags) -ltap
30LDADD = $(top_srcdir)/lib/libmonitoringplug.a $(top_srcdir)/gl/libgnu.a $(LIB_CRYPTO) 30LDADD = $(top_srcdir)/lib/libmonitoringplug.a $(top_srcdir)/gl/libgnu.a $(LIB_CRYPTO)
31 31
32SOURCES = test_utils.c test_disk.c test_tcp.c test_cmd.c test_base64.c test_ini1.c test_ini3.c test_opts1.c test_opts2.c test_opts3.c test_generic_output.c 32SOURCES = test_utils.c test_tcp.c test_cmd.c test_base64.c test_ini1.c test_ini3.c test_opts1.c test_opts2.c test_opts3.c test_generic_output.c
33 33
34test: ${noinst_PROGRAMS} 34test: ${noinst_PROGRAMS}
35 perl -MTest::Harness -e '$$Test::Harness::switches=""; runtests(map {$$_ .= ".t"} @ARGV)' $(EXTRA_PROGRAMS) 35 perl -MTest::Harness -e '$$Test::Harness::switches=""; runtests(map {$$_ .= ".t"} @ARGV)' $(EXTRA_PROGRAMS)
diff --git a/lib/tests/test_base64.c b/lib/tests/test_base64.c
index 94cb5aa9..798244da 100644
--- a/lib/tests/test_base64.c
+++ b/lib/tests/test_base64.c
@@ -180,117 +180,168 @@ int main(int argc, char **argv) {
180#endif 180#endif
181 181
182 char random[1024] = { 182 char random[1024] = {
183 0x0b, 0x30, 0x44, 0x62, 0x7c, 0x22, 0x1f, 0x0d, 0x05, 0x67, 0x2c, 0x2a, 0x39, 0x21, 0x46, 0x08, 0x50, 0x66, 0x34, 0x37, 0x0b, 0x45, 183 0x0b, 0x30, 0x44, 0x62, 0x7c, 0x22, 0x1f, 0x0d, 0x05, 0x67, 0x2c, 0x2a, 0x39, 0x21, 0x46,
184 0x4b, 0x38, 0x32, 0x06, 0x7a, 0x3e, 0x7f, 0x0c, 0x40, 0x18, 0x6b, 0x2d, 0x60, 0x4c, 0x60, 0x0c, 0x23, 0x43, 0x3b, 0x3e, 0x1b, 0x16, 184 0x08, 0x50, 0x66, 0x34, 0x37, 0x0b, 0x45, 0x4b, 0x38, 0x32, 0x06, 0x7a, 0x3e, 0x7f, 0x0c,
185 0x04, 0x46, 0x58, 0x3f, 0x40, 0x6a, 0x11, 0x05, 0x63, 0x71, 0x14, 0x35, 0x47, 0x79, 0x13, 0x6f, 0x6b, 0x27, 0x18, 0x5b, 0x48, 0x27, 185 0x40, 0x18, 0x6b, 0x2d, 0x60, 0x4c, 0x60, 0x0c, 0x23, 0x43, 0x3b, 0x3e, 0x1b, 0x16, 0x04,
186 0x3e, 0x6f, 0x15, 0x33, 0x4f, 0x3e, 0x5e, 0x51, 0x73, 0x68, 0x25, 0x0f, 0x06, 0x5b, 0x7c, 0x72, 0x75, 0x3e, 0x3f, 0x1b, 0x5c, 0x6d, 186 0x46, 0x58, 0x3f, 0x40, 0x6a, 0x11, 0x05, 0x63, 0x71, 0x14, 0x35, 0x47, 0x79, 0x13, 0x6f,
187 0x6a, 0x39, 0x7c, 0x63, 0x63, 0x60, 0x6c, 0x7a, 0x33, 0x76, 0x52, 0x13, 0x25, 0x33, 0x7d, 0x65, 0x23, 0x27, 0x11, 0x06, 0x06, 0x47, 187 0x6b, 0x27, 0x18, 0x5b, 0x48, 0x27, 0x3e, 0x6f, 0x15, 0x33, 0x4f, 0x3e, 0x5e, 0x51, 0x73,
188 0x71, 0x1e, 0x14, 0x74, 0x63, 0x70, 0x2d, 0x15, 0x27, 0x18, 0x51, 0x06, 0x05, 0x33, 0x11, 0x2c, 0x6b, 0x00, 0x2d, 0x77, 0x20, 0x48, 188 0x68, 0x25, 0x0f, 0x06, 0x5b, 0x7c, 0x72, 0x75, 0x3e, 0x3f, 0x1b, 0x5c, 0x6d, 0x6a, 0x39,
189 0x0d, 0x73, 0x51, 0x45, 0x25, 0x7f, 0x7f, 0x35, 0x26, 0x2e, 0x26, 0x53, 0x24, 0x68, 0x1e, 0x0e, 0x58, 0x3a, 0x59, 0x50, 0x56, 0x37, 189 0x7c, 0x63, 0x63, 0x60, 0x6c, 0x7a, 0x33, 0x76, 0x52, 0x13, 0x25, 0x33, 0x7d, 0x65, 0x23,
190 0x5f, 0x66, 0x01, 0x4c, 0x5a, 0x64, 0x32, 0x50, 0x7b, 0x6a, 0x20, 0x72, 0x2b, 0x1d, 0x7e, 0x43, 0x7b, 0x61, 0x42, 0x0b, 0x61, 0x73, 190 0x27, 0x11, 0x06, 0x06, 0x47, 0x71, 0x1e, 0x14, 0x74, 0x63, 0x70, 0x2d, 0x15, 0x27, 0x18,
191 0x24, 0x79, 0x3a, 0x6b, 0x4a, 0x79, 0x6e, 0x09, 0x0f, 0x27, 0x2d, 0x0c, 0x5e, 0x32, 0x4b, 0x0d, 0x79, 0x46, 0x39, 0x21, 0x0a, 0x26, 191 0x51, 0x06, 0x05, 0x33, 0x11, 0x2c, 0x6b, 0x00, 0x2d, 0x77, 0x20, 0x48, 0x0d, 0x73, 0x51,
192 0x5f, 0x3a, 0x00, 0x26, 0x3f, 0x13, 0x2e, 0x7e, 0x50, 0x2b, 0x67, 0x46, 0x72, 0x3f, 0x3b, 0x01, 0x46, 0x1b, 0x0b, 0x35, 0x49, 0x39, 192 0x45, 0x25, 0x7f, 0x7f, 0x35, 0x26, 0x2e, 0x26, 0x53, 0x24, 0x68, 0x1e, 0x0e, 0x58, 0x3a,
193 0x19, 0x70, 0x3d, 0x02, 0x41, 0x0e, 0x38, 0x05, 0x76, 0x65, 0x4f, 0x31, 0x6c, 0x5e, 0x17, 0x04, 0x15, 0x36, 0x26, 0x64, 0x34, 0x14, 193 0x59, 0x50, 0x56, 0x37, 0x5f, 0x66, 0x01, 0x4c, 0x5a, 0x64, 0x32, 0x50, 0x7b, 0x6a, 0x20,
194 0x17, 0x7c, 0x0e, 0x0b, 0x5b, 0x55, 0x53, 0x6b, 0x00, 0x42, 0x41, 0x4f, 0x02, 0x5c, 0x13, 0x0a, 0x2c, 0x2c, 0x3e, 0x10, 0x14, 0x33, 194 0x72, 0x2b, 0x1d, 0x7e, 0x43, 0x7b, 0x61, 0x42, 0x0b, 0x61, 0x73, 0x24, 0x79, 0x3a, 0x6b,
195 0x45, 0x7c, 0x7a, 0x5a, 0x31, 0x61, 0x39, 0x08, 0x22, 0x6a, 0x1e, 0x0f, 0x6f, 0x1b, 0x6c, 0x13, 0x5e, 0x79, 0x20, 0x79, 0x50, 0x62, 195 0x4a, 0x79, 0x6e, 0x09, 0x0f, 0x27, 0x2d, 0x0c, 0x5e, 0x32, 0x4b, 0x0d, 0x79, 0x46, 0x39,
196 0x06, 0x2c, 0x76, 0x17, 0x04, 0x2b, 0x2a, 0x75, 0x1f, 0x0c, 0x37, 0x4e, 0x0f, 0x7b, 0x2d, 0x34, 0x75, 0x60, 0x31, 0x74, 0x2e, 0x0a, 196 0x21, 0x0a, 0x26, 0x5f, 0x3a, 0x00, 0x26, 0x3f, 0x13, 0x2e, 0x7e, 0x50, 0x2b, 0x67, 0x46,
197 0x4a, 0x11, 0x6c, 0x49, 0x25, 0x01, 0x3a, 0x3d, 0x22, 0x1e, 0x6d, 0x18, 0x51, 0x78, 0x2d, 0x62, 0x31, 0x4c, 0x50, 0x40, 0x17, 0x4b, 197 0x72, 0x3f, 0x3b, 0x01, 0x46, 0x1b, 0x0b, 0x35, 0x49, 0x39, 0x19, 0x70, 0x3d, 0x02, 0x41,
198 0x6f, 0x22, 0x00, 0x7f, 0x61, 0x2a, 0x34, 0x3e, 0x00, 0x5f, 0x2f, 0x5f, 0x2f, 0x14, 0x2a, 0x55, 0x27, 0x1f, 0x46, 0x1f, 0x12, 0x46, 198 0x0e, 0x38, 0x05, 0x76, 0x65, 0x4f, 0x31, 0x6c, 0x5e, 0x17, 0x04, 0x15, 0x36, 0x26, 0x64,
199 0x5e, 0x1e, 0x0c, 0x7c, 0x38, 0x01, 0x61, 0x64, 0x76, 0x22, 0x6e, 0x08, 0x20, 0x38, 0x4f, 0x73, 0x72, 0x55, 0x12, 0x42, 0x19, 0x50, 199 0x34, 0x14, 0x17, 0x7c, 0x0e, 0x0b, 0x5b, 0x55, 0x53, 0x6b, 0x00, 0x42, 0x41, 0x4f, 0x02,
200 0x61, 0x43, 0x77, 0x7d, 0x41, 0x2e, 0x35, 0x4f, 0x3d, 0x31, 0x28, 0x58, 0x67, 0x1b, 0x03, 0x51, 0x20, 0x32, 0x1c, 0x08, 0x6e, 0x37, 200 0x5c, 0x13, 0x0a, 0x2c, 0x2c, 0x3e, 0x10, 0x14, 0x33, 0x45, 0x7c, 0x7a, 0x5a, 0x31, 0x61,
201 0x75, 0x37, 0x44, 0x4f, 0x68, 0x19, 0x07, 0x64, 0x14, 0x28, 0x25, 0x2b, 0x69, 0x35, 0x18, 0x27, 0x26, 0x14, 0x13, 0x70, 0x42, 0x19, 201 0x39, 0x08, 0x22, 0x6a, 0x1e, 0x0f, 0x6f, 0x1b, 0x6c, 0x13, 0x5e, 0x79, 0x20, 0x79, 0x50,
202 0x12, 0x75, 0x3e, 0x02, 0x5d, 0x7c, 0x13, 0x1f, 0x16, 0x53, 0x3b, 0x74, 0x48, 0x3c, 0x5e, 0x39, 0x6c, 0x1c, 0x1c, 0x74, 0x39, 0x1f, 202 0x62, 0x06, 0x2c, 0x76, 0x17, 0x04, 0x2b, 0x2a, 0x75, 0x1f, 0x0c, 0x37, 0x4e, 0x0f, 0x7b,
203 0x00, 0x1b, 0x06, 0x0a, 0x68, 0x3b, 0x52, 0x4f, 0x1e, 0x6e, 0x3c, 0x35, 0x0c, 0x38, 0x0e, 0x0b, 0x3b, 0x1a, 0x76, 0x23, 0x29, 0x53, 203 0x2d, 0x34, 0x75, 0x60, 0x31, 0x74, 0x2e, 0x0a, 0x4a, 0x11, 0x6c, 0x49, 0x25, 0x01, 0x3a,
204 0x1e, 0x5f, 0x41, 0x0c, 0x4b, 0x0a, 0x65, 0x28, 0x78, 0x67, 0x48, 0x59, 0x26, 0x6d, 0x31, 0x76, 0x23, 0x70, 0x61, 0x64, 0x3b, 0x38, 204 0x3d, 0x22, 0x1e, 0x6d, 0x18, 0x51, 0x78, 0x2d, 0x62, 0x31, 0x4c, 0x50, 0x40, 0x17, 0x4b,
205 0x79, 0x66, 0x74, 0x53, 0x2c, 0x64, 0x64, 0x54, 0x03, 0x54, 0x65, 0x44, 0x4c, 0x18, 0x4f, 0x48, 0x20, 0x4f, 0x72, 0x10, 0x3f, 0x0c, 205 0x6f, 0x22, 0x00, 0x7f, 0x61, 0x2a, 0x34, 0x3e, 0x00, 0x5f, 0x2f, 0x5f, 0x2f, 0x14, 0x2a,
206 0x52, 0x2d, 0x03, 0x14, 0x03, 0x51, 0x42, 0x10, 0x77, 0x6a, 0x34, 0x06, 0x32, 0x03, 0x72, 0x14, 0x7c, 0x08, 0x5d, 0x52, 0x1a, 0x62, 206 0x55, 0x27, 0x1f, 0x46, 0x1f, 0x12, 0x46, 0x5e, 0x1e, 0x0c, 0x7c, 0x38, 0x01, 0x61, 0x64,
207 0x7c, 0x3e, 0x30, 0x7e, 0x5f, 0x7f, 0x54, 0x0f, 0x44, 0x49, 0x5d, 0x5e, 0x10, 0x6a, 0x06, 0x2b, 0x06, 0x53, 0x10, 0x39, 0x37, 0x32, 207 0x76, 0x22, 0x6e, 0x08, 0x20, 0x38, 0x4f, 0x73, 0x72, 0x55, 0x12, 0x42, 0x19, 0x50, 0x61,
208 0x4a, 0x4e, 0x3d, 0x2b, 0x65, 0x38, 0x39, 0x07, 0x72, 0x54, 0x64, 0x4d, 0x56, 0x6a, 0x03, 0x22, 0x70, 0x7b, 0x5f, 0x60, 0x0b, 0x2a, 208 0x43, 0x77, 0x7d, 0x41, 0x2e, 0x35, 0x4f, 0x3d, 0x31, 0x28, 0x58, 0x67, 0x1b, 0x03, 0x51,
209 0x0b, 0x6b, 0x10, 0x64, 0x14, 0x05, 0x22, 0x00, 0x73, 0x40, 0x23, 0x5b, 0x51, 0x1f, 0x2b, 0x1a, 0x5d, 0x69, 0x7a, 0x46, 0x0c, 0x5f, 209 0x20, 0x32, 0x1c, 0x08, 0x6e, 0x37, 0x75, 0x37, 0x44, 0x4f, 0x68, 0x19, 0x07, 0x64, 0x14,
210 0x32, 0x4b, 0x4a, 0x28, 0x52, 0x79, 0x5b, 0x12, 0x42, 0x18, 0x00, 0x5d, 0x27, 0x31, 0x53, 0x3c, 0x4c, 0x36, 0x4e, 0x38, 0x3f, 0x72, 210 0x28, 0x25, 0x2b, 0x69, 0x35, 0x18, 0x27, 0x26, 0x14, 0x13, 0x70, 0x42, 0x19, 0x12, 0x75,
211 0x03, 0x71, 0x02, 0x5b, 0x36, 0x59, 0x7f, 0x75, 0x6e, 0x08, 0x54, 0x0d, 0x34, 0x1c, 0x34, 0x57, 0x5d, 0x69, 0x48, 0x00, 0x3b, 0x05, 211 0x3e, 0x02, 0x5d, 0x7c, 0x13, 0x1f, 0x16, 0x53, 0x3b, 0x74, 0x48, 0x3c, 0x5e, 0x39, 0x6c,
212 0x07, 0x6e, 0x27, 0x65, 0x6e, 0x40, 0x3d, 0x3a, 0x4f, 0x72, 0x5d, 0x39, 0x16, 0x0f, 0x63, 0x12, 0x12, 0x15, 0x3a, 0x70, 0x0d, 0x57, 212 0x1c, 0x1c, 0x74, 0x39, 0x1f, 0x00, 0x1b, 0x06, 0x0a, 0x68, 0x3b, 0x52, 0x4f, 0x1e, 0x6e,
213 0x18, 0x0d, 0x5e, 0x3d, 0x22, 0x68, 0x68, 0x7c, 0x6d, 0x4f, 0x0c, 0x7b, 0x09, 0x2d, 0x4a, 0x73, 0x20, 0x47, 0x07, 0x57, 0x75, 0x5d, 213 0x3c, 0x35, 0x0c, 0x38, 0x0e, 0x0b, 0x3b, 0x1a, 0x76, 0x23, 0x29, 0x53, 0x1e, 0x5f, 0x41,
214 0x53, 0x70, 0x34, 0x21, 0x40, 0x57, 0x51, 0x5e, 0x49, 0x44, 0x00, 0x54, 0x27, 0x04, 0x68, 0x7e, 0x59, 0x56, 0x58, 0x74, 0x14, 0x3c, 214 0x0c, 0x4b, 0x0a, 0x65, 0x28, 0x78, 0x67, 0x48, 0x59, 0x26, 0x6d, 0x31, 0x76, 0x23, 0x70,
215 0x16, 0x33, 0x41, 0x16, 0x4b, 0x2f, 0x49, 0x37, 0x0a, 0x54, 0x08, 0x08, 0x1f, 0x39, 0x67, 0x76, 0x28, 0x28, 0x07, 0x1d, 0x61, 0x47, 215 0x61, 0x64, 0x3b, 0x38, 0x79, 0x66, 0x74, 0x53, 0x2c, 0x64, 0x64, 0x54, 0x03, 0x54, 0x65,
216 0x51, 0x4d, 0x75, 0x26, 0x52, 0x47, 0x47, 0x0c, 0x57, 0x58, 0x74, 0x3e, 0x62, 0x6c, 0x58, 0x3a, 0x44, 0x1e, 0x16, 0x2e, 0x21, 0x1c, 216 0x44, 0x4c, 0x18, 0x4f, 0x48, 0x20, 0x4f, 0x72, 0x10, 0x3f, 0x0c, 0x52, 0x2d, 0x03, 0x14,
217 0x73, 0x45, 0x67, 0x74, 0x4f, 0x33, 0x66, 0x0e, 0x74, 0x66, 0x26, 0x1f, 0x2e, 0x38, 0x44, 0x40, 0x7e, 0x2a, 0x50, 0x52, 0x5e, 0x43, 217 0x03, 0x51, 0x42, 0x10, 0x77, 0x6a, 0x34, 0x06, 0x32, 0x03, 0x72, 0x14, 0x7c, 0x08, 0x5d,
218 0x01, 0x7a, 0x38, 0x49, 0x3c, 0x55, 0x4d, 0x5a, 0x44, 0x08, 0x26, 0x59, 0x4d, 0x45, 0x0b, 0x48, 0x0a, 0x33, 0x5e, 0x4a, 0x4d, 0x75, 218 0x52, 0x1a, 0x62, 0x7c, 0x3e, 0x30, 0x7e, 0x5f, 0x7f, 0x54, 0x0f, 0x44, 0x49, 0x5d, 0x5e,
219 0x16, 0x17, 0x63, 0x46, 0x01, 0x2a, 0x55, 0x7b, 0x0f, 0x02, 0x73, 0x6a, 0x4b, 0x7f, 0x75, 0x65, 0x3c, 0x4c, 0x33, 0x39, 0x6c, 0x74, 219 0x10, 0x6a, 0x06, 0x2b, 0x06, 0x53, 0x10, 0x39, 0x37, 0x32, 0x4a, 0x4e, 0x3d, 0x2b, 0x65,
220 0x05, 0x60, 0x0f, 0x7f, 0x2d, 0x41, 0x4d, 0x4d, 0x46, 0x71, 0x09, 0x6f, 0x4f, 0x60, 0x15, 0x0f, 0x46, 0x73, 0x63, 0x4c, 0x5e, 0x74, 220 0x38, 0x39, 0x07, 0x72, 0x54, 0x64, 0x4d, 0x56, 0x6a, 0x03, 0x22, 0x70, 0x7b, 0x5f, 0x60,
221 0x30, 0x0d, 0x28, 0x43, 0x08, 0x72, 0x32, 0x04, 0x2e, 0x31, 0x29, 0x27, 0x44, 0x6d, 0x13, 0x17, 0x48, 0x0f, 0x49, 0x52, 0x10, 0x13, 221 0x0b, 0x2a, 0x0b, 0x6b, 0x10, 0x64, 0x14, 0x05, 0x22, 0x00, 0x73, 0x40, 0x23, 0x5b, 0x51,
222 0x7f, 0x17, 0x16, 0x62, 0x79, 0x35, 0x78, 0x3e, 0x01, 0x7c, 0x2e, 0x0f, 0x76, 0x3e, 0x5e, 0x53, 0x6c, 0x5b, 0x5f, 0x7c, 0x19, 0x41, 222 0x1f, 0x2b, 0x1a, 0x5d, 0x69, 0x7a, 0x46, 0x0c, 0x5f, 0x32, 0x4b, 0x4a, 0x28, 0x52, 0x79,
223 0x02, 0x2f, 0x17, 0x64, 0x41, 0x75, 0x10, 0x04, 0x47, 0x7c, 0x3d, 0x4b, 0x52, 0x00, 0x10, 0x5d, 0x51, 0x4e, 0x7a, 0x27, 0x25, 0x55, 223 0x5b, 0x12, 0x42, 0x18, 0x00, 0x5d, 0x27, 0x31, 0x53, 0x3c, 0x4c, 0x36, 0x4e, 0x38, 0x3f,
224 0x40, 0x12, 0x35, 0x60, 0x05, 0x1b, 0x34, 0x2d, 0x04, 0x7a, 0x6a, 0x69, 0x02, 0x79, 0x03, 0x3a, 0x2f, 0x06, 0x0a, 0x79, 0x7b, 0x12, 224 0x72, 0x03, 0x71, 0x02, 0x5b, 0x36, 0x59, 0x7f, 0x75, 0x6e, 0x08, 0x54, 0x0d, 0x34, 0x1c,
225 0x5d, 0x7c, 0x52, 0x29, 0x47, 0x58, 0x12, 0x73, 0x3f, 0x27, 0x56, 0x05, 0x0c, 0x48, 0x32, 0x58, 0x6b, 0x57, 0x5c, 0x03, 0x64, 0x56, 225 0x34, 0x57, 0x5d, 0x69, 0x48, 0x00, 0x3b, 0x05, 0x07, 0x6e, 0x27, 0x65, 0x6e, 0x40, 0x3d,
226 0x11, 0x52, 0x7a, 0x30, 0x36, 0x29, 0x17, 0x3b, 0x68, 0x7a, 0x7c, 0x05, 0x6b, 0x6b, 0x13, 0x6a, 0x24, 0x5c, 0x68, 0x42, 0x18, 0x32, 226 0x3a, 0x4f, 0x72, 0x5d, 0x39, 0x16, 0x0f, 0x63, 0x12, 0x12, 0x15, 0x3a, 0x70, 0x0d, 0x57,
227 0x03, 0x73, 0x6e, 0x04, 0x21, 0x2e, 0x01, 0x04, 0x63, 0x7d, 0x44, 0x41, 0x12, 0x31, 0x0b, 0x15, 0x1f, 0x70, 0x00, 0x2e, 0x66, 0x14, 227 0x18, 0x0d, 0x5e, 0x3d, 0x22, 0x68, 0x68, 0x7c, 0x6d, 0x4f, 0x0c, 0x7b, 0x09, 0x2d, 0x4a,
228 0x3c, 0x7f, 0x2b, 0x00, 0x1f, 0x0c, 0x28, 0x59, 0x0a, 0x16, 0x49, 0x5a, 0x5c, 0x64, 0x65, 0x4b, 0x11, 0x29, 0x15, 0x36, 0x5a, 0x65, 228 0x73, 0x20, 0x47, 0x07, 0x57, 0x75, 0x5d, 0x53, 0x70, 0x34, 0x21, 0x40, 0x57, 0x51, 0x5e,
229 0x19, 0x4f, 0x60, 0x23, 0x3a, 0x3a, 0x13, 0x25, 0x02, 0x78, 0x4c, 0x54}; 229 0x49, 0x44, 0x00, 0x54, 0x27, 0x04, 0x68, 0x7e, 0x59, 0x56, 0x58, 0x74, 0x14, 0x3c, 0x16,
230 0x33, 0x41, 0x16, 0x4b, 0x2f, 0x49, 0x37, 0x0a, 0x54, 0x08, 0x08, 0x1f, 0x39, 0x67, 0x76,
231 0x28, 0x28, 0x07, 0x1d, 0x61, 0x47, 0x51, 0x4d, 0x75, 0x26, 0x52, 0x47, 0x47, 0x0c, 0x57,
232 0x58, 0x74, 0x3e, 0x62, 0x6c, 0x58, 0x3a, 0x44, 0x1e, 0x16, 0x2e, 0x21, 0x1c, 0x73, 0x45,
233 0x67, 0x74, 0x4f, 0x33, 0x66, 0x0e, 0x74, 0x66, 0x26, 0x1f, 0x2e, 0x38, 0x44, 0x40, 0x7e,
234 0x2a, 0x50, 0x52, 0x5e, 0x43, 0x01, 0x7a, 0x38, 0x49, 0x3c, 0x55, 0x4d, 0x5a, 0x44, 0x08,
235 0x26, 0x59, 0x4d, 0x45, 0x0b, 0x48, 0x0a, 0x33, 0x5e, 0x4a, 0x4d, 0x75, 0x16, 0x17, 0x63,
236 0x46, 0x01, 0x2a, 0x55, 0x7b, 0x0f, 0x02, 0x73, 0x6a, 0x4b, 0x7f, 0x75, 0x65, 0x3c, 0x4c,
237 0x33, 0x39, 0x6c, 0x74, 0x05, 0x60, 0x0f, 0x7f, 0x2d, 0x41, 0x4d, 0x4d, 0x46, 0x71, 0x09,
238 0x6f, 0x4f, 0x60, 0x15, 0x0f, 0x46, 0x73, 0x63, 0x4c, 0x5e, 0x74, 0x30, 0x0d, 0x28, 0x43,
239 0x08, 0x72, 0x32, 0x04, 0x2e, 0x31, 0x29, 0x27, 0x44, 0x6d, 0x13, 0x17, 0x48, 0x0f, 0x49,
240 0x52, 0x10, 0x13, 0x7f, 0x17, 0x16, 0x62, 0x79, 0x35, 0x78, 0x3e, 0x01, 0x7c, 0x2e, 0x0f,
241 0x76, 0x3e, 0x5e, 0x53, 0x6c, 0x5b, 0x5f, 0x7c, 0x19, 0x41, 0x02, 0x2f, 0x17, 0x64, 0x41,
242 0x75, 0x10, 0x04, 0x47, 0x7c, 0x3d, 0x4b, 0x52, 0x00, 0x10, 0x5d, 0x51, 0x4e, 0x7a, 0x27,
243 0x25, 0x55, 0x40, 0x12, 0x35, 0x60, 0x05, 0x1b, 0x34, 0x2d, 0x04, 0x7a, 0x6a, 0x69, 0x02,
244 0x79, 0x03, 0x3a, 0x2f, 0x06, 0x0a, 0x79, 0x7b, 0x12, 0x5d, 0x7c, 0x52, 0x29, 0x47, 0x58,
245 0x12, 0x73, 0x3f, 0x27, 0x56, 0x05, 0x0c, 0x48, 0x32, 0x58, 0x6b, 0x57, 0x5c, 0x03, 0x64,
246 0x56, 0x11, 0x52, 0x7a, 0x30, 0x36, 0x29, 0x17, 0x3b, 0x68, 0x7a, 0x7c, 0x05, 0x6b, 0x6b,
247 0x13, 0x6a, 0x24, 0x5c, 0x68, 0x42, 0x18, 0x32, 0x03, 0x73, 0x6e, 0x04, 0x21, 0x2e, 0x01,
248 0x04, 0x63, 0x7d, 0x44, 0x41, 0x12, 0x31, 0x0b, 0x15, 0x1f, 0x70, 0x00, 0x2e, 0x66, 0x14,
249 0x3c, 0x7f, 0x2b, 0x00, 0x1f, 0x0c, 0x28, 0x59, 0x0a, 0x16, 0x49, 0x5a, 0x5c, 0x64, 0x65,
250 0x4b, 0x11, 0x29, 0x15, 0x36, 0x5a, 0x65, 0x19, 0x4f, 0x60, 0x23, 0x3a, 0x3a, 0x13, 0x25,
251 0x02, 0x78, 0x4c, 0x54};
230 char b64_known[1369] = { 252 char b64_known[1369] = {
231 0x43, 0x7a, 0x42, 0x45, 0x59, 0x6e, 0x77, 0x69, 0x48, 0x77, 0x30, 0x46, 0x5a, 0x79, 0x77, 0x71, 0x4f, 0x53, 0x46, 0x47, 0x43, 0x46, 253 0x43, 0x7a, 0x42, 0x45, 0x59, 0x6e, 0x77, 0x69, 0x48, 0x77, 0x30, 0x46, 0x5a, 0x79, 0x77,
232 0x42, 0x6d, 0x4e, 0x44, 0x63, 0x4c, 0x52, 0x55, 0x73, 0x34, 0x4d, 0x67, 0x5a, 0x36, 0x50, 0x6e, 0x38, 0x4d, 0x51, 0x42, 0x68, 0x72, 254 0x71, 0x4f, 0x53, 0x46, 0x47, 0x43, 0x46, 0x42, 0x6d, 0x4e, 0x44, 0x63, 0x4c, 0x52, 0x55,
233 0x4c, 0x57, 0x42, 0x4d, 0x59, 0x41, 0x77, 0x6a, 0x51, 0x7a, 0x73, 0x2b, 0x47, 0x78, 0x59, 0x45, 0x52, 0x6c, 0x67, 0x2f, 0x51, 0x47, 255 0x73, 0x34, 0x4d, 0x67, 0x5a, 0x36, 0x50, 0x6e, 0x38, 0x4d, 0x51, 0x42, 0x68, 0x72, 0x4c,
234 0x6f, 0x52, 0x42, 0x57, 0x4e, 0x78, 0x46, 0x44, 0x56, 0x48, 0x65, 0x52, 0x4e, 0x76, 0x61, 0x79, 0x63, 0x59, 0x57, 0x30, 0x67, 0x6e, 256 0x57, 0x42, 0x4d, 0x59, 0x41, 0x77, 0x6a, 0x51, 0x7a, 0x73, 0x2b, 0x47, 0x78, 0x59, 0x45,
235 0x50, 0x6d, 0x38, 0x56, 0x4d, 0x30, 0x38, 0x2b, 0x58, 0x6c, 0x46, 0x7a, 0x61, 0x43, 0x55, 0x50, 0x42, 0x6c, 0x74, 0x38, 0x63, 0x6e, 257 0x52, 0x6c, 0x67, 0x2f, 0x51, 0x47, 0x6f, 0x52, 0x42, 0x57, 0x4e, 0x78, 0x46, 0x44, 0x56,
236 0x55, 0x2b, 0x50, 0x78, 0x74, 0x63, 0x62, 0x57, 0x6f, 0x35, 0x66, 0x47, 0x4e, 0x6a, 0x59, 0x47, 0x78, 0x36, 0x4d, 0x33, 0x5a, 0x53, 258 0x48, 0x65, 0x52, 0x4e, 0x76, 0x61, 0x79, 0x63, 0x59, 0x57, 0x30, 0x67, 0x6e, 0x50, 0x6d,
237 0x45, 0x79, 0x55, 0x7a, 0x66, 0x57, 0x55, 0x6a, 0x4a, 0x78, 0x45, 0x47, 0x42, 0x6b, 0x64, 0x78, 0x48, 0x68, 0x52, 0x30, 0x59, 0x33, 259 0x38, 0x56, 0x4d, 0x30, 0x38, 0x2b, 0x58, 0x6c, 0x46, 0x7a, 0x61, 0x43, 0x55, 0x50, 0x42,
238 0x41, 0x74, 0x46, 0x53, 0x63, 0x59, 0x55, 0x51, 0x59, 0x46, 0x4d, 0x78, 0x45, 0x73, 0x61, 0x77, 0x41, 0x74, 0x64, 0x79, 0x42, 0x49, 260 0x6c, 0x74, 0x38, 0x63, 0x6e, 0x55, 0x2b, 0x50, 0x78, 0x74, 0x63, 0x62, 0x57, 0x6f, 0x35,
239 0x44, 0x58, 0x4e, 0x52, 0x52, 0x53, 0x56, 0x2f, 0x66, 0x7a, 0x55, 0x6d, 0x4c, 0x69, 0x5a, 0x54, 0x4a, 0x47, 0x67, 0x65, 0x44, 0x6c, 261 0x66, 0x47, 0x4e, 0x6a, 0x59, 0x47, 0x78, 0x36, 0x4d, 0x33, 0x5a, 0x53, 0x45, 0x79, 0x55,
240 0x67, 0x36, 0x57, 0x56, 0x42, 0x57, 0x4e, 0x31, 0x39, 0x6d, 0x41, 0x55, 0x78, 0x61, 0x5a, 0x44, 0x4a, 0x51, 0x65, 0x32, 0x6f, 0x67, 262 0x7a, 0x66, 0x57, 0x55, 0x6a, 0x4a, 0x78, 0x45, 0x47, 0x42, 0x6b, 0x64, 0x78, 0x48, 0x68,
241 0x63, 0x69, 0x73, 0x64, 0x66, 0x6b, 0x4e, 0x37, 0x59, 0x55, 0x49, 0x4c, 0x59, 0x58, 0x4d, 0x6b, 0x65, 0x54, 0x70, 0x72, 0x53, 0x6e, 263 0x52, 0x30, 0x59, 0x33, 0x41, 0x74, 0x46, 0x53, 0x63, 0x59, 0x55, 0x51, 0x59, 0x46, 0x4d,
242 0x6c, 0x75, 0x43, 0x51, 0x38, 0x6e, 0x4c, 0x51, 0x78, 0x65, 0x4d, 0x6b, 0x73, 0x4e, 0x65, 0x55, 0x59, 0x35, 0x49, 0x51, 0x6f, 0x6d, 264 0x78, 0x45, 0x73, 0x61, 0x77, 0x41, 0x74, 0x64, 0x79, 0x42, 0x49, 0x44, 0x58, 0x4e, 0x52,
243 0x58, 0x7a, 0x6f, 0x41, 0x4a, 0x6a, 0x38, 0x54, 0x4c, 0x6e, 0x35, 0x51, 0x4b, 0x32, 0x64, 0x47, 0x63, 0x6a, 0x38, 0x37, 0x41, 0x55, 265 0x52, 0x53, 0x56, 0x2f, 0x66, 0x7a, 0x55, 0x6d, 0x4c, 0x69, 0x5a, 0x54, 0x4a, 0x47, 0x67,
244 0x59, 0x62, 0x43, 0x7a, 0x56, 0x4a, 0x4f, 0x52, 0x6c, 0x77, 0x50, 0x51, 0x4a, 0x42, 0x44, 0x6a, 0x67, 0x46, 0x64, 0x6d, 0x56, 0x50, 266 0x65, 0x44, 0x6c, 0x67, 0x36, 0x57, 0x56, 0x42, 0x57, 0x4e, 0x31, 0x39, 0x6d, 0x41, 0x55,
245 0x4d, 0x57, 0x78, 0x65, 0x46, 0x77, 0x51, 0x56, 0x4e, 0x69, 0x5a, 0x6b, 0x4e, 0x42, 0x51, 0x58, 0x66, 0x41, 0x34, 0x4c, 0x57, 0x31, 267 0x78, 0x61, 0x5a, 0x44, 0x4a, 0x51, 0x65, 0x32, 0x6f, 0x67, 0x63, 0x69, 0x73, 0x64, 0x66,
246 0x56, 0x54, 0x61, 0x77, 0x42, 0x43, 0x51, 0x55, 0x38, 0x43, 0x58, 0x42, 0x4d, 0x4b, 0x4c, 0x43, 0x77, 0x2b, 0x45, 0x42, 0x51, 0x7a, 268 0x6b, 0x4e, 0x37, 0x59, 0x55, 0x49, 0x4c, 0x59, 0x58, 0x4d, 0x6b, 0x65, 0x54, 0x70, 0x72,
247 0x52, 0x58, 0x78, 0x36, 0x57, 0x6a, 0x46, 0x68, 0x4f, 0x51, 0x67, 0x69, 0x61, 0x68, 0x34, 0x50, 0x62, 0x78, 0x74, 0x73, 0x45, 0x31, 269 0x53, 0x6e, 0x6c, 0x75, 0x43, 0x51, 0x38, 0x6e, 0x4c, 0x51, 0x78, 0x65, 0x4d, 0x6b, 0x73,
248 0x35, 0x35, 0x49, 0x48, 0x6c, 0x51, 0x59, 0x67, 0x59, 0x73, 0x64, 0x68, 0x63, 0x45, 0x4b, 0x79, 0x70, 0x31, 0x48, 0x77, 0x77, 0x33, 270 0x4e, 0x65, 0x55, 0x59, 0x35, 0x49, 0x51, 0x6f, 0x6d, 0x58, 0x7a, 0x6f, 0x41, 0x4a, 0x6a,
249 0x54, 0x67, 0x39, 0x37, 0x4c, 0x54, 0x52, 0x31, 0x59, 0x44, 0x46, 0x30, 0x4c, 0x67, 0x70, 0x4b, 0x45, 0x57, 0x78, 0x4a, 0x4a, 0x51, 271 0x38, 0x54, 0x4c, 0x6e, 0x35, 0x51, 0x4b, 0x32, 0x64, 0x47, 0x63, 0x6a, 0x38, 0x37, 0x41,
250 0x45, 0x36, 0x50, 0x53, 0x49, 0x65, 0x62, 0x52, 0x68, 0x52, 0x65, 0x43, 0x31, 0x69, 0x4d, 0x55, 0x78, 0x51, 0x51, 0x42, 0x64, 0x4c, 272 0x55, 0x59, 0x62, 0x43, 0x7a, 0x56, 0x4a, 0x4f, 0x52, 0x6c, 0x77, 0x50, 0x51, 0x4a, 0x42,
251 0x62, 0x79, 0x49, 0x41, 0x66, 0x32, 0x45, 0x71, 0x4e, 0x44, 0x34, 0x41, 0x58, 0x79, 0x39, 0x66, 0x4c, 0x78, 0x51, 0x71, 0x56, 0x53, 273 0x44, 0x6a, 0x67, 0x46, 0x64, 0x6d, 0x56, 0x50, 0x4d, 0x57, 0x78, 0x65, 0x46, 0x77, 0x51,
252 0x63, 0x66, 0x52, 0x68, 0x38, 0x53, 0x52, 0x6c, 0x34, 0x65, 0x44, 0x48, 0x77, 0x34, 0x41, 0x57, 0x46, 0x6b, 0x64, 0x69, 0x4a, 0x75, 274 0x56, 0x4e, 0x69, 0x5a, 0x6b, 0x4e, 0x42, 0x51, 0x58, 0x66, 0x41, 0x34, 0x4c, 0x57, 0x31,
253 0x43, 0x43, 0x41, 0x34, 0x54, 0x33, 0x4e, 0x79, 0x56, 0x52, 0x4a, 0x43, 0x47, 0x56, 0x42, 0x68, 0x51, 0x33, 0x64, 0x39, 0x51, 0x53, 275 0x56, 0x54, 0x61, 0x77, 0x42, 0x43, 0x51, 0x55, 0x38, 0x43, 0x58, 0x42, 0x4d, 0x4b, 0x4c,
254 0x34, 0x31, 0x54, 0x7a, 0x30, 0x78, 0x4b, 0x46, 0x68, 0x6e, 0x47, 0x77, 0x4e, 0x52, 0x49, 0x44, 0x49, 0x63, 0x43, 0x47, 0x34, 0x33, 276 0x43, 0x77, 0x2b, 0x45, 0x42, 0x51, 0x7a, 0x52, 0x58, 0x78, 0x36, 0x57, 0x6a, 0x46, 0x68,
255 0x64, 0x54, 0x64, 0x45, 0x54, 0x32, 0x67, 0x5a, 0x42, 0x32, 0x51, 0x55, 0x4b, 0x43, 0x55, 0x72, 0x61, 0x54, 0x55, 0x59, 0x4a, 0x79, 277 0x4f, 0x51, 0x67, 0x69, 0x61, 0x68, 0x34, 0x50, 0x62, 0x78, 0x74, 0x73, 0x45, 0x31, 0x35,
256 0x59, 0x55, 0x45, 0x33, 0x42, 0x43, 0x47, 0x52, 0x4a, 0x31, 0x50, 0x67, 0x4a, 0x64, 0x66, 0x42, 0x4d, 0x66, 0x46, 0x6c, 0x4d, 0x37, 278 0x35, 0x49, 0x48, 0x6c, 0x51, 0x59, 0x67, 0x59, 0x73, 0x64, 0x68, 0x63, 0x45, 0x4b, 0x79,
257 0x64, 0x45, 0x67, 0x38, 0x58, 0x6a, 0x6c, 0x73, 0x48, 0x42, 0x78, 0x30, 0x4f, 0x52, 0x38, 0x41, 0x47, 0x77, 0x59, 0x4b, 0x61, 0x44, 279 0x70, 0x31, 0x48, 0x77, 0x77, 0x33, 0x54, 0x67, 0x39, 0x37, 0x4c, 0x54, 0x52, 0x31, 0x59,
258 0x74, 0x53, 0x54, 0x78, 0x35, 0x75, 0x50, 0x44, 0x55, 0x4d, 0x4f, 0x41, 0x34, 0x4c, 0x4f, 0x78, 0x70, 0x32, 0x49, 0x79, 0x6c, 0x54, 280 0x44, 0x46, 0x30, 0x4c, 0x67, 0x70, 0x4b, 0x45, 0x57, 0x78, 0x4a, 0x4a, 0x51, 0x45, 0x36,
259 0x48, 0x6c, 0x39, 0x42, 0x44, 0x45, 0x73, 0x4b, 0x5a, 0x53, 0x68, 0x34, 0x5a, 0x30, 0x68, 0x5a, 0x4a, 0x6d, 0x30, 0x78, 0x64, 0x69, 281 0x50, 0x53, 0x49, 0x65, 0x62, 0x52, 0x68, 0x52, 0x65, 0x43, 0x31, 0x69, 0x4d, 0x55, 0x78,
260 0x4e, 0x77, 0x59, 0x57, 0x51, 0x37, 0x4f, 0x48, 0x6c, 0x6d, 0x64, 0x46, 0x4d, 0x73, 0x5a, 0x47, 0x52, 0x55, 0x41, 0x31, 0x52, 0x6c, 282 0x51, 0x51, 0x42, 0x64, 0x4c, 0x62, 0x79, 0x49, 0x41, 0x66, 0x32, 0x45, 0x71, 0x4e, 0x44,
261 0x52, 0x45, 0x77, 0x59, 0x54, 0x30, 0x67, 0x67, 0x54, 0x33, 0x49, 0x51, 0x50, 0x77, 0x78, 0x53, 0x4c, 0x51, 0x4d, 0x55, 0x41, 0x31, 283 0x34, 0x41, 0x58, 0x79, 0x39, 0x66, 0x4c, 0x78, 0x51, 0x71, 0x56, 0x53, 0x63, 0x66, 0x52,
262 0x46, 0x43, 0x45, 0x48, 0x64, 0x71, 0x4e, 0x41, 0x59, 0x79, 0x41, 0x33, 0x49, 0x55, 0x66, 0x41, 0x68, 0x64, 0x55, 0x68, 0x70, 0x69, 284 0x68, 0x38, 0x53, 0x52, 0x6c, 0x34, 0x65, 0x44, 0x48, 0x77, 0x34, 0x41, 0x57, 0x46, 0x6b,
263 0x66, 0x44, 0x34, 0x77, 0x66, 0x6c, 0x39, 0x2f, 0x56, 0x41, 0x39, 0x45, 0x53, 0x56, 0x31, 0x65, 0x45, 0x47, 0x6f, 0x47, 0x4b, 0x77, 285 0x64, 0x69, 0x4a, 0x75, 0x43, 0x43, 0x41, 0x34, 0x54, 0x33, 0x4e, 0x79, 0x56, 0x52, 0x4a,
264 0x5a, 0x54, 0x45, 0x44, 0x6b, 0x33, 0x4d, 0x6b, 0x70, 0x4f, 0x50, 0x53, 0x74, 0x6c, 0x4f, 0x44, 0x6b, 0x48, 0x63, 0x6c, 0x52, 0x6b, 286 0x43, 0x47, 0x56, 0x42, 0x68, 0x51, 0x33, 0x64, 0x39, 0x51, 0x53, 0x34, 0x31, 0x54, 0x7a,
265 0x54, 0x56, 0x5a, 0x71, 0x41, 0x79, 0x4a, 0x77, 0x65, 0x31, 0x39, 0x67, 0x43, 0x79, 0x6f, 0x4c, 0x61, 0x78, 0x42, 0x6b, 0x46, 0x41, 287 0x30, 0x78, 0x4b, 0x46, 0x68, 0x6e, 0x47, 0x77, 0x4e, 0x52, 0x49, 0x44, 0x49, 0x63, 0x43,
266 0x55, 0x69, 0x41, 0x48, 0x4e, 0x41, 0x49, 0x31, 0x74, 0x52, 0x48, 0x79, 0x73, 0x61, 0x58, 0x57, 0x6c, 0x36, 0x52, 0x67, 0x78, 0x66, 288 0x47, 0x34, 0x33, 0x64, 0x54, 0x64, 0x45, 0x54, 0x32, 0x67, 0x5a, 0x42, 0x32, 0x51, 0x55,
267 0x4d, 0x6b, 0x74, 0x4b, 0x4b, 0x46, 0x4a, 0x35, 0x57, 0x78, 0x4a, 0x43, 0x47, 0x41, 0x42, 0x64, 0x4a, 0x7a, 0x46, 0x54, 0x50, 0x45, 289 0x4b, 0x43, 0x55, 0x72, 0x61, 0x54, 0x55, 0x59, 0x4a, 0x79, 0x59, 0x55, 0x45, 0x33, 0x42,
268 0x77, 0x32, 0x54, 0x6a, 0x67, 0x2f, 0x63, 0x67, 0x4e, 0x78, 0x41, 0x6c, 0x73, 0x32, 0x57, 0x58, 0x39, 0x31, 0x62, 0x67, 0x68, 0x55, 290 0x43, 0x47, 0x52, 0x4a, 0x31, 0x50, 0x67, 0x4a, 0x64, 0x66, 0x42, 0x4d, 0x66, 0x46, 0x6c,
269 0x44, 0x54, 0x51, 0x63, 0x4e, 0x46, 0x64, 0x64, 0x61, 0x55, 0x67, 0x41, 0x4f, 0x77, 0x55, 0x48, 0x62, 0x69, 0x64, 0x6c, 0x62, 0x6b, 291 0x4d, 0x37, 0x64, 0x45, 0x67, 0x38, 0x58, 0x6a, 0x6c, 0x73, 0x48, 0x42, 0x78, 0x30, 0x4f,
270 0x41, 0x39, 0x4f, 0x6b, 0x39, 0x79, 0x58, 0x54, 0x6b, 0x57, 0x44, 0x32, 0x4d, 0x53, 0x45, 0x68, 0x55, 0x36, 0x63, 0x41, 0x31, 0x58, 292 0x52, 0x38, 0x41, 0x47, 0x77, 0x59, 0x4b, 0x61, 0x44, 0x74, 0x53, 0x54, 0x78, 0x35, 0x75,
271 0x47, 0x41, 0x31, 0x65, 0x50, 0x53, 0x4a, 0x6f, 0x61, 0x48, 0x78, 0x74, 0x54, 0x77, 0x78, 0x37, 0x43, 0x53, 0x31, 0x4b, 0x63, 0x79, 293 0x50, 0x44, 0x55, 0x4d, 0x4f, 0x41, 0x34, 0x4c, 0x4f, 0x78, 0x70, 0x32, 0x49, 0x79, 0x6c,
272 0x42, 0x48, 0x42, 0x31, 0x64, 0x31, 0x58, 0x56, 0x4e, 0x77, 0x4e, 0x43, 0x46, 0x41, 0x56, 0x31, 0x46, 0x65, 0x53, 0x55, 0x51, 0x41, 294 0x54, 0x48, 0x6c, 0x39, 0x42, 0x44, 0x45, 0x73, 0x4b, 0x5a, 0x53, 0x68, 0x34, 0x5a, 0x30,
273 0x56, 0x43, 0x63, 0x45, 0x61, 0x48, 0x35, 0x5a, 0x56, 0x6c, 0x68, 0x30, 0x46, 0x44, 0x77, 0x57, 0x4d, 0x30, 0x45, 0x57, 0x53, 0x79, 295 0x68, 0x5a, 0x4a, 0x6d, 0x30, 0x78, 0x64, 0x69, 0x4e, 0x77, 0x59, 0x57, 0x51, 0x37, 0x4f,
274 0x39, 0x4a, 0x4e, 0x77, 0x70, 0x55, 0x43, 0x41, 0x67, 0x66, 0x4f, 0x57, 0x64, 0x32, 0x4b, 0x43, 0x67, 0x48, 0x48, 0x57, 0x46, 0x48, 296 0x48, 0x6c, 0x6d, 0x64, 0x46, 0x4d, 0x73, 0x5a, 0x47, 0x52, 0x55, 0x41, 0x31, 0x52, 0x6c,
275 0x55, 0x55, 0x31, 0x31, 0x4a, 0x6c, 0x4a, 0x48, 0x52, 0x77, 0x78, 0x58, 0x57, 0x48, 0x51, 0x2b, 0x59, 0x6d, 0x78, 0x59, 0x4f, 0x6b, 297 0x52, 0x45, 0x77, 0x59, 0x54, 0x30, 0x67, 0x67, 0x54, 0x33, 0x49, 0x51, 0x50, 0x77, 0x78,
276 0x51, 0x65, 0x46, 0x69, 0x34, 0x68, 0x48, 0x48, 0x4e, 0x46, 0x5a, 0x33, 0x52, 0x50, 0x4d, 0x32, 0x59, 0x4f, 0x64, 0x47, 0x59, 0x6d, 298 0x53, 0x4c, 0x51, 0x4d, 0x55, 0x41, 0x31, 0x46, 0x43, 0x45, 0x48, 0x64, 0x71, 0x4e, 0x41,
277 0x48, 0x79, 0x34, 0x34, 0x52, 0x45, 0x42, 0x2b, 0x4b, 0x6c, 0x42, 0x53, 0x58, 0x6b, 0x4d, 0x42, 0x65, 0x6a, 0x68, 0x4a, 0x50, 0x46, 299 0x59, 0x79, 0x41, 0x33, 0x49, 0x55, 0x66, 0x41, 0x68, 0x64, 0x55, 0x68, 0x70, 0x69, 0x66,
278 0x56, 0x4e, 0x57, 0x6b, 0x51, 0x49, 0x4a, 0x6c, 0x6c, 0x4e, 0x52, 0x51, 0x74, 0x49, 0x43, 0x6a, 0x4e, 0x65, 0x53, 0x6b, 0x31, 0x31, 300 0x44, 0x34, 0x77, 0x66, 0x6c, 0x39, 0x2f, 0x56, 0x41, 0x39, 0x45, 0x53, 0x56, 0x31, 0x65,
279 0x46, 0x68, 0x64, 0x6a, 0x52, 0x67, 0x45, 0x71, 0x56, 0x58, 0x73, 0x50, 0x41, 0x6e, 0x4e, 0x71, 0x53, 0x33, 0x39, 0x31, 0x5a, 0x54, 301 0x45, 0x47, 0x6f, 0x47, 0x4b, 0x77, 0x5a, 0x54, 0x45, 0x44, 0x6b, 0x33, 0x4d, 0x6b, 0x70,
280 0x78, 0x4d, 0x4d, 0x7a, 0x6c, 0x73, 0x64, 0x41, 0x56, 0x67, 0x44, 0x33, 0x38, 0x74, 0x51, 0x55, 0x31, 0x4e, 0x52, 0x6e, 0x45, 0x4a, 302 0x4f, 0x50, 0x53, 0x74, 0x6c, 0x4f, 0x44, 0x6b, 0x48, 0x63, 0x6c, 0x52, 0x6b, 0x54, 0x56,
281 0x62, 0x30, 0x39, 0x67, 0x46, 0x51, 0x39, 0x47, 0x63, 0x32, 0x4e, 0x4d, 0x58, 0x6e, 0x51, 0x77, 0x44, 0x53, 0x68, 0x44, 0x43, 0x48, 303 0x5a, 0x71, 0x41, 0x79, 0x4a, 0x77, 0x65, 0x31, 0x39, 0x67, 0x43, 0x79, 0x6f, 0x4c, 0x61,
282 0x49, 0x79, 0x42, 0x43, 0x34, 0x78, 0x4b, 0x53, 0x64, 0x45, 0x62, 0x52, 0x4d, 0x58, 0x53, 0x41, 0x39, 0x4a, 0x55, 0x68, 0x41, 0x54, 304 0x78, 0x42, 0x6b, 0x46, 0x41, 0x55, 0x69, 0x41, 0x48, 0x4e, 0x41, 0x49, 0x31, 0x74, 0x52,
283 0x66, 0x78, 0x63, 0x57, 0x59, 0x6e, 0x6b, 0x31, 0x65, 0x44, 0x34, 0x42, 0x66, 0x43, 0x34, 0x50, 0x64, 0x6a, 0x35, 0x65, 0x55, 0x32, 305 0x48, 0x79, 0x73, 0x61, 0x58, 0x57, 0x6c, 0x36, 0x52, 0x67, 0x78, 0x66, 0x4d, 0x6b, 0x74,
284 0x78, 0x62, 0x58, 0x33, 0x77, 0x5a, 0x51, 0x51, 0x49, 0x76, 0x46, 0x32, 0x52, 0x42, 0x64, 0x52, 0x41, 0x45, 0x52, 0x33, 0x77, 0x39, 306 0x4b, 0x4b, 0x46, 0x4a, 0x35, 0x57, 0x78, 0x4a, 0x43, 0x47, 0x41, 0x42, 0x64, 0x4a, 0x7a,
285 0x53, 0x31, 0x49, 0x41, 0x45, 0x46, 0x31, 0x52, 0x54, 0x6e, 0x6f, 0x6e, 0x4a, 0x56, 0x56, 0x41, 0x45, 0x6a, 0x56, 0x67, 0x42, 0x52, 307 0x46, 0x54, 0x50, 0x45, 0x77, 0x32, 0x54, 0x6a, 0x67, 0x2f, 0x63, 0x67, 0x4e, 0x78, 0x41,
286 0x73, 0x30, 0x4c, 0x51, 0x52, 0x36, 0x61, 0x6d, 0x6b, 0x43, 0x65, 0x51, 0x4d, 0x36, 0x4c, 0x77, 0x59, 0x4b, 0x65, 0x58, 0x73, 0x53, 308 0x6c, 0x73, 0x32, 0x57, 0x58, 0x39, 0x31, 0x62, 0x67, 0x68, 0x55, 0x44, 0x54, 0x51, 0x63,
287 0x58, 0x58, 0x78, 0x53, 0x4b, 0x55, 0x64, 0x59, 0x45, 0x6e, 0x4d, 0x2f, 0x4a, 0x31, 0x59, 0x46, 0x44, 0x45, 0x67, 0x79, 0x57, 0x47, 309 0x4e, 0x46, 0x64, 0x64, 0x61, 0x55, 0x67, 0x41, 0x4f, 0x77, 0x55, 0x48, 0x62, 0x69, 0x64,
288 0x74, 0x58, 0x58, 0x41, 0x4e, 0x6b, 0x56, 0x68, 0x46, 0x53, 0x65, 0x6a, 0x41, 0x32, 0x4b, 0x52, 0x63, 0x37, 0x61, 0x48, 0x70, 0x38, 310 0x6c, 0x62, 0x6b, 0x41, 0x39, 0x4f, 0x6b, 0x39, 0x79, 0x58, 0x54, 0x6b, 0x57, 0x44, 0x32,
289 0x42, 0x57, 0x74, 0x72, 0x45, 0x32, 0x6f, 0x6b, 0x58, 0x47, 0x68, 0x43, 0x47, 0x44, 0x49, 0x44, 0x63, 0x32, 0x34, 0x45, 0x49, 0x53, 311 0x4d, 0x53, 0x45, 0x68, 0x55, 0x36, 0x63, 0x41, 0x31, 0x58, 0x47, 0x41, 0x31, 0x65, 0x50,
290 0x34, 0x42, 0x42, 0x47, 0x4e, 0x39, 0x52, 0x45, 0x45, 0x53, 0x4d, 0x51, 0x73, 0x56, 0x48, 0x33, 0x41, 0x41, 0x4c, 0x6d, 0x59, 0x55, 312 0x53, 0x4a, 0x6f, 0x61, 0x48, 0x78, 0x74, 0x54, 0x77, 0x78, 0x37, 0x43, 0x53, 0x31, 0x4b,
291 0x50, 0x48, 0x38, 0x72, 0x41, 0x42, 0x38, 0x4d, 0x4b, 0x46, 0x6b, 0x4b, 0x46, 0x6b, 0x6c, 0x61, 0x58, 0x47, 0x52, 0x6c, 0x53, 0x78, 313 0x63, 0x79, 0x42, 0x48, 0x42, 0x31, 0x64, 0x31, 0x58, 0x56, 0x4e, 0x77, 0x4e, 0x43, 0x46,
292 0x45, 0x70, 0x46, 0x54, 0x5a, 0x61, 0x5a, 0x52, 0x6c, 0x50, 0x59, 0x43, 0x4d, 0x36, 0x4f, 0x68, 0x4d, 0x6c, 0x41, 0x6e, 0x68, 0x4d, 314 0x41, 0x56, 0x31, 0x46, 0x65, 0x53, 0x55, 0x51, 0x41, 0x56, 0x43, 0x63, 0x45, 0x61, 0x48,
293 0x56, 0x41, 0x3d, 0x3d, 0x00}; 315 0x35, 0x5a, 0x56, 0x6c, 0x68, 0x30, 0x46, 0x44, 0x77, 0x57, 0x4d, 0x30, 0x45, 0x57, 0x53,
316 0x79, 0x39, 0x4a, 0x4e, 0x77, 0x70, 0x55, 0x43, 0x41, 0x67, 0x66, 0x4f, 0x57, 0x64, 0x32,
317 0x4b, 0x43, 0x67, 0x48, 0x48, 0x57, 0x46, 0x48, 0x55, 0x55, 0x31, 0x31, 0x4a, 0x6c, 0x4a,
318 0x48, 0x52, 0x77, 0x78, 0x58, 0x57, 0x48, 0x51, 0x2b, 0x59, 0x6d, 0x78, 0x59, 0x4f, 0x6b,
319 0x51, 0x65, 0x46, 0x69, 0x34, 0x68, 0x48, 0x48, 0x4e, 0x46, 0x5a, 0x33, 0x52, 0x50, 0x4d,
320 0x32, 0x59, 0x4f, 0x64, 0x47, 0x59, 0x6d, 0x48, 0x79, 0x34, 0x34, 0x52, 0x45, 0x42, 0x2b,
321 0x4b, 0x6c, 0x42, 0x53, 0x58, 0x6b, 0x4d, 0x42, 0x65, 0x6a, 0x68, 0x4a, 0x50, 0x46, 0x56,
322 0x4e, 0x57, 0x6b, 0x51, 0x49, 0x4a, 0x6c, 0x6c, 0x4e, 0x52, 0x51, 0x74, 0x49, 0x43, 0x6a,
323 0x4e, 0x65, 0x53, 0x6b, 0x31, 0x31, 0x46, 0x68, 0x64, 0x6a, 0x52, 0x67, 0x45, 0x71, 0x56,
324 0x58, 0x73, 0x50, 0x41, 0x6e, 0x4e, 0x71, 0x53, 0x33, 0x39, 0x31, 0x5a, 0x54, 0x78, 0x4d,
325 0x4d, 0x7a, 0x6c, 0x73, 0x64, 0x41, 0x56, 0x67, 0x44, 0x33, 0x38, 0x74, 0x51, 0x55, 0x31,
326 0x4e, 0x52, 0x6e, 0x45, 0x4a, 0x62, 0x30, 0x39, 0x67, 0x46, 0x51, 0x39, 0x47, 0x63, 0x32,
327 0x4e, 0x4d, 0x58, 0x6e, 0x51, 0x77, 0x44, 0x53, 0x68, 0x44, 0x43, 0x48, 0x49, 0x79, 0x42,
328 0x43, 0x34, 0x78, 0x4b, 0x53, 0x64, 0x45, 0x62, 0x52, 0x4d, 0x58, 0x53, 0x41, 0x39, 0x4a,
329 0x55, 0x68, 0x41, 0x54, 0x66, 0x78, 0x63, 0x57, 0x59, 0x6e, 0x6b, 0x31, 0x65, 0x44, 0x34,
330 0x42, 0x66, 0x43, 0x34, 0x50, 0x64, 0x6a, 0x35, 0x65, 0x55, 0x32, 0x78, 0x62, 0x58, 0x33,
331 0x77, 0x5a, 0x51, 0x51, 0x49, 0x76, 0x46, 0x32, 0x52, 0x42, 0x64, 0x52, 0x41, 0x45, 0x52,
332 0x33, 0x77, 0x39, 0x53, 0x31, 0x49, 0x41, 0x45, 0x46, 0x31, 0x52, 0x54, 0x6e, 0x6f, 0x6e,
333 0x4a, 0x56, 0x56, 0x41, 0x45, 0x6a, 0x56, 0x67, 0x42, 0x52, 0x73, 0x30, 0x4c, 0x51, 0x52,
334 0x36, 0x61, 0x6d, 0x6b, 0x43, 0x65, 0x51, 0x4d, 0x36, 0x4c, 0x77, 0x59, 0x4b, 0x65, 0x58,
335 0x73, 0x53, 0x58, 0x58, 0x78, 0x53, 0x4b, 0x55, 0x64, 0x59, 0x45, 0x6e, 0x4d, 0x2f, 0x4a,
336 0x31, 0x59, 0x46, 0x44, 0x45, 0x67, 0x79, 0x57, 0x47, 0x74, 0x58, 0x58, 0x41, 0x4e, 0x6b,
337 0x56, 0x68, 0x46, 0x53, 0x65, 0x6a, 0x41, 0x32, 0x4b, 0x52, 0x63, 0x37, 0x61, 0x48, 0x70,
338 0x38, 0x42, 0x57, 0x74, 0x72, 0x45, 0x32, 0x6f, 0x6b, 0x58, 0x47, 0x68, 0x43, 0x47, 0x44,
339 0x49, 0x44, 0x63, 0x32, 0x34, 0x45, 0x49, 0x53, 0x34, 0x42, 0x42, 0x47, 0x4e, 0x39, 0x52,
340 0x45, 0x45, 0x53, 0x4d, 0x51, 0x73, 0x56, 0x48, 0x33, 0x41, 0x41, 0x4c, 0x6d, 0x59, 0x55,
341 0x50, 0x48, 0x38, 0x72, 0x41, 0x42, 0x38, 0x4d, 0x4b, 0x46, 0x6b, 0x4b, 0x46, 0x6b, 0x6c,
342 0x61, 0x58, 0x47, 0x52, 0x6c, 0x53, 0x78, 0x45, 0x70, 0x46, 0x54, 0x5a, 0x61, 0x5a, 0x52,
343 0x6c, 0x50, 0x59, 0x43, 0x4d, 0x36, 0x4f, 0x68, 0x4d, 0x6c, 0x41, 0x6e, 0x68, 0x4d, 0x56,
344 0x41, 0x3d, 0x3d, 0x00};
294 char *b64_test; 345 char *b64_test;
295 346
296 plan_tests(1); 347 plan_tests(1);
diff --git a/lib/tests/test_cmd.c b/lib/tests/test_cmd.c
index c8867dfb..d51016cc 100644
--- a/lib/tests/test_cmd.c
+++ b/lib/tests/test_cmd.c
@@ -38,36 +38,35 @@ char *get_command(char *const *line) {
38} 38}
39 39
40int main(int argc, char **argv) { 40int main(int argc, char **argv) {
41 char **command_line = malloc(sizeof(char *) * COMMAND_LINE);
42 char *command = NULL;
43 char *perl;
44 output chld_out, chld_err;
45 int c;
46 int result = UNSET;
47
48 plan_tests(51); 41 plan_tests(51);
49 42
50 diag("Running plain echo command, set one"); 43 diag("Running plain echo command, set one");
51 44
52 /* ensure everything is empty before we begin */ 45 /* ensure everything is empty before we begin */
46
47 output chld_out;
53 memset(&chld_out, 0, sizeof(output)); 48 memset(&chld_out, 0, sizeof(output));
49 output chld_err;
54 memset(&chld_err, 0, sizeof(output)); 50 memset(&chld_err, 0, sizeof(output));
55 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset"); 51 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
56 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset"); 52 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
53 int result = UNSET;
57 ok(result == UNSET, "(initialised) Checking exit code is reset"); 54 ok(result == UNSET, "(initialised) Checking exit code is reset");
58 55
56 char **command_line = malloc(sizeof(char *) * COMMAND_LINE);
59 command_line[0] = strdup("/bin/echo"); 57 command_line[0] = strdup("/bin/echo");
60 command_line[1] = strdup("this"); 58 command_line[1] = strdup("this");
61 command_line[2] = strdup("is"); 59 command_line[2] = strdup("is");
62 command_line[3] = strdup("test"); 60 command_line[3] = strdup("test");
63 command_line[4] = strdup("one"); 61 command_line[4] = strdup("one");
64 62
65 command = get_command(command_line); 63 char *command = get_command(command_line);
66 64
67 result = cmd_run_array(command_line, &chld_out, &chld_err, 0); 65 result = cmd_run_array(command_line, &chld_out, &chld_err, 0);
68 ok(chld_out.lines == 1, "(array) Check for expected number of stdout lines"); 66 ok(chld_out.lines == 1, "(array) Check for expected number of stdout lines");
69 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines"); 67 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines");
70 ok(strcmp(chld_out.line[0], "this is test one") == 0, "(array) Check for expected stdout output"); 68 ok(strcmp(chld_out.line[0], "this is test one") == 0,
69 "(array) Check for expected stdout output");
71 ok(result == 0, "(array) Checking exit code"); 70 ok(result == 0, "(array) Checking exit code");
72 71
73 /* ensure everything is empty again */ 72 /* ensure everything is empty again */
@@ -82,7 +81,8 @@ int main(int argc, char **argv) {
82 81
83 ok(chld_out.lines == 1, "(string) Check for expected number of stdout lines"); 82 ok(chld_out.lines == 1, "(string) Check for expected number of stdout lines");
84 ok(chld_err.lines == 0, "(string) Check for expected number of stderr lines"); 83 ok(chld_err.lines == 0, "(string) Check for expected number of stderr lines");
85 ok(strcmp(chld_out.line[0], "this is test one") == 0, "(string) Check for expected stdout output"); 84 ok(strcmp(chld_out.line[0], "this is test one") == 0,
85 "(string) Check for expected stdout output");
86 ok(result == 0, "(string) Checking exit code"); 86 ok(result == 0, "(string) Checking exit code");
87 87
88 diag("Running plain echo command, set two"); 88 diag("Running plain echo command, set two");
@@ -104,7 +104,8 @@ int main(int argc, char **argv) {
104 result = cmd_run_array(command_line, &chld_out, &chld_err, 0); 104 result = cmd_run_array(command_line, &chld_out, &chld_err, 0);
105 ok(chld_out.lines == 1, "(array) Check for expected number of stdout lines"); 105 ok(chld_out.lines == 1, "(array) Check for expected number of stdout lines");
106 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines"); 106 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines");
107 ok(strcmp(chld_out.line[0], "this is test two") == 0, "(array) Check for expected stdout output"); 107 ok(strcmp(chld_out.line[0], "this is test two") == 0,
108 "(array) Check for expected stdout output");
108 ok(result == 0, "(array) Checking exit code"); 109 ok(result == 0, "(array) Checking exit code");
109 110
110 /* ensure everything is empty again */ 111 /* ensure everything is empty again */
@@ -119,7 +120,8 @@ int main(int argc, char **argv) {
119 120
120 ok(chld_out.lines == 1, "(string) Check for expected number of stdout lines"); 121 ok(chld_out.lines == 1, "(string) Check for expected number of stdout lines");
121 ok(chld_err.lines == 0, "(string) Check for expected number of stderr lines"); 122 ok(chld_err.lines == 0, "(string) Check for expected number of stderr lines");
122 ok(strcmp(chld_out.line[0], "this is test one") == 0, "(string) Check for expected stdout output"); 123 ok(strcmp(chld_out.line[0], "this is test one") == 0,
124 "(string) Check for expected stdout output");
123 ok(result == 0, "(string) Checking exit code"); 125 ok(result == 0, "(string) Checking exit code");
124 126
125 /* ensure everything is empty again */ 127 /* ensure everything is empty again */
@@ -130,7 +132,8 @@ int main(int argc, char **argv) {
130 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset"); 132 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
131 ok(result == UNSET, "(initialised) Checking exit code is reset"); 133 ok(result == UNSET, "(initialised) Checking exit code is reset");
132 134
133 /* Pass linefeeds via parameters through - those should be evaluated by echo to give multi line output */ 135 /* Pass linefeeds via parameters through - those should be evaluated by echo to give multi line
136 * output */
134 command_line[0] = strdup("/bin/echo"); 137 command_line[0] = strdup("/bin/echo");
135 command_line[1] = strdup("this is a test via echo\nline two\nit's line 3"); 138 command_line[1] = strdup("this is a test via echo\nline two\nit's line 3");
136 command_line[2] = strdup("and (note space between '3' and 'and') $$ will not get evaluated"); 139 command_line[2] = strdup("and (note space between '3' and 'and') $$ will not get evaluated");
@@ -138,9 +141,12 @@ int main(int argc, char **argv) {
138 result = cmd_run_array(command_line, &chld_out, &chld_err, 0); 141 result = cmd_run_array(command_line, &chld_out, &chld_err, 0);
139 ok(chld_out.lines == 3, "(array) Check for expected number of stdout lines"); 142 ok(chld_out.lines == 3, "(array) Check for expected number of stdout lines");
140 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines"); 143 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines");
141 ok(strcmp(chld_out.line[0], "this is a test via echo") == 0, "(array) Check line 1 for expected stdout output"); 144 ok(strcmp(chld_out.line[0], "this is a test via echo") == 0,
142 ok(strcmp(chld_out.line[1], "line two") == 0, "(array) Check line 2 for expected stdout output"); 145 "(array) Check line 1 for expected stdout output");
143 ok(strcmp(chld_out.line[2], "it's line 3 and (note space between '3' and 'and') $$ will not get evaluated") == 0, 146 ok(strcmp(chld_out.line[1], "line two") == 0,
147 "(array) Check line 2 for expected stdout output");
148 ok(strcmp(chld_out.line[2],
149 "it's line 3 and (note space between '3' and 'and') $$ will not get evaluated") == 0,
144 "(array) Check line 3 for expected stdout output"); 150 "(array) Check line 3 for expected stdout output");
145 ok(result == 0, "(array) Checking exit code"); 151 ok(result == 0, "(array) Checking exit code");
146 152
@@ -171,7 +177,8 @@ int main(int argc, char **argv) {
171 177
172 ok(chld_out.lines == 0, "/bin/sh returns no stdout when file is missing..."); 178 ok(chld_out.lines == 0, "/bin/sh returns no stdout when file is missing...");
173 ok(chld_err.lines == 1, "...but does give an error line"); 179 ok(chld_err.lines == 1, "...but does give an error line");
174 ok(strstr(chld_err.line[0], "non-existent-file") != NULL, "And missing filename is in error message"); 180 ok(strstr(chld_err.line[0], "non-existent-file") != NULL,
181 "And missing filename is in error message");
175 ok(result != 0, "Get non-zero return code from /bin/sh"); 182 ok(result != 0, "Get non-zero return code from /bin/sh");
176 183
177 /* ensure everything is empty again */ 184 /* ensure everything is empty again */
diff --git a/lib/tests/test_disk.t b/lib/tests/test_disk.t
deleted file mode 100755
index da84dfdf..00000000
--- a/lib/tests/test_disk.t
+++ /dev/null
@@ -1,6 +0,0 @@
1#!/usr/bin/perl
2use Test::More;
3if (! -e "./test_disk") {
4 plan skip_all => "./test_disk not compiled - please enable libtap library to test";
5}
6exec "./test_disk";
diff --git a/lib/tests/test_generic_output.c b/lib/tests/test_generic_output.c
index e67aefc9..e4a78bcd 100644
--- a/lib/tests/test_generic_output.c
+++ b/lib/tests/test_generic_output.c
@@ -110,7 +110,8 @@ void test_two_subchecks(void) {
110 sc1.output = "foobar"; 110 sc1.output = "foobar";
111 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING); 111 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
112 112
113 ok(mp_compute_subcheck_state(sc1) == STATE_WARNING, "Test subcheck state directly after setting it"); 113 ok(mp_compute_subcheck_state(sc1) == STATE_WARNING,
114 "Test subcheck state directly after setting it");
114 115
115 mp_perfdata pd1 = perfdata_init(); 116 mp_perfdata pd1 = perfdata_init();
116 117
@@ -129,7 +130,8 @@ void test_two_subchecks(void) {
129 130
130 mp_add_subcheck_to_subcheck(&sc1, sc2); 131 mp_add_subcheck_to_subcheck(&sc1, sc2);
131 132
132 ok(mp_compute_subcheck_state(sc1) == STATE_WARNING, "Test subcheck state after adding a subcheck"); 133 ok(mp_compute_subcheck_state(sc1) == STATE_WARNING,
134 "Test subcheck state after adding a subcheck");
133 135
134 mp_check check = mp_check_init(); 136 mp_check check = mp_check_init();
135 mp_add_subcheck_to_check(&check, sc1); 137 mp_add_subcheck_to_check(&check, sc1);
diff --git a/lib/tests/test_ini1.c b/lib/tests/test_ini1.c
index 246c1250..de983764 100644
--- a/lib/tests/test_ini1.c
+++ b/lib/tests/test_ini1.c
@@ -42,27 +42,30 @@ char *list2str(np_arg_list *optlst) {
42 free(optltmp); 42 free(optltmp);
43 } 43 }
44 /* Strip last whitespace */ 44 /* Strip last whitespace */
45 if (strlen(optstr) > 1) 45 if (strlen(optstr) > 1) {
46 optstr[strlen(optstr) - 1] = '\0'; 46 optstr[strlen(optstr) - 1] = '\0';
47 }
47 48
48 return optstr; 49 return optstr;
49} 50}
50 51
51int main(int argc, char **argv) { 52int main(int argc, char **argv) {
52 char *optstr = NULL;
53 53
54 plan_tests(12); 54 plan_tests(12);
55 55
56 optstr = list2str(np_get_defaults("section@./config-tiny.ini", "check_disk")); 56 char *optstr = list2str(np_get_defaults("section@./config-tiny.ini", "check_disk"));
57 ok(!strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"), "config-tiny.ini's section as expected"); 57 ok(!strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"),
58 "config-tiny.ini's section as expected");
58 my_free(optstr); 59 my_free(optstr);
59 60
60 optstr = list2str(np_get_defaults("@./config-tiny.ini", "section")); 61 optstr = list2str(np_get_defaults("@./config-tiny.ini", "section"));
61 ok(!strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"), "Used default section name, without specific"); 62 ok(!strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"),
63 "Used default section name, without specific");
62 my_free(optstr); 64 my_free(optstr);
63 65
64 optstr = list2str(np_get_defaults("Section Two@./config-tiny.ini", "check_disk")); 66 optstr = list2str(np_get_defaults("Section Two@./config-tiny.ini", "check_disk"));
65 ok(!strcmp(optstr, "--something else=blah --remove=whitespace"), "config-tiny.ini's Section Two as expected"); 67 ok(!strcmp(optstr, "--something else=blah --remove=whitespace"),
68 "config-tiny.ini's Section Two as expected");
66 my_free(optstr); 69 my_free(optstr);
67 70
68 optstr = list2str(np_get_defaults("/path/to/file.txt@./config-tiny.ini", "check_disk")); 71 optstr = list2str(np_get_defaults("/path/to/file.txt@./config-tiny.ini", "check_disk"));
@@ -70,15 +73,18 @@ int main(int argc, char **argv) {
70 my_free(optstr); 73 my_free(optstr);
71 74
72 optstr = list2str(np_get_defaults("section2@./config-tiny.ini", "check_disk")); 75 optstr = list2str(np_get_defaults("section2@./config-tiny.ini", "check_disk"));
73 ok(!strcmp(optstr, "--this=that"), "config-tiny.ini's section2 with whitespace before section name"); 76 ok(!strcmp(optstr, "--this=that"),
77 "config-tiny.ini's section2 with whitespace before section name");
74 my_free(optstr); 78 my_free(optstr);
75 79
76 optstr = list2str(np_get_defaults("section3@./config-tiny.ini", "check_disk")); 80 optstr = list2str(np_get_defaults("section3@./config-tiny.ini", "check_disk"));
77 ok(!strcmp(optstr, "--this=that"), "config-tiny.ini's section3 with whitespace after section name"); 81 ok(!strcmp(optstr, "--this=that"),
82 "config-tiny.ini's section3 with whitespace after section name");
78 my_free(optstr); 83 my_free(optstr);
79 84
80 optstr = list2str(np_get_defaults("check_mysql@./plugin.ini", "check_disk")); 85 optstr = list2str(np_get_defaults("check_mysql@./plugin.ini", "check_disk"));
81 ok(!strcmp(optstr, "--username=operator --password=secret"), "plugin.ini's check_mysql as expected"); 86 ok(!strcmp(optstr, "--username=operator --password=secret"),
87 "plugin.ini's check_mysql as expected");
82 my_free(optstr); 88 my_free(optstr);
83 89
84 optstr = list2str(np_get_defaults("check_mysql2@./plugin.ini", "check_disk")); 90 optstr = list2str(np_get_defaults("check_mysql2@./plugin.ini", "check_disk"));
@@ -90,29 +96,39 @@ int main(int argc, char **argv) {
90 my_free(optstr); 96 my_free(optstr);
91 97
92 optstr = list2str(np_get_defaults("Section Two@./config-dos.ini", "check_disk")); 98 optstr = list2str(np_get_defaults("Section Two@./config-dos.ini", "check_disk"));
93 ok(!strcmp(optstr, "--something else=blah --remove=whitespace"), "config-dos.ini's Section Two as expected"); 99 ok(!strcmp(optstr, "--something else=blah --remove=whitespace"),
100 "config-dos.ini's Section Two as expected");
94 my_free(optstr); 101 my_free(optstr);
95 102
96 optstr = list2str(np_get_defaults("section_twice@./plugin.ini", "check_disk")); 103 optstr = list2str(np_get_defaults("section_twice@./plugin.ini", "check_disk"));
97 ok(!strcmp(optstr, "--foo=bar --bar=foo"), "plugin.ini's section_twice defined twice in the file"); 104 ok(!strcmp(optstr, "--foo=bar --bar=foo"),
105 "plugin.ini's section_twice defined twice in the file");
98 my_free(optstr); 106 my_free(optstr);
99 107
100 optstr = list2str(np_get_defaults("tcp_long_lines@plugins.ini", "check_tcp")); 108 optstr = list2str(np_get_defaults("tcp_long_lines@plugins.ini", "check_tcp"));
101 ok(!strcmp(optstr, "--escape --send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar " 109 ok(!strcmp(optstr, "--escape --send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
110 "yadda Foo bar BAZ yadda yadda yadda Foo bar "
102 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda " 111 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
103 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda " 112 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar "
113 "BAZ yadda yadda yadda Foo bar BAZ yadda "
104 "yadda yadda Foo bar BAZ yadda yadda yadda Foo " 114 "yadda yadda Foo bar BAZ yadda yadda yadda Foo "
105 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda " 115 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
116 "yadda yadda Foo bar BAZ yadda yadda "
106 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ " 117 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
107 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda --expect=Foo bar BAZ yadda yadda " 118 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
119 "yadda --expect=Foo bar BAZ yadda yadda "
108 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ " 120 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
109 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo " 121 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
122 "yadda Foo bar BAZ yadda yadda yadda Foo "
110 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda " 123 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
111 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda " 124 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar "
125 "BAZ yadda yadda yadda Foo bar BAZ yadda "
112 "yadda yadda Foo bar BAZ yadda yadda yadda Foo " 126 "yadda yadda Foo bar BAZ yadda yadda yadda Foo "
113 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda " 127 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
128 "yadda yadda Foo bar BAZ yadda yadda "
114 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ " 129 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
115 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo " 130 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
131 "yadda Foo bar BAZ yadda yadda yadda Foo "
116 "bar BAZ yadda yadda yadda --jail"), 132 "bar BAZ yadda yadda yadda --jail"),
117 "Long options"); 133 "Long options");
118 my_free(optstr); 134 my_free(optstr);
diff --git a/lib/tests/test_opts1.c b/lib/tests/test_opts1.c
index 984183d3..fa95c4d4 100644
--- a/lib/tests/test_opts1.c
+++ b/lib/tests/test_opts1.c
@@ -40,37 +40,40 @@ void my_free(int *argc, char **newargv, char **argv) {
40#else 40#else
41void my_free(int *argc, char **newargv, char **argv) { 41void my_free(int *argc, char **newargv, char **argv) {
42 /* Free stuff (and print while we're at it) */ 42 /* Free stuff (and print while we're at it) */
43 int i, freeflag = 1; 43 bool freeflag = true;
44 printf(" Arg(%i): ", *argc + 1); 44 printf(" Arg(%i): ", *argc + 1);
45 printf("'%s' ", newargv[0]); 45 printf("'%s' ", newargv[0]);
46 for (i = 1; i < *argc; i++) { 46
47 for (int i = 1; i < *argc; i++) {
47 printf("'%s' ", newargv[i]); 48 printf("'%s' ", newargv[i]);
48 /* Stop freeing when we get to the start of the original array */ 49 /* Stop freeing when we get to the start of the original array */
49 if (freeflag) { 50 if (freeflag) {
50 if (newargv[i] == argv[1]) 51 if (newargv[i] == argv[1]) {
51 freeflag = 0; 52 freeflag = false;
52 else 53 } else {
53 free(newargv[i]); 54 free(newargv[i]);
55 }
54 } 56 }
55 } 57 }
56 printf("\n"); 58 printf("\n");
57 /* Free only if it's a different array */ 59 /* Free only if it's a different array */
58 if (newargv != argv) 60 if (newargv != argv) {
59 free(newargv); 61 free(newargv);
62 }
60 *argc = 0; 63 *argc = 0;
61} 64}
62#endif 65#endif
63 66
64int array_diff(int i1, char **a1, int i2, char **a2) { 67int array_diff(int i1, char **a1, int i2, char **a2) {
65 int i;
66
67 if (i1 != i2) { 68 if (i1 != i2) {
68 printf(" Argument count doesn't match!\n"); 69 printf(" Argument count doesn't match!\n");
69 return 0; 70 return 0;
70 } 71 }
71 for (i = 0; i <= i1; i++) { 72
72 if (a1[i] == NULL && a2[i] == NULL) 73 for (int i = 0; i <= i1; i++) {
74 if (a1[i] == NULL && a2[i] == NULL) {
73 continue; 75 continue;
76 }
74 if (a1[i] == NULL || a2[i] == NULL) { 77 if (a1[i] == NULL || a2[i] == NULL) {
75 printf(" Argument # %i null in one array!\n", i); 78 printf(" Argument # %i null in one array!\n", i);
76 return 0; 79 return 0;
@@ -84,11 +87,10 @@ int array_diff(int i1, char **a1, int i2, char **a2) {
84} 87}
85 88
86int main(int argc, char **argv) { 89int main(int argc, char **argv) {
87 char **argv_new = NULL;
88 int i, argc_test;
89
90 plan_tests(5); 90 plan_tests(5);
91 91
92 char **argv_new = NULL;
93 int argc_test;
92 { 94 {
93 char *argv_test[] = {"prog_name", (char *)NULL}; 95 char *argv_test[] = {"prog_name", (char *)NULL};
94 argc_test = 1; 96 argc_test = 1;
@@ -110,27 +112,36 @@ int main(int argc, char **argv) {
110 { 112 {
111 char *argv_test[] = {"prog_name", "--extra-opts=@./config-opts.ini", (char *)NULL}; 113 char *argv_test[] = {"prog_name", "--extra-opts=@./config-opts.ini", (char *)NULL};
112 argc_test = 2; 114 argc_test = 2;
113 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", (char *)NULL}; 115 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank",
116 (char *)NULL};
114 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk"); 117 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
115 ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts using default section"); 118 ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts using default section");
116 my_free(&argc_test, argv_new, argv_test); 119 my_free(&argc_test, argv_new, argv_test);
117 } 120 }
118 121
119 { 122 {
120 char *argv_test[] = {"prog_name", "--extra-opts=sect1@./config-opts.ini", "--extra-opts", "sect2@./config-opts.ini", (char *)NULL}; 123 char *argv_test[] = {"prog_name", "--extra-opts=sect1@./config-opts.ini", "--extra-opts",
124 "sect2@./config-opts.ini", (char *)NULL};
121 argc_test = 4; 125 argc_test = 4;
122 char *argv_known[] = {"prog_name", "--one=two", "--something else=oops", "--this=that", (char *)NULL}; 126 char *argv_known[] = {"prog_name", "--one=two", "--something else=oops", "--this=that",
127 (char *)NULL};
123 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk"); 128 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
124 ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts specified twice"); 129 ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts specified twice");
125 my_free(&argc_test, argv_new, argv_test); 130 my_free(&argc_test, argv_new, argv_test);
126 } 131 }
127 132
128 { 133 {
129 char *argv_test[] = {"prog_name", "--arg1=val1", "--extra-opts=@./config-opts.ini", "--extra-opts", "sect1@./config-opts.ini", 134 char *argv_test[] = {"prog_name",
130 "--arg2", (char *)NULL}; 135 "--arg1=val1",
136 "--extra-opts=@./config-opts.ini",
137 "--extra-opts",
138 "sect1@./config-opts.ini",
139 "--arg2",
140 (char *)NULL};
131 argc_test = 6; 141 argc_test = 6;
132 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", "--one=two", 142 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!",
133 "--arg1=val1", "--arg2", (char *)NULL}; 143 "--blank", "--one=two", "--arg1=val1",
144 "--arg2", (char *)NULL};
134 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk"); 145 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
135 ok(array_diff(argc_test, argv_new, 7, argv_known), "twice extra opts using two sections"); 146 ok(array_diff(argc_test, argv_new, 7, argv_known), "twice extra opts using two sections");
136 my_free(&argc_test, argv_new, argv_test); 147 my_free(&argc_test, argv_new, argv_test);
diff --git a/lib/tests/test_opts2.c b/lib/tests/test_opts2.c
index 23496617..3dd1b039 100644
--- a/lib/tests/test_opts2.c
+++ b/lib/tests/test_opts2.c
@@ -23,36 +23,39 @@
23 23
24void my_free(int *argc, char **newargv, char **argv) { 24void my_free(int *argc, char **newargv, char **argv) {
25 /* Free stuff (and print while we're at it) */ 25 /* Free stuff (and print while we're at it) */
26 int i, freeflag = 1; 26 bool freeflag = true;
27
27 printf(" Arg(%i): ", *argc + 1); 28 printf(" Arg(%i): ", *argc + 1);
28 printf("'%s' ", newargv[0]); 29 printf("'%s' ", newargv[0]);
29 for (i = 1; i < *argc; i++) { 30 for (int i = 1; i < *argc; i++) {
30 printf("'%s' ", newargv[i]); 31 printf("'%s' ", newargv[i]);
31 /* Stop freeing when we get to the start of the original array */ 32 /* Stop freeing when we get to the start of the original array */
32 if (freeflag) { 33 if (freeflag) {
33 if (newargv[i] == argv[1]) 34 if (newargv[i] == argv[1]) {
34 freeflag = 0; 35 freeflag = false;
35 else 36 } else {
36 free(newargv[i]); 37 free(newargv[i]);
38 }
37 } 39 }
38 } 40 }
39 printf("\n"); 41 printf("\n");
40 /* Free only if it's a different array */ 42 /* Free only if it's a different array */
41 if (newargv != argv) 43 if (newargv != argv) {
42 free(newargv); 44 free(newargv);
45 }
43 *argc = 0; 46 *argc = 0;
44} 47}
45 48
46int array_diff(int i1, char **a1, int i2, char **a2) { 49int array_diff(int i1, char **a1, int i2, char **a2) {
47 int i;
48
49 if (i1 != i2) { 50 if (i1 != i2) {
50 printf(" Argument count doesn't match!\n"); 51 printf(" Argument count doesn't match!\n");
51 return 0; 52 return 0;
52 } 53 }
53 for (i = 0; i <= i1; i++) { 54
54 if (a1[i] == NULL && a2[i] == NULL) 55 for (int i = 0; i <= i1; i++) {
56 if (a1[i] == NULL && a2[i] == NULL) {
55 continue; 57 continue;
58 }
56 if (a1[i] == NULL || a2[i] == NULL) { 59 if (a1[i] == NULL || a2[i] == NULL) {
57 printf(" Argument # %i null in one array!\n", i); 60 printf(" Argument # %i null in one array!\n", i);
58 return 0; 61 return 0;
@@ -66,11 +69,10 @@ int array_diff(int i1, char **a1, int i2, char **a2) {
66} 69}
67 70
68int main(int argc, char **argv) { 71int main(int argc, char **argv) {
69 char **argv_new = NULL;
70 int i, argc_test;
71
72 plan_tests(5); 72 plan_tests(5);
73 73
74 char **argv_new = NULL;
75 int argc_test;
74 { 76 {
75 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "--arg3", "val2", (char *)NULL}; 77 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "--arg3", "val2", (char *)NULL};
76 argc_test = 5; 78 argc_test = 5;
@@ -90,7 +92,8 @@ int main(int argc, char **argv) {
90 } 92 }
91 93
92 { 94 {
93 char *argv_test[] = {"prog_name", "arg1", "--extra-opts=section1", "--arg3", "val2", (char *)NULL}; 95 char *argv_test[] = {"prog_name", "arg1", "--extra-opts=section1",
96 "--arg3", "val2", (char *)NULL};
94 argc_test = 5; 97 argc_test = 5;
95 char *argv_known[] = {"prog_name", "--foobar=baz", "arg1", "--arg3", "val2", (char *)NULL}; 98 char *argv_known[] = {"prog_name", "--foobar=baz", "arg1", "--arg3", "val2", (char *)NULL};
96 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk"); 99 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
@@ -108,30 +111,39 @@ int main(int argc, char **argv) {
108 } 111 }
109 112
110 { 113 {
111 char *argv_test[] = {"check_tcp", "--extra-opts", "--extra-opts=tcp_long_lines", (char *)NULL}; 114 char *argv_test[] = {"check_tcp", "--extra-opts", "--extra-opts=tcp_long_lines",
115 (char *)NULL};
112 argc_test = 3; 116 argc_test = 3;
113 char *argv_known[] = { 117 char *argv_known[] = {"check_tcp",
114 "check_tcp", 118 "--timeout=10",
115 "--timeout=10", 119 "--escape",
116 "--escape", 120 "--send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda "
117 "--send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda " 121 "Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
118 "yadda Foo bar BAZ yadda " 122 "yadda Foo bar BAZ yadda "
119 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda " 123 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
120 "yadda Foo bar BAZ " 124 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
121 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda " 125 "yadda Foo bar BAZ "
122 "yadda yadda Foo bar " 126 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
123 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda", 127 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
124 "--expect=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda " 128 "yadda yadda Foo bar "
125 "yadda Foo bar BAZ yadda " 129 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
126 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda " 130 "yadda yadda yadda Foo bar BAZ yadda yadda yadda",
127 "yadda Foo bar BAZ " 131 "--expect=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
128 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda " 132 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
129 "yadda yadda Foo bar " 133 "yadda Foo bar BAZ yadda "
130 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ " 134 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
131 "yadda yadda yadda Foo " 135 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
132 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda", 136 "yadda Foo bar BAZ "
133 "--jail", 137 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
134 (char *)NULL}; 138 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
139 "yadda yadda Foo bar "
140 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
141 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
142 "yadda yadda yadda Foo "
143 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
144 "yadda yadda yadda Foo bar BAZ yadda yadda yadda",
145 "--jail",
146 (char *)NULL};
135 argv_new = np_extra_opts(&argc_test, argv_test, "check_tcp"); 147 argv_new = np_extra_opts(&argc_test, argv_test, "check_tcp");
136 ok(array_diff(argc_test, argv_new, 6, argv_known), "Long lines test"); 148 ok(array_diff(argc_test, argv_new, 6, argv_known), "Long lines test");
137 my_free(&argc_test, argv_new, argv_test); 149 my_free(&argc_test, argv_new, argv_test);
diff --git a/lib/tests/test_tcp.c b/lib/tests/test_tcp.c
index 1b3003e9..37c818c9 100644
--- a/lib/tests/test_tcp.c
+++ b/lib/tests/test_tcp.c
@@ -21,30 +21,38 @@
21#include "tap.h" 21#include "tap.h"
22 22
23int main(void) { 23int main(void) {
24 char **server_expect;
25 int server_expect_count = 3;
26
27 plan_tests(9); 24 plan_tests(9);
28 25
26 char **server_expect;
27 const int server_expect_count = 3;
29 server_expect = malloc(sizeof(char *) * server_expect_count); 28 server_expect = malloc(sizeof(char *) * server_expect_count);
30 29
31 server_expect[0] = strdup("AA"); 30 server_expect[0] = strdup("AA");
32 server_expect[1] = strdup("bb"); 31 server_expect[1] = strdup("bb");
33 server_expect[2] = strdup("CC"); 32 server_expect[2] = strdup("CC");
34 33
35 ok(np_expect_match("AA bb CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_SUCCESS, 34 ok(np_expect_match("AA bb CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) ==
35 NP_MATCH_SUCCESS,
36 "Test matching any string at the beginning (first expect string)"); 36 "Test matching any string at the beginning (first expect string)");
37 ok(np_expect_match("bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_SUCCESS, 37 ok(np_expect_match("bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) ==
38 NP_MATCH_SUCCESS,
38 "Test matching any string at the beginning (second expect string)"); 39 "Test matching any string at the beginning (second expect string)");
39 ok(np_expect_match("b", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_RETRY, 40 ok(np_expect_match("b", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_RETRY,
40 "Test matching any string at the beginning (substring match)"); 41 "Test matching any string at the beginning (substring match)");
41 ok(np_expect_match("XX bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_FAILURE, 42 ok(np_expect_match("XX bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) ==
43 NP_MATCH_FAILURE,
42 "Test with strings not matching at the beginning"); 44 "Test with strings not matching at the beginning");
43 ok(np_expect_match("XX CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_FAILURE, "Test matching any string"); 45 ok(np_expect_match("XX CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) ==
44 ok(np_expect_match("XX", server_expect, server_expect_count, 0) == NP_MATCH_RETRY, "Test not matching any string"); 46 NP_MATCH_FAILURE,
45 ok(np_expect_match("XX AA bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_SUCCESS, 47 "Test matching any string");
48 ok(np_expect_match("XX", server_expect, server_expect_count, 0) == NP_MATCH_RETRY,
49 "Test not matching any string");
50 ok(np_expect_match("XX AA bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) ==
51 NP_MATCH_SUCCESS,
46 "Test matching all strings"); 52 "Test matching all strings");
47 ok(np_expect_match("XX bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY, "Test not matching all strings"); 53 ok(np_expect_match("XX bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) ==
54 NP_MATCH_RETRY,
55 "Test not matching all strings");
48 ok(np_expect_match("XX XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY, 56 ok(np_expect_match("XX XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY,
49 "Test not matching any string (testing all)"); 57 "Test not matching any string (testing all)");
50 58
diff --git a/lib/tests/test_utils.c b/lib/tests/test_utils.c
index c3150f00..8040dec8 100644
--- a/lib/tests/test_utils.c
+++ b/lib/tests/test_utils.c
@@ -28,17 +28,7 @@
28#include "utils_base.c" 28#include "utils_base.c"
29 29
30int main(int argc, char **argv) { 30int main(int argc, char **argv) {
31 char state_path[1024]; 31 plan_tests(155);
32 range *range;
33 double temp;
34 thresholds *thresholds = NULL;
35 int i, rc;
36 char *temp_string;
37 state_key *temp_state_key = NULL;
38 state_data *temp_state_data;
39 time_t current_time;
40
41 plan_tests(185);
42 32
43 ok(this_monitoring_plugin == NULL, "monitoring_plugin not initialised"); 33 ok(this_monitoring_plugin == NULL, "monitoring_plugin not initialised");
44 34
@@ -57,7 +47,7 @@ int main(int argc, char **argv) {
57 47
58 np_set_args(argc, argv); 48 np_set_args(argc, argv);
59 49
60 range = parse_range_string("6"); 50 range *range = parse_range_string("6");
61 ok(range != NULL, "'6' is valid range"); 51 ok(range != NULL, "'6' is valid range");
62 ok(range->start == 0, "Start correct"); 52 ok(range->start == 0, "Start correct");
63 ok(range->start_infinity == false, "Not using negative infinity"); 53 ok(range->start_infinity == false, "Not using negative infinity");
@@ -97,7 +87,7 @@ int main(int argc, char **argv) {
97 free(range); 87 free(range);
98 88
99 range = parse_range_string("12345678901234567890:"); 89 range = parse_range_string("12345678901234567890:");
100 temp = atof("12345678901234567890"); /* Can't just use this because number too large */ 90 double temp = atof("12345678901234567890"); /* Can't just use this because number too large */
101 ok(range != NULL, "'12345678901234567890:' is valid range"); 91 ok(range != NULL, "'12345678901234567890:' is valid range");
102 ok(range->start == temp, "Start correct"); 92 ok(range->start == temp, "Start correct");
103 ok(range->start_infinity == false, "Not using negative infinity"); 93 ok(range->start_infinity == false, "Not using negative infinity");
@@ -158,32 +148,34 @@ int main(int argc, char **argv) {
158 range = parse_range_string("2:1"); 148 range = parse_range_string("2:1");
159 ok(range == NULL, "'2:1' rejected"); 149 ok(range == NULL, "'2:1' rejected");
160 150
161 rc = _set_thresholds(&thresholds, NULL, NULL); 151 thresholds *thresholds = NULL;
162 ok(rc == 0, "Thresholds (NULL, NULL) set"); 152 int returnCode;
153 returnCode = _set_thresholds(&thresholds, NULL, NULL);
154 ok(returnCode == 0, "Thresholds (NULL, NULL) set");
163 ok(thresholds->warning == NULL, "Warning not set"); 155 ok(thresholds->warning == NULL, "Warning not set");
164 ok(thresholds->critical == NULL, "Critical not set"); 156 ok(thresholds->critical == NULL, "Critical not set");
165 157
166 rc = _set_thresholds(&thresholds, NULL, "80"); 158 returnCode = _set_thresholds(&thresholds, NULL, "80");
167 ok(rc == 0, "Thresholds (NULL, '80') set"); 159 ok(returnCode == 0, "Thresholds (NULL, '80') set");
168 ok(thresholds->warning == NULL, "Warning not set"); 160 ok(thresholds->warning == NULL, "Warning not set");
169 ok(thresholds->critical->end == 80, "Critical set correctly"); 161 ok(thresholds->critical->end == 80, "Critical set correctly");
170 162
171 rc = _set_thresholds(&thresholds, "5:33", NULL); 163 returnCode = _set_thresholds(&thresholds, "5:33", NULL);
172 ok(rc == 0, "Thresholds ('5:33', NULL) set"); 164 ok(returnCode == 0, "Thresholds ('5:33', NULL) set");
173 ok(thresholds->warning->start == 5, "Warning start set"); 165 ok(thresholds->warning->start == 5, "Warning start set");
174 ok(thresholds->warning->end == 33, "Warning end set"); 166 ok(thresholds->warning->end == 33, "Warning end set");
175 ok(thresholds->critical == NULL, "Critical not set"); 167 ok(thresholds->critical == NULL, "Critical not set");
176 168
177 rc = _set_thresholds(&thresholds, "30", "60"); 169 returnCode = _set_thresholds(&thresholds, "30", "60");
178 ok(rc == 0, "Thresholds ('30', '60') set"); 170 ok(returnCode == 0, "Thresholds ('30', '60') set");
179 ok(thresholds->warning->end == 30, "Warning set correctly"); 171 ok(thresholds->warning->end == 30, "Warning set correctly");
180 ok(thresholds->critical->end == 60, "Critical set correctly"); 172 ok(thresholds->critical->end == 60, "Critical set correctly");
181 ok(get_status(15.3, thresholds) == STATE_OK, "15.3 - ok"); 173 ok(get_status(15.3, thresholds) == STATE_OK, "15.3 - ok");
182 ok(get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning"); 174 ok(get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning");
183 ok(get_status(69, thresholds) == STATE_CRITICAL, "69 - critical"); 175 ok(get_status(69, thresholds) == STATE_CRITICAL, "69 - critical");
184 176
185 rc = _set_thresholds(&thresholds, "-10:-2", "-30:20"); 177 returnCode = _set_thresholds(&thresholds, "-10:-2", "-30:20");
186 ok(rc == 0, "Thresholds ('-30:20', '-10:-2') set"); 178 ok(returnCode == 0, "Thresholds ('-30:20', '-10:-2') set");
187 ok(thresholds->warning->start == -10, "Warning start set correctly"); 179 ok(thresholds->warning->start == -10, "Warning start set correctly");
188 ok(thresholds->warning->end == -2, "Warning end set correctly"); 180 ok(thresholds->warning->end == -2, "Warning end set correctly");
189 ok(thresholds->critical->start == -30, "Critical start set correctly"); 181 ok(thresholds->critical->start == -30, "Critical start set correctly");
@@ -304,164 +296,28 @@ int main(int argc, char **argv) {
304 test = np_extract_ntpvar("", "foo"); 296 test = np_extract_ntpvar("", "foo");
305 ok(!test, "Empty string return NULL"); 297 ok(!test, "Empty string return NULL");
306 298
307 /* This is the result of running ./test_utils */
308 temp_string = (char *)_np_state_generate_key();
309 ok(!strcmp(temp_string, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got hash with exe and no parameters") ||
310 diag("You are probably running in wrong directory. Must run as ./test_utils");
311
312 this_monitoring_plugin->argc = 4;
313 this_monitoring_plugin->argv[0] = "./test_utils";
314 this_monitoring_plugin->argv[1] = "here";
315 this_monitoring_plugin->argv[2] = "--and";
316 this_monitoring_plugin->argv[3] = "now";
317 temp_string = (char *)_np_state_generate_key();
318 ok(!strcmp(temp_string, "bd72da9f78ff1419fad921ea5e43ce56508aef6c"), "Got based on expected argv");
319
320 unsetenv("MP_STATE_PATH");
321 temp_string = (char *)_np_state_calculate_location_prefix();
322 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory");
323
324 setenv("MP_STATE_PATH", "", 1);
325 temp_string = (char *)_np_state_calculate_location_prefix();
326 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory even with empty string");
327
328 setenv("MP_STATE_PATH", "/usr/local/nagios/var", 1);
329 temp_string = (char *)_np_state_calculate_location_prefix();
330 ok(!strcmp(temp_string, "/usr/local/nagios/var"), "Got default directory");
331
332 ok(temp_state_key == NULL, "temp_state_key initially empty");
333
334 this_monitoring_plugin->argc = 1;
335 this_monitoring_plugin->argv[0] = "./test_utils";
336 np_enable_state(NULL, 51);
337 temp_state_key = this_monitoring_plugin->state;
338 ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name");
339 ok(!strcmp(temp_state_key->name, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got generated filename");
340
341 np_enable_state("allowedchars_in_keyname", 77);
342 temp_state_key = this_monitoring_plugin->state;
343 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/allowedchars_in_keyname", (unsigned long)geteuid());
344 ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name");
345 ok(!strcmp(temp_state_key->name, "allowedchars_in_keyname"), "Got key name with valid chars");
346 ok(!strcmp(temp_state_key->_filename, state_path), "Got internal filename");
347
348 /* Don't do this test just yet. Will die */
349 /*
350 np_enable_state("bad^chars$in@here", 77);
351 temp_state_key = this_monitoring_plugin->state;
352 ok( !strcmp(temp_state_key->name, "bad_chars_in_here"), "Got key name with bad chars replaced" );
353 */
354
355 np_enable_state("funnykeyname", 54);
356 temp_state_key = this_monitoring_plugin->state;
357 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/funnykeyname", (unsigned long)geteuid());
358 ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name");
359 ok(!strcmp(temp_state_key->name, "funnykeyname"), "Got key name");
360
361 ok(!strcmp(temp_state_key->_filename, state_path), "Got internal filename");
362 ok(temp_state_key->data_version == 54, "Version set");
363
364 temp_state_data = np_state_read();
365 ok(temp_state_data == NULL, "Got no state data as file does not exist");
366
367 /*
368 temp_fp = fopen("var/statefile", "r");
369 if (temp_fp==NULL)
370 printf("Error opening. errno=%d\n", errno);
371 printf("temp_fp=%s\n", temp_fp);
372 ok( _np_state_read_file(temp_fp) == true, "Can read state file" );
373 fclose(temp_fp);
374 */
375
376 temp_state_key->_filename = "var/statefile";
377 temp_state_data = np_state_read();
378 ok(this_monitoring_plugin->state->state_data != NULL, "Got state data now") ||
379 diag("Are you running in right directory? Will get coredump next if not");
380 ok(this_monitoring_plugin->state->state_data->time == 1234567890, "Got time");
381 ok(!strcmp((char *)this_monitoring_plugin->state->state_data->data, "String to read"), "Data as expected");
382
383 temp_state_key->data_version = 53;
384 temp_state_data = np_state_read();
385 ok(temp_state_data == NULL, "Older data version gives NULL");
386 temp_state_key->data_version = 54;
387
388 temp_state_key->_filename = "var/nonexistent";
389 temp_state_data = np_state_read();
390 ok(temp_state_data == NULL, "Missing file gives NULL");
391 ok(this_monitoring_plugin->state->state_data == NULL, "No state information");
392
393 temp_state_key->_filename = "var/oldformat";
394 temp_state_data = np_state_read();
395 ok(temp_state_data == NULL, "Old file format gives NULL");
396
397 temp_state_key->_filename = "var/baddate";
398 temp_state_data = np_state_read();
399 ok(temp_state_data == NULL, "Bad date gives NULL");
400
401 temp_state_key->_filename = "var/missingdataline";
402 temp_state_data = np_state_read();
403 ok(temp_state_data == NULL, "Missing data line gives NULL");
404
405 unlink("var/generated");
406 temp_state_key->_filename = "var/generated";
407 current_time = 1234567890;
408 np_state_write_string(current_time, "String to read");
409 ok(system("cmp var/generated var/statefile") == 0, "Generated file same as expected");
410
411 unlink("var/generated_directory/statefile");
412 unlink("var/generated_directory");
413 temp_state_key->_filename = "var/generated_directory/statefile";
414 current_time = 1234567890;
415 np_state_write_string(current_time, "String to read");
416 ok(system("cmp var/generated_directory/statefile var/statefile") == 0, "Have created directory");
417
418 /* This test to check cannot write to dir - can't automate yet */
419 /*
420 unlink("var/generated_bad_dir");
421 mkdir("var/generated_bad_dir", S_IRUSR);
422 np_state_write_string(current_time, "String to read");
423 */
424
425 temp_state_key->_filename = "var/generated";
426 time(&current_time);
427 np_state_write_string(0, "String to read");
428 temp_state_data = np_state_read();
429 /* Check time is set to current_time */
430 ok(system("cmp var/generated var/statefile > /dev/null") != 0, "Generated file should be different this time");
431 ok(this_monitoring_plugin->state->state_data->time - current_time <= 1, "Has time generated from current time");
432
433 /* Don't know how to automatically test this. Need to be able to redefine die and catch the error */
434 /*
435 temp_state_key->_filename="/dev/do/not/expect/to/be/able/to/write";
436 np_state_write_string(0, "Bad file");
437 */
438
439 np_cleanup();
440
441 ok(this_monitoring_plugin == NULL, "Free'd this_monitoring_plugin");
442
443 ok(mp_suid() == false, "Test aren't suid"); 299 ok(mp_suid() == false, "Test aren't suid");
444 300
445 /* base states with random case */ 301 /* base states with random case */
446 char *states[] = {"Ok", "wArnINg", "cRiTIcaL", "UnKNoWN", NULL}; 302 char *states[] = {"Ok", "wArnINg", "cRiTIcaL", "UnKNoWN", NULL};
447 303
448 for (i = 0; states[i] != NULL; i++) { 304 for (int i = 0; states[i] != NULL; i++) {
449 /* out of the random case states, create the lower and upper versions + numeric string one */ 305 /* out of the random case states, create the lower and upper versions + numeric string one
306 */
450 char *statelower = strdup(states[i]); 307 char *statelower = strdup(states[i]);
451 char *stateupper = strdup(states[i]); 308 char *stateupper = strdup(states[i]);
452 char statenum[2]; 309 char statenum[2];
453 char *temp_ptr; 310 for (char *temp_ptr = statelower; *temp_ptr; temp_ptr++) {
454 for (temp_ptr = statelower; *temp_ptr; temp_ptr++) { 311 *temp_ptr = (char)tolower(*temp_ptr);
455 *temp_ptr = tolower(*temp_ptr);
456 } 312 }
457 for (temp_ptr = stateupper; *temp_ptr; temp_ptr++) { 313 for (char *temp_ptr = stateupper; *temp_ptr; temp_ptr++) {
458 *temp_ptr = toupper(*temp_ptr); 314 *temp_ptr = (char)toupper(*temp_ptr);
459 } 315 }
460 snprintf(statenum, 2, "%i", i); 316 snprintf(statenum, 2, "%i", i);
461 317
462 /* Base test names, we'll append the state string */ 318 /* Base test names, we'll append the state string */
463 char testname[64] = "Translate state string: "; 319 char testname[64] = "Translate state string: ";
464 int tlen = strlen(testname); 320 size_t tlen = strlen(testname);
465 321
466 strcpy(testname + tlen, states[i]); 322 strcpy(testname + tlen, states[i]);
467 ok(i == mp_translate_state(states[i]), testname); 323 ok(i == mp_translate_state(states[i]), testname);
diff --git a/lib/thresholds.c b/lib/thresholds.c
index ddefae37..de2b9315 100644
--- a/lib/thresholds.c
+++ b/lib/thresholds.c
@@ -51,9 +51,21 @@ mp_state_enum mp_get_pd_status(mp_perfdata perfdata) {
51 } 51 }
52 if (perfdata.warn_present) { 52 if (perfdata.warn_present) {
53 if (mp_check_range(perfdata.value, perfdata.warn)) { 53 if (mp_check_range(perfdata.value, perfdata.warn)) {
54 return STATE_CRITICAL; 54 return STATE_WARNING;
55 } 55 }
56 } 56 }
57 57
58 return STATE_OK; 58 return STATE_OK;
59} 59}
60
61mp_thresholds mp_thresholds_set_warn(mp_thresholds thlds, mp_range warn) {
62 thlds.warning = warn;
63 thlds.warning_is_set = true;
64 return thlds;
65}
66
67mp_thresholds mp_thresholds_set_crit(mp_thresholds thlds, mp_range crit) {
68 thlds.critical = crit;
69 thlds.critical_is_set = true;
70 return thlds;
71}
diff --git a/lib/thresholds.h b/lib/thresholds.h
index 4e7defee..f8647681 100644
--- a/lib/thresholds.h
+++ b/lib/thresholds.h
@@ -6,12 +6,12 @@
6/* 6/*
7 * Old threshold type using the old range type 7 * Old threshold type using the old range type
8 */ 8 */
9typedef struct thresholds_struct { 9typedef struct {
10 range *warning; 10 range *warning;
11 range *critical; 11 range *critical;
12} thresholds; 12} thresholds;
13 13
14typedef struct mp_thresholds_struct { 14typedef struct {
15 bool warning_is_set; 15 bool warning_is_set;
16 mp_range warning; 16 mp_range warning;
17 bool critical_is_set; 17 bool critical_is_set;
@@ -24,5 +24,8 @@ mp_perfdata mp_pd_set_thresholds(mp_perfdata /* pd */, mp_thresholds /* th */);
24 24
25mp_state_enum mp_get_pd_status(mp_perfdata /* pd */); 25mp_state_enum mp_get_pd_status(mp_perfdata /* pd */);
26 26
27mp_thresholds mp_thresholds_set_warn(mp_thresholds thlds, mp_range warn);
28mp_thresholds mp_thresholds_set_crit(mp_thresholds thlds, mp_range crit);
29
27char *fmt_threshold_warning(thresholds th); 30char *fmt_threshold_warning(thresholds th);
28char *fmt_threshold_critical(thresholds th); 31char *fmt_threshold_critical(thresholds th);
diff --git a/lib/utils_base.c b/lib/utils_base.c
index ff9540c7..28e6dc47 100644
--- a/lib/utils_base.c
+++ b/lib/utils_base.c
@@ -25,6 +25,7 @@
25 *****************************************************************************/ 25 *****************************************************************************/
26 26
27#include "../plugins/common.h" 27#include "../plugins/common.h"
28#include "states.h"
28#include <stdarg.h> 29#include <stdarg.h>
29#include "utils_base.h" 30#include "utils_base.h"
30#include <ctype.h> 31#include <ctype.h>
@@ -33,20 +34,20 @@
33#include <unistd.h> 34#include <unistd.h>
34#include <sys/types.h> 35#include <sys/types.h>
35 36
36#define np_free(ptr) \ 37#define np_free(ptr) \
37 { \ 38 { \
38 if (ptr) { \ 39 if (ptr) { \
39 free(ptr); \ 40 free(ptr); \
40 ptr = NULL; \ 41 ptr = NULL; \
41 } \ 42 } \
42 } 43 }
43 44
44monitoring_plugin *this_monitoring_plugin = NULL; 45monitoring_plugin *this_monitoring_plugin = NULL;
45 46
46int timeout_state = STATE_CRITICAL; 47mp_state_enum timeout_state = STATE_CRITICAL;
47unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT; 48unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT;
48 49
49bool _np_state_read_file(FILE *); 50bool _np_state_read_file(FILE *state_file);
50 51
51void np_init(char *plugin_name, int argc, char **argv) { 52void np_init(char *plugin_name, int argc, char **argv) {
52 if (this_monitoring_plugin == NULL) { 53 if (this_monitoring_plugin == NULL) {
@@ -74,14 +75,6 @@ void np_set_args(int argc, char **argv) {
74 75
75void np_cleanup(void) { 76void np_cleanup(void) {
76 if (this_monitoring_plugin != NULL) { 77 if (this_monitoring_plugin != NULL) {
77 if (this_monitoring_plugin->state != NULL) {
78 if (this_monitoring_plugin->state->state_data) {
79 np_free(this_monitoring_plugin->state->state_data->data);
80 np_free(this_monitoring_plugin->state->state_data);
81 }
82 np_free(this_monitoring_plugin->state->name);
83 np_free(this_monitoring_plugin->state);
84 }
85 np_free(this_monitoring_plugin->plugin_name); 78 np_free(this_monitoring_plugin->plugin_name);
86 np_free(this_monitoring_plugin); 79 np_free(this_monitoring_plugin);
87 } 80 }
@@ -153,7 +146,8 @@ range *parse_range_string(char *str) {
153 set_range_end(temp_range, end); 146 set_range_end(temp_range, end);
154 } 147 }
155 148
156 if (temp_range->start_infinity == true || temp_range->end_infinity == true || temp_range->start <= temp_range->end) { 149 if (temp_range->start_infinity || temp_range->end_infinity ||
150 temp_range->start <= temp_range->end) {
157 return temp_range; 151 return temp_range;
158 } 152 }
159 free(temp_range); 153 free(temp_range);
@@ -205,12 +199,14 @@ void print_thresholds(const char *threshold_name, thresholds *my_threshold) {
205 printf("Threshold not set"); 199 printf("Threshold not set");
206 } else { 200 } else {
207 if (my_threshold->warning) { 201 if (my_threshold->warning) {
208 printf("Warning: start=%g end=%g; ", my_threshold->warning->start, my_threshold->warning->end); 202 printf("Warning: start=%g end=%g; ", my_threshold->warning->start,
203 my_threshold->warning->end);
209 } else { 204 } else {
210 printf("Warning not set; "); 205 printf("Warning not set; ");
211 } 206 }
212 if (my_threshold->critical) { 207 if (my_threshold->critical) {
213 printf("Critical: start=%g end=%g", my_threshold->critical->start, my_threshold->critical->end); 208 printf("Critical: start=%g end=%g", my_threshold->critical->start,
209 my_threshold->critical->end);
214 } else { 210 } else {
215 printf("Critical not set"); 211 printf("Critical not set");
216 } 212 }
@@ -222,36 +218,26 @@ void print_thresholds(const char *threshold_name, thresholds *my_threshold) {
222bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) { 218bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) {
223 bool is_inside = false; 219 bool is_inside = false;
224 220
225 if (my_range.end_infinity == false && my_range.start_infinity == false) { 221 if (!my_range.end_infinity && !my_range.start_infinity) {
226 // range: .........|---inside---|........... 222 // range: .........|---inside---|...........
227 // value 223 // value
228 if ((cmp_perfdata_value(my_range.start, value) < 1) && (cmp_perfdata_value(value, my_range.end) <= 0)) { 224 is_inside = ((cmp_perfdata_value(value, my_range.start) >= 0) &&
229 is_inside = true; 225 (cmp_perfdata_value(value, my_range.end) <= 0));
230 } else { 226 } else if (!my_range.start_infinity && my_range.end_infinity) {
231 is_inside = false;
232 }
233 } else if (my_range.start_infinity == false && my_range.end_infinity == true) {
234 // range: .........|---inside--------- 227 // range: .........|---inside---------
235 // value 228 // value
236 if (cmp_perfdata_value(my_range.start, value) < 0) { 229 is_inside = (cmp_perfdata_value(value, my_range.start) >= 0);
237 is_inside = true; 230 } else if (my_range.start_infinity && !my_range.end_infinity) {
238 } else {
239 is_inside = false;
240 }
241 } else if (my_range.start_infinity == true && my_range.end_infinity == false) {
242 // range: -inside--------|.................... 231 // range: -inside--------|....................
243 // value 232 // value
244 if (cmp_perfdata_value(value, my_range.end) == -1) { 233 is_inside = (cmp_perfdata_value(value, my_range.end) == -1);
245 is_inside = true;
246 } else {
247 is_inside = false;
248 }
249 } else { 234 } else {
250 // range from -inf to inf, so always inside 235 // range from -inf to inf, so always inside
251 is_inside = true; 236 is_inside = true;
252 } 237 }
253 238
254 if ((is_inside && my_range.alert_on_inside_range == INSIDE) || (!is_inside && my_range.alert_on_inside_range == OUTSIDE)) { 239 if ((is_inside && my_range.alert_on_inside_range == INSIDE) ||
240 (!is_inside && my_range.alert_on_inside_range == OUTSIDE)) {
255 return true; 241 return true;
256 } 242 }
257 243
@@ -268,21 +254,21 @@ bool check_range(double value, range *my_range) {
268 yes = false; 254 yes = false;
269 } 255 }
270 256
271 if (my_range->end_infinity == false && my_range->start_infinity == false) { 257 if (!my_range->end_infinity && !my_range->start_infinity) {
272 if ((my_range->start <= value) && (value <= my_range->end)) { 258 if ((my_range->start <= value) && (value <= my_range->end)) {
273 return no; 259 return no;
274 } 260 }
275 return yes; 261 return yes;
276 } 262 }
277 263
278 if (my_range->start_infinity == false && my_range->end_infinity == true) { 264 if (!my_range->start_infinity && my_range->end_infinity) {
279 if (my_range->start <= value) { 265 if (my_range->start <= value) {
280 return no; 266 return no;
281 } 267 }
282 return yes; 268 return yes;
283 } 269 }
284 270
285 if (my_range->start_infinity == true && my_range->end_infinity == false) { 271 if (my_range->start_infinity && !my_range->end_infinity) {
286 if (value <= my_range->end) { 272 if (value <= my_range->end) {
287 return no; 273 return no;
288 } 274 }
@@ -292,14 +278,14 @@ bool check_range(double value, range *my_range) {
292} 278}
293 279
294/* Returns status */ 280/* Returns status */
295int get_status(double value, thresholds *my_thresholds) { 281mp_state_enum get_status(double value, thresholds *my_thresholds) {
296 if (my_thresholds->critical != NULL) { 282 if (my_thresholds->critical != NULL) {
297 if (check_range(value, my_thresholds->critical) == true) { 283 if (check_range(value, my_thresholds->critical)) {
298 return STATE_CRITICAL; 284 return STATE_CRITICAL;
299 } 285 }
300 } 286 }
301 if (my_thresholds->warning != NULL) { 287 if (my_thresholds->warning != NULL) {
302 if (check_range(value, my_thresholds->warning) == true) { 288 if (check_range(value, my_thresholds->warning)) {
303 return STATE_WARNING; 289 return STATE_WARNING;
304 } 290 }
305 } 291 }
@@ -308,32 +294,31 @@ int get_status(double value, thresholds *my_thresholds) {
308 294
309char *np_escaped_string(const char *string) { 295char *np_escaped_string(const char *string) {
310 char *data; 296 char *data;
311 int i; 297 int write_index = 0;
312 int j = 0;
313 data = strdup(string); 298 data = strdup(string);
314 for (i = 0; data[i]; i++) { 299 for (int i = 0; data[i]; i++) {
315 if (data[i] == '\\') { 300 if (data[i] == '\\') {
316 switch (data[++i]) { 301 switch (data[++i]) {
317 case 'n': 302 case 'n':
318 data[j++] = '\n'; 303 data[write_index++] = '\n';
319 break; 304 break;
320 case 'r': 305 case 'r':
321 data[j++] = '\r'; 306 data[write_index++] = '\r';
322 break; 307 break;
323 case 't': 308 case 't':
324 data[j++] = '\t'; 309 data[write_index++] = '\t';
325 break; 310 break;
326 case '\\': 311 case '\\':
327 data[j++] = '\\'; 312 data[write_index++] = '\\';
328 break; 313 break;
329 default: 314 default:
330 data[j++] = data[i]; 315 data[write_index++] = data[i];
331 } 316 }
332 } else { 317 } else {
333 data[j++] = data[i]; 318 data[write_index++] = data[i];
334 } 319 }
335 } 320 }
336 data[j] = '\0'; 321 data[write_index] = '\0';
337 return data; 322 return data;
338} 323}
339 324
@@ -348,33 +333,35 @@ int np_check_if_root(void) { return (geteuid() == 0); }
348char *np_extract_value(const char *varlist, const char *name, char sep) { 333char *np_extract_value(const char *varlist, const char *name, char sep) {
349 char *tmp = NULL; 334 char *tmp = NULL;
350 char *value = NULL; 335 char *value = NULL;
351 int i;
352 336
353 while (1) { 337 while (true) {
354 /* Strip any leading space */ 338 /* Strip any leading space */
355 for (; isspace(varlist[0]); varlist++) 339 for (; isspace(varlist[0]); varlist++) {
356 ; 340 ;
341 }
357 342
358 if (strncmp(name, varlist, strlen(name)) == 0) { 343 if (strncmp(name, varlist, strlen(name)) == 0) {
359 varlist += strlen(name); 344 varlist += strlen(name);
360 /* strip trailing spaces */ 345 /* strip trailing spaces */
361 for (; isspace(varlist[0]); varlist++) 346 for (; isspace(varlist[0]); varlist++) {
362 ; 347 ;
348 }
363 349
364 if (varlist[0] == '=') { 350 if (varlist[0] == '=') {
365 /* We matched the key, go past the = sign */ 351 /* We matched the key, go past the = sign */
366 varlist++; 352 varlist++;
367 /* strip leading spaces */ 353 /* strip leading spaces */
368 for (; isspace(varlist[0]); varlist++) 354 for (; isspace(varlist[0]); varlist++) {
369 ; 355 ;
356 }
370 357
371 if ((tmp = index(varlist, sep))) { 358 if ((tmp = index(varlist, sep))) {
372 /* Value is delimited by a comma */ 359 /* Value is delimited by a comma */
373 if (tmp - varlist == 0) { 360 if (tmp - varlist == 0) {
374 continue; 361 continue;
375 } 362 }
376 value = (char *)calloc(1, tmp - varlist + 1); 363 value = (char *)calloc(1, (unsigned long)(tmp - varlist + 1));
377 strncpy(value, varlist, tmp - varlist); 364 strncpy(value, varlist, (unsigned long)(tmp - varlist));
378 value[tmp - varlist] = '\0'; 365 value[tmp - varlist] = '\0';
379 } else { 366 } else {
380 /* Value is delimited by a \0 */ 367 /* Value is delimited by a \0 */
@@ -399,7 +386,7 @@ char *np_extract_value(const char *varlist, const char *name, char sep) {
399 386
400 /* Clean-up trailing spaces/newlines */ 387 /* Clean-up trailing spaces/newlines */
401 if (value) { 388 if (value) {
402 for (i = strlen(value) - 1; isspace(value[i]); i--) { 389 for (unsigned long i = strlen(value) - 1; isspace(value[i]); i--) {
403 value[i] = '\0'; 390 value[i] = '\0';
404 } 391 }
405 } 392 }
@@ -407,7 +394,7 @@ char *np_extract_value(const char *varlist, const char *name, char sep) {
407 return value; 394 return value;
408} 395}
409 396
410const char *state_text(int result) { 397const char *state_text(mp_state_enum result) {
411 switch (result) { 398 switch (result) {
412 case STATE_OK: 399 case STATE_OK:
413 return "OK"; 400 return "OK";
@@ -441,349 +428,3 @@ int mp_translate_state(char *state_text) {
441 } 428 }
442 return ERROR; 429 return ERROR;
443} 430}
444
445/*
446 * Returns a string to use as a keyname, based on an md5 hash of argv, thus
447 * hopefully a unique key per service/plugin invocation. Use the extra-opts
448 * parse of argv, so that uniqueness in parameters are reflected there.
449 */
450char *_np_state_generate_key(void) {
451 int i;
452 char **argv = this_monitoring_plugin->argv;
453 char keyname[41];
454 char *p = NULL;
455
456 unsigned char result[256];
457
458#ifdef USE_OPENSSL
459 /*
460 * This code path is chosen if openssl is available (which should be the most common
461 * scenario). Alternatively, the gnulib implementation/
462 *
463 */
464 EVP_MD_CTX *ctx = EVP_MD_CTX_new();
465
466 EVP_DigestInit(ctx, EVP_sha256());
467
468 for (i = 0; i < this_monitoring_plugin->argc; i++) {
469 EVP_DigestUpdate(ctx, argv[i], strlen(argv[i]));
470 }
471
472 EVP_DigestFinal(ctx, result, NULL);
473#else
474
475 struct sha256_ctx ctx;
476
477 for (i = 0; i < this_monitoring_plugin->argc; i++) {
478 sha256_process_bytes(argv[i], strlen(argv[i]), &ctx);
479 }
480
481 sha256_finish_ctx(&ctx, result);
482#endif // FOUNDOPENSSL
483
484 for (i = 0; i < 20; ++i) {
485 sprintf(&keyname[2 * i], "%02x", result[i]);
486 }
487
488 keyname[40] = '\0';
489
490 p = strdup(keyname);
491 if (p == NULL) {
492 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
493 }
494 return p;
495}
496
497void _cleanup_state_data(void) {
498 if (this_monitoring_plugin->state->state_data != NULL) {
499 np_free(this_monitoring_plugin->state->state_data->data);
500 np_free(this_monitoring_plugin->state->state_data);
501 }
502}
503
504/*
505 * Internal function. Returns either:
506 * envvar NAGIOS_PLUGIN_STATE_DIRECTORY
507 * statically compiled shared state directory
508 */
509char *_np_state_calculate_location_prefix(void) {
510 char *env_dir;
511
512 /* Do not allow passing MP_STATE_PATH in setuid plugins
513 * for security reasons */
514 if (!mp_suid()) {
515 env_dir = getenv("MP_STATE_PATH");
516 if (env_dir && env_dir[0] != '\0') {
517 return env_dir;
518 }
519 /* This is the former ENV, for backward-compatibility */
520 env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY");
521 if (env_dir && env_dir[0] != '\0') {
522 return env_dir;
523 }
524 }
525
526 return NP_STATE_DIR_PREFIX;
527}
528
529/*
530 * Initiatializer for state routines.
531 * Sets variables. Generates filename. Returns np_state_key. die with
532 * UNKNOWN if exception
533 */
534void np_enable_state(char *keyname, int expected_data_version) {
535 state_key *this_state = NULL;
536 char *temp_filename = NULL;
537 char *temp_keyname = NULL;
538 char *p = NULL;
539 int ret;
540
541 if (this_monitoring_plugin == NULL) {
542 die(STATE_UNKNOWN, _("This requires np_init to be called"));
543 }
544
545 this_state = (state_key *)calloc(1, sizeof(state_key));
546 if (this_state == NULL) {
547 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
548 }
549
550 if (keyname == NULL) {
551 temp_keyname = _np_state_generate_key();
552 } else {
553 temp_keyname = strdup(keyname);
554 if (temp_keyname == NULL) {
555 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
556 }
557 }
558 /* Die if invalid characters used for keyname */
559 p = temp_keyname;
560 while (*p != '\0') {
561 if (!(isalnum(*p) || *p == '_')) {
562 die(STATE_UNKNOWN, _("Invalid character for keyname - only alphanumerics or '_'"));
563 }
564 p++;
565 }
566 this_state->name = temp_keyname;
567 this_state->plugin_name = this_monitoring_plugin->plugin_name;
568 this_state->data_version = expected_data_version;
569 this_state->state_data = NULL;
570
571 /* Calculate filename */
572 ret = asprintf(&temp_filename, "%s/%lu/%s/%s", _np_state_calculate_location_prefix(), (unsigned long)geteuid(),
573 this_monitoring_plugin->plugin_name, this_state->name);
574 if (ret < 0) {
575 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
576 }
577
578 this_state->_filename = temp_filename;
579
580 this_monitoring_plugin->state = this_state;
581}
582
583/*
584 * Will return NULL if no data is available (first run). If key currently
585 * exists, read data. If state file format version is not expected, return
586 * as if no data. Get state data version number and compares to expected.
587 * If numerically lower, then return as no previous state. die with UNKNOWN
588 * if exceptional error.
589 */
590state_data *np_state_read(void) {
591 state_data *this_state_data = NULL;
592 FILE *statefile;
593 bool rc = false;
594
595 if (this_monitoring_plugin == NULL) {
596 die(STATE_UNKNOWN, _("This requires np_init to be called"));
597 }
598
599 /* Open file. If this fails, no previous state found */
600 statefile = fopen(this_monitoring_plugin->state->_filename, "r");
601 if (statefile != NULL) {
602
603 this_state_data = (state_data *)calloc(1, sizeof(state_data));
604 if (this_state_data == NULL) {
605 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
606 }
607
608 this_state_data->data = NULL;
609 this_monitoring_plugin->state->state_data = this_state_data;
610
611 rc = _np_state_read_file(statefile);
612
613 fclose(statefile);
614 }
615
616 if (!rc) {
617 _cleanup_state_data();
618 }
619
620 return this_monitoring_plugin->state->state_data;
621}
622
623/*
624 * Read the state file
625 */
626bool _np_state_read_file(FILE *f) {
627 bool status = false;
628 size_t pos;
629 char *line;
630 int i;
631 int failure = 0;
632 time_t current_time, data_time;
633 enum {
634 STATE_FILE_VERSION,
635 STATE_DATA_VERSION,
636 STATE_DATA_TIME,
637 STATE_DATA_TEXT,
638 STATE_DATA_END
639 } expected = STATE_FILE_VERSION;
640
641 time(&current_time);
642
643 /* Note: This introduces a limit of 1024 bytes in the string data */
644 line = (char *)calloc(1, 1024);
645 if (line == NULL) {
646 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
647 }
648
649 while (!failure && (fgets(line, 1024, f)) != NULL) {
650 pos = strlen(line);
651 if (line[pos - 1] == '\n') {
652 line[pos - 1] = '\0';
653 }
654
655 if (line[0] == '#') {
656 continue;
657 }
658
659 switch (expected) {
660 case STATE_FILE_VERSION:
661 i = atoi(line);
662 if (i != NP_STATE_FORMAT_VERSION) {
663 failure++;
664 } else {
665 expected = STATE_DATA_VERSION;
666 }
667 break;
668 case STATE_DATA_VERSION:
669 i = atoi(line);
670 if (i != this_monitoring_plugin->state->data_version) {
671 failure++;
672 } else {
673 expected = STATE_DATA_TIME;
674 }
675 break;
676 case STATE_DATA_TIME:
677 /* If time > now, error */
678 data_time = strtoul(line, NULL, 10);
679 if (data_time > current_time) {
680 failure++;
681 } else {
682 this_monitoring_plugin->state->state_data->time = data_time;
683 expected = STATE_DATA_TEXT;
684 }
685 break;
686 case STATE_DATA_TEXT:
687 this_monitoring_plugin->state->state_data->data = strdup(line);
688 if (this_monitoring_plugin->state->state_data->data == NULL) {
689 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
690 }
691 expected = STATE_DATA_END;
692 status = true;
693 break;
694 case STATE_DATA_END:;
695 }
696 }
697
698 np_free(line);
699 return status;
700}
701
702/*
703 * If time=NULL, use current time. Create state file, with state format
704 * version, default text. Writes version, time, and data. Avoid locking
705 * problems - use mv to write and then swap. Possible loss of state data if
706 * two things writing to same key at same time.
707 * Will die with UNKNOWN if errors
708 */
709void np_state_write_string(time_t data_time, char *data_string) {
710 FILE *fp;
711 char *temp_file = NULL;
712 int fd = 0, result = 0;
713 time_t current_time;
714 char *directories = NULL;
715 char *p = NULL;
716
717 if (data_time == 0) {
718 time(&current_time);
719 } else {
720 current_time = data_time;
721 }
722
723 /* If file doesn't currently exist, create directories */
724 if (access(this_monitoring_plugin->state->_filename, F_OK) != 0) {
725 result = asprintf(&directories, "%s", this_monitoring_plugin->state->_filename);
726 if (result < 0) {
727 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
728 }
729
730 for (p = directories + 1; *p; p++) {
731 if (*p == '/') {
732 *p = '\0';
733 if ((access(directories, F_OK) != 0) && (mkdir(directories, S_IRWXU) != 0)) {
734 /* Can't free this! Otherwise error message is wrong! */
735 /* np_free(directories); */
736 die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories);
737 }
738 *p = '/';
739 }
740 }
741 np_free(directories);
742 }
743
744 result = asprintf(&temp_file, "%s.XXXXXX", this_monitoring_plugin->state->_filename);
745 if (result < 0) {
746 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
747 }
748
749 if ((fd = mkstemp(temp_file)) == -1) {
750 np_free(temp_file);
751 die(STATE_UNKNOWN, _("Cannot create temporary filename"));
752 }
753
754 fp = (FILE *)fdopen(fd, "w");
755 if (fp == NULL) {
756 close(fd);
757 unlink(temp_file);
758 np_free(temp_file);
759 die(STATE_UNKNOWN, _("Unable to open temporary state file"));
760 }
761
762 fprintf(fp, "# NP State file\n");
763 fprintf(fp, "%d\n", NP_STATE_FORMAT_VERSION);
764 fprintf(fp, "%d\n", this_monitoring_plugin->state->data_version);
765 fprintf(fp, "%lu\n", current_time);
766 fprintf(fp, "%s\n", data_string);
767
768 fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP);
769
770 fflush(fp);
771
772 result = fclose(fp);
773
774 fsync(fd);
775
776 if (result != 0) {
777 unlink(temp_file);
778 np_free(temp_file);
779 die(STATE_UNKNOWN, _("Error writing temp file"));
780 }
781
782 if (rename(temp_file, this_monitoring_plugin->state->_filename) != 0) {
783 unlink(temp_file);
784 np_free(temp_file);
785 die(STATE_UNKNOWN, _("Cannot rename state temp file"));
786 }
787
788 np_free(temp_file);
789}
diff --git a/lib/utils_base.h b/lib/utils_base.h
index 123066f8..27884bf0 100644
--- a/lib/utils_base.h
+++ b/lib/utils_base.h
@@ -7,7 +7,7 @@
7 7
8#include "./perfdata.h" 8#include "./perfdata.h"
9#include "./thresholds.h" 9#include "./thresholds.h"
10 10#include "states.h"
11 11
12#ifndef USE_OPENSSL 12#ifndef USE_OPENSSL
13# include "sha256.h" 13# include "sha256.h"
@@ -26,25 +26,8 @@
26#define OUTSIDE 0 26#define OUTSIDE 0
27#define INSIDE 1 27#define INSIDE 1
28 28
29#define NP_STATE_FORMAT_VERSION 1
30
31typedef struct state_data_struct {
32 time_t time;
33 void *data;
34 int length; /* Of binary data */
35} state_data;
36
37typedef struct state_key_struct {
38 char *name;
39 char *plugin_name;
40 int data_version;
41 char *_filename;
42 state_data *state_data;
43} state_key;
44
45typedef struct np_struct { 29typedef struct np_struct {
46 char *plugin_name; 30 char *plugin_name;
47 state_key *state;
48 int argc; 31 int argc;
49 char **argv; 32 char **argv;
50} monitoring_plugin; 33} monitoring_plugin;
@@ -55,10 +38,10 @@ void set_thresholds(thresholds **, char *, char *);
55void print_thresholds(const char *, thresholds *); 38void print_thresholds(const char *, thresholds *);
56bool check_range(double, range *); 39bool check_range(double, range *);
57bool mp_check_range(mp_perfdata_value, mp_range); 40bool mp_check_range(mp_perfdata_value, mp_range);
58int get_status(double, thresholds *); 41mp_state_enum get_status(double, thresholds *);
59 42
60/* Handle timeouts */ 43/* Handle timeouts */
61extern int timeout_state; 44extern mp_state_enum timeout_state;
62extern unsigned int timeout_interval; 45extern unsigned int timeout_interval;
63 46
64/* All possible characters in a threshold range */ 47/* All possible characters in a threshold range */
@@ -100,13 +83,9 @@ char *np_extract_value(const char *, const char *, char);
100 */ 83 */
101int mp_translate_state(char *); 84int mp_translate_state(char *);
102 85
103void np_enable_state(char *, int);
104state_data *np_state_read(void);
105void np_state_write_string(time_t, char *);
106
107void np_init(char *, int argc, char **argv); 86void np_init(char *, int argc, char **argv);
108void np_set_args(int argc, char **argv); 87void np_set_args(int argc, char **argv);
109void np_cleanup(void); 88void np_cleanup(void);
110const char *state_text(int); 89const char *state_text(mp_state_enum);
111 90
112#endif /* _UTILS_BASE_ */ 91#endif /* _UTILS_BASE_ */
diff --git a/lib/utils_cmd.c b/lib/utils_cmd.c
index 18350ac0..23d42168 100644
--- a/lib/utils_cmd.c
+++ b/lib/utils_cmd.c
@@ -40,7 +40,6 @@
40 40
41/** includes **/ 41/** includes **/
42#include "common.h" 42#include "common.h"
43#include "utils.h"
44#include "utils_cmd.h" 43#include "utils_cmd.h"
45/* This variable must be global, since there's no way the caller 44/* This variable must be global, since there's no way the caller
46 * can forcibly slay a dead or ungainly running program otherwise. 45 * can forcibly slay a dead or ungainly running program otherwise.
@@ -57,21 +56,19 @@ static pid_t *_cmd_pids = NULL;
57#include "./maxfd.h" 56#include "./maxfd.h"
58 57
59#include <fcntl.h> 58#include <fcntl.h>
59#include <stddef.h>
60 60
61#ifdef HAVE_SYS_WAIT_H 61#ifdef HAVE_SYS_WAIT_H
62# include <sys/wait.h> 62# include <sys/wait.h>
63#endif 63#endif
64 64
65/* used in _cmd_open to pass the environment to commands */
66extern char **environ;
67
68/** macros **/ 65/** macros **/
69#ifndef WEXITSTATUS 66#ifndef WEXITSTATUS
70# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) 67# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
71#endif 68#endif
72 69
73#ifndef WIFEXITED 70#ifndef WIFEXITED
74# define WIFEXITED(stat_val) (((stat_val)&255) == 0) 71# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
75#endif 72#endif
76 73
77/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */ 74/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */
@@ -80,14 +77,13 @@ extern char **environ;
80#endif 77#endif
81 78
82/** prototypes **/ 79/** prototypes **/
83static int _cmd_open(char *const *, int *, int *) __attribute__((__nonnull__(1, 2, 3))); 80static int _cmd_open(char *const *argv, int *pfd, int *pfderr)
84 81 __attribute__((__nonnull__(1, 2, 3)));
85static int _cmd_fetch_output(int, output *, int) __attribute__((__nonnull__(2)));
86 82
87static int _cmd_close(int); 83static int _cmd_fetch_output(int fileDescriptor, output *cmd_output, int flags)
84 __attribute__((__nonnull__(2)));
88 85
89/* prototype imported from utils.h */ 86static int _cmd_close(int fileDescriptor);
90extern void die(int, const char *, ...) __attribute__((__noreturn__, __format__(__printf__, 2, 3)));
91 87
92/* this function is NOT async-safe. It is exported so multithreaded 88/* this function is NOT async-safe. It is exported so multithreaded
93 * plugins (or other apps) can call it prior to running any commands 89 * plugins (or other apps) can call it prior to running any commands
@@ -103,26 +99,100 @@ void cmd_init(void) {
103 maxfd = MAXFD_LIMIT; 99 maxfd = MAXFD_LIMIT;
104 } 100 }
105 101
106 if (!_cmd_pids) 102 if (!_cmd_pids) {
107 _cmd_pids = calloc(maxfd, sizeof(pid_t)); 103 _cmd_pids = calloc(maxfd, sizeof(pid_t));
104 }
105}
106
107typedef struct {
108 int stdout_pipe_fd[2];
109 int stderr_pipe_fd[2];
110 int file_descriptor;
111 int error_code;
112} int_cmd_open_result;
113static int_cmd_open_result _cmd_open2(char *const *argv) {
114#ifdef RLIMIT_CORE
115 struct rlimit limit;
116#endif
117
118 if (!_cmd_pids) {
119 CMD_INIT;
120 }
121
122 setenv("LC_ALL", "C", 1);
123
124 int_cmd_open_result result = {
125 .error_code = 0,
126 .stdout_pipe_fd = {0, 0},
127 .stderr_pipe_fd = {0, 0},
128 };
129 pid_t pid;
130 if (pipe(result.stdout_pipe_fd) < 0 || pipe(result.stderr_pipe_fd) < 0 || (pid = fork()) < 0) {
131 result.error_code = -1;
132 return result; /* errno set by the failing function */
133 }
134
135 /* child runs exceve() and _exit. */
136 if (pid == 0) {
137#ifdef RLIMIT_CORE
138 /* the program we execve shouldn't leave core files */
139 getrlimit(RLIMIT_CORE, &limit);
140 limit.rlim_cur = 0;
141 setrlimit(RLIMIT_CORE, &limit);
142#endif
143 close(result.stdout_pipe_fd[0]);
144 if (result.stdout_pipe_fd[1] != STDOUT_FILENO) {
145 dup2(result.stdout_pipe_fd[1], STDOUT_FILENO);
146 close(result.stdout_pipe_fd[1]);
147 }
148 close(result.stderr_pipe_fd[0]);
149 if (result.stderr_pipe_fd[1] != STDERR_FILENO) {
150 dup2(result.stderr_pipe_fd[1], STDERR_FILENO);
151 close(result.stderr_pipe_fd[1]);
152 }
153
154 /* close all descriptors in _cmd_pids[]
155 * This is executed in a separate address space (pure child),
156 * so we don't have to worry about async safety */
157 long maxfd = mp_open_max();
158 for (int i = 0; i < maxfd; i++) {
159 if (_cmd_pids[i] > 0) {
160 close(i);
161 }
162 }
163
164 execve(argv[0], argv, environ);
165 _exit(STATE_UNKNOWN);
166 }
167
168 /* parent picks up execution here */
169 /* close children descriptors in our address space */
170 close(result.stdout_pipe_fd[1]);
171 close(result.stderr_pipe_fd[1]);
172
173 /* tag our file's entry in the pid-list and return it */
174 _cmd_pids[result.stdout_pipe_fd[0]] = pid;
175
176 result.file_descriptor = result.stdout_pipe_fd[0];
177 return result;
108} 178}
109 179
110/* Start running a command, array style */ 180/* Start running a command, array style */
111static int _cmd_open(char *const *argv, int *pfd, int *pfderr) { 181static int _cmd_open(char *const *argv, int *pfd, int *pfderr) {
112 pid_t pid;
113#ifdef RLIMIT_CORE 182#ifdef RLIMIT_CORE
114 struct rlimit limit; 183 struct rlimit limit;
115#endif 184#endif
116 185
117 int i = 0; 186 if (!_cmd_pids) {
118
119 if (!_cmd_pids)
120 CMD_INIT; 187 CMD_INIT;
188 }
121 189
122 setenv("LC_ALL", "C", 1); 190 setenv("LC_ALL", "C", 1);
123 191
124 if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0) 192 pid_t pid;
193 if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0) {
125 return -1; /* errno set by the failing function */ 194 return -1; /* errno set by the failing function */
195 }
126 196
127 /* child runs exceve() and _exit. */ 197 /* child runs exceve() and _exit. */
128 if (pid == 0) { 198 if (pid == 0) {
@@ -147,9 +217,11 @@ static int _cmd_open(char *const *argv, int *pfd, int *pfderr) {
147 * This is executed in a separate address space (pure child), 217 * This is executed in a separate address space (pure child),
148 * so we don't have to worry about async safety */ 218 * so we don't have to worry about async safety */
149 long maxfd = mp_open_max(); 219 long maxfd = mp_open_max();
150 for (i = 0; i < maxfd; i++) 220 for (int i = 0; i < maxfd; i++) {
151 if (_cmd_pids[i] > 0) 221 if (_cmd_pids[i] > 0) {
152 close(i); 222 close(i);
223 }
224 }
153 225
154 execve(argv[0], argv, environ); 226 execve(argv[0], argv, environ);
155 _exit(STATE_UNKNOWN); 227 _exit(STATE_UNKNOWN);
@@ -166,88 +238,171 @@ static int _cmd_open(char *const *argv, int *pfd, int *pfderr) {
166 return pfd[0]; 238 return pfd[0];
167} 239}
168 240
169static int _cmd_close(int fd) { 241static int _cmd_close(int fileDescriptor) {
170 int status;
171 pid_t pid; 242 pid_t pid;
172 243
173 /* make sure the provided fd was opened */ 244 /* make sure the provided fd was opened */
174 long maxfd = mp_open_max(); 245 long maxfd = mp_open_max();
175 if (fd < 0 || fd > maxfd || !_cmd_pids || (pid = _cmd_pids[fd]) == 0) 246 if (fileDescriptor < 0 || fileDescriptor > maxfd || !_cmd_pids ||
247 (pid = _cmd_pids[fileDescriptor]) == 0) {
176 return -1; 248 return -1;
249 }
177 250
178 _cmd_pids[fd] = 0; 251 _cmd_pids[fileDescriptor] = 0;
179 if (close(fd) == -1) 252 if (close(fileDescriptor) == -1) {
180 return -1; 253 return -1;
254 }
181 255
182 /* EINTR is ok (sort of), everything else is bad */ 256 /* EINTR is ok (sort of), everything else is bad */
183 while (waitpid(pid, &status, 0) < 0) 257 int status;
184 if (errno != EINTR) 258 while (waitpid(pid, &status, 0) < 0) {
259 if (errno != EINTR) {
185 return -1; 260 return -1;
261 }
262 }
186 263
187 /* return child's termination status */ 264 /* return child's termination status */
188 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1; 265 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1;
189} 266}
190 267
191static int _cmd_fetch_output(int fd, output *op, int flags) { 268typedef struct {
192 size_t len = 0, i = 0, lineno = 0; 269 int error_code;
193 size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */ 270 output output_container;
194 char *buf = NULL; 271} int_cmd_fetch_output2;
195 int ret; 272static int_cmd_fetch_output2 _cmd_fetch_output2(int fileDescriptor, int flags) {
196 char tmpbuf[4096]; 273 char tmpbuf[4096];
197 274
198 op->buf = NULL; 275 int_cmd_fetch_output2 result = {
199 op->buflen = 0; 276 .error_code = 0,
200 while ((ret = read(fd, tmpbuf, sizeof(tmpbuf))) > 0) { 277 .output_container =
201 len = (size_t)ret; 278 {
202 op->buf = realloc(op->buf, op->buflen + len + 1); 279 .buf = NULL,
203 memcpy(op->buf + op->buflen, tmpbuf, len); 280 .buflen = 0,
204 op->buflen += len; 281 .line = NULL,
282 .lines = 0,
283 },
284 };
285 ssize_t ret;
286 while ((ret = read(fileDescriptor, tmpbuf, sizeof(tmpbuf))) > 0) {
287 size_t len = (size_t)ret;
288 result.output_container.buf =
289 realloc(result.output_container.buf, result.output_container.buflen + len + 1);
290 memcpy(result.output_container.buf + result.output_container.buflen, tmpbuf, len);
291 result.output_container.buflen += len;
292 }
293
294 if (ret < 0) {
295 printf("read() returned %zd: %s\n", ret, strerror(errno));
296 result.error_code = -1;
297 return result;
298 }
299
300 /* some plugins may want to keep output unbroken, and some commands
301 * will yield no output, so return here for those */
302 if (flags & CMD_NO_ARRAYS || !result.output_container.buf || !result.output_container.buflen) {
303 return result;
304 }
305
306 /* and some may want both */
307 char *buf = NULL;
308 if (flags & CMD_NO_ASSOC) {
309 buf = malloc(result.output_container.buflen);
310 memcpy(buf, result.output_container.buf, result.output_container.buflen);
311 } else {
312 buf = result.output_container.buf;
313 }
314
315 result.output_container.line = NULL;
316 size_t ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */
317 size_t rsf = 6;
318 size_t lineno = 0;
319 for (size_t i = 0; i < result.output_container.buflen;) {
320 /* make sure we have enough memory */
321 if (lineno >= ary_size) {
322 /* ary_size must never be zero */
323 do {
324 ary_size = result.output_container.buflen >> --rsf;
325 } while (!ary_size);
326
327 result.output_container.line =
328 realloc(result.output_container.line, ary_size * sizeof(char *));
329 }
330
331 /* set the pointer to the string */
332 result.output_container.line[lineno] = &buf[i];
333
334 /* hop to next newline or end of buffer */
335 while (buf[i] != '\n' && i < result.output_container.buflen) {
336 i++;
337 }
338 buf[i] = '\0';
339
340 lineno++;
205 i++; 341 i++;
206 } 342 }
207 343
344 result.output_container.lines = lineno;
345
346 return result;
347}
348
349static int _cmd_fetch_output(int fileDescriptor, output *cmd_output, int flags) {
350 char tmpbuf[4096];
351 cmd_output->buf = NULL;
352 cmd_output->buflen = 0;
353 ssize_t ret;
354 while ((ret = read(fileDescriptor, tmpbuf, sizeof(tmpbuf))) > 0) {
355 size_t len = (size_t)ret;
356 cmd_output->buf = realloc(cmd_output->buf, cmd_output->buflen + len + 1);
357 memcpy(cmd_output->buf + cmd_output->buflen, tmpbuf, len);
358 cmd_output->buflen += len;
359 }
360
208 if (ret < 0) { 361 if (ret < 0) {
209 printf("read() returned %d: %s\n", ret, strerror(errno)); 362 printf("read() returned %zd: %s\n", ret, strerror(errno));
210 return ret; 363 return ret;
211 } 364 }
212 365
213 /* some plugins may want to keep output unbroken, and some commands 366 /* some plugins may want to keep output unbroken, and some commands
214 * will yield no output, so return here for those */ 367 * will yield no output, so return here for those */
215 if (flags & CMD_NO_ARRAYS || !op->buf || !op->buflen) 368 if (flags & CMD_NO_ARRAYS || !cmd_output->buf || !cmd_output->buflen) {
216 return op->buflen; 369 return cmd_output->buflen;
370 }
217 371
218 /* and some may want both */ 372 /* and some may want both */
373 char *buf = NULL;
219 if (flags & CMD_NO_ASSOC) { 374 if (flags & CMD_NO_ASSOC) {
220 buf = malloc(op->buflen); 375 buf = malloc(cmd_output->buflen);
221 memcpy(buf, op->buf, op->buflen); 376 memcpy(buf, cmd_output->buf, cmd_output->buflen);
222 } else 377 } else {
223 buf = op->buf; 378 buf = cmd_output->buf;
224 379 }
225 op->line = NULL; 380
226 op->lens = NULL; 381 cmd_output->line = NULL;
227 i = 0; 382 size_t i = 0;
228 while (i < op->buflen) { 383 size_t ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */
384 size_t rsf = 6;
385 size_t lineno = 0;
386 while (i < cmd_output->buflen) {
229 /* make sure we have enough memory */ 387 /* make sure we have enough memory */
230 if (lineno >= ary_size) { 388 if (lineno >= ary_size) {
231 /* ary_size must never be zero */ 389 /* ary_size must never be zero */
232 do { 390 do {
233 ary_size = op->buflen >> --rsf; 391 ary_size = cmd_output->buflen >> --rsf;
234 } while (!ary_size); 392 } while (!ary_size);
235 393
236 op->line = realloc(op->line, ary_size * sizeof(char *)); 394 cmd_output->line = realloc(cmd_output->line, ary_size * sizeof(char *));
237 op->lens = realloc(op->lens, ary_size * sizeof(size_t));
238 } 395 }
239 396
240 /* set the pointer to the string */ 397 /* set the pointer to the string */
241 op->line[lineno] = &buf[i]; 398 cmd_output->line[lineno] = &buf[i];
242 399
243 /* hop to next newline or end of buffer */ 400 /* hop to next newline or end of buffer */
244 while (buf[i] != '\n' && i < op->buflen) 401 while (buf[i] != '\n' && i < cmd_output->buflen) {
245 i++; 402 i++;
403 }
246 buf[i] = '\0'; 404 buf[i] = '\0';
247 405
248 /* calculate the string length using pointer difference */
249 op->lens[lineno] = (size_t)&buf[i] - (size_t)op->line[lineno];
250
251 lineno++; 406 lineno++;
252 i++; 407 i++;
253 } 408 }
@@ -256,41 +411,42 @@ static int _cmd_fetch_output(int fd, output *op, int flags) {
256} 411}
257 412
258int cmd_run(const char *cmdstring, output *out, output *err, int flags) { 413int cmd_run(const char *cmdstring, output *out, output *err, int flags) {
259 int i = 0, argc; 414 if (cmdstring == NULL) {
260 size_t cmdlen;
261 char **argv = NULL;
262 char *cmd = NULL;
263 char *str = NULL;
264
265 if (cmdstring == NULL)
266 return -1; 415 return -1;
416 }
267 417
268 /* initialize the structs */ 418 /* initialize the structs */
269 if (out) 419 if (out) {
270 memset(out, 0, sizeof(output)); 420 memset(out, 0, sizeof(output));
271 if (err) 421 }
422 if (err) {
272 memset(err, 0, sizeof(output)); 423 memset(err, 0, sizeof(output));
424 }
273 425
274 /* make copy of command string so strtok() doesn't silently modify it */ 426 /* make copy of command string so strtok() doesn't silently modify it */
275 /* (the calling program may want to access it later) */ 427 /* (the calling program may want to access it later) */
276 cmdlen = strlen(cmdstring); 428 size_t cmdlen = strlen(cmdstring);
277 if ((cmd = malloc(cmdlen + 1)) == NULL) 429 char *cmd = NULL;
430 if ((cmd = malloc(cmdlen + 1)) == NULL) {
278 return -1; 431 return -1;
432 }
279 memcpy(cmd, cmdstring, cmdlen); 433 memcpy(cmd, cmdstring, cmdlen);
280 cmd[cmdlen] = '\0'; 434 cmd[cmdlen] = '\0';
281 435
282 /* This is not a shell, so we don't handle "???" */ 436 /* This is not a shell, so we don't handle "???" */
283 if (strstr(cmdstring, "\"")) 437 if (strstr(cmdstring, "\"")) {
284 return -1; 438 return -1;
439 }
285 440
286 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ 441 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
287 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''")) 442 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''")) {
288 return -1; 443 return -1;
444 }
289 445
290 /* each arg must be whitespace-separated, so args can be a maximum 446 /* each arg must be whitespace-separated, so args can be a maximum
291 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */ 447 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */
292 argc = (cmdlen >> 1) + 2; 448 int argc = (cmdlen >> 1) + 2;
293 argv = calloc((size_t)argc, sizeof(char *)); 449 char **argv = calloc((size_t)argc, sizeof(char *));
294 450
295 if (argv == NULL) { 451 if (argv == NULL) {
296 printf("%s\n", _("Could not malloc argv array in popen()")); 452 printf("%s\n", _("Could not malloc argv array in popen()"));
@@ -298,14 +454,16 @@ int cmd_run(const char *cmdstring, output *out, output *err, int flags) {
298 } 454 }
299 455
300 /* get command arguments (stupidly, but fairly quickly) */ 456 /* get command arguments (stupidly, but fairly quickly) */
457 int i = 0;
301 while (cmd) { 458 while (cmd) {
302 str = cmd; 459 char *str = cmd;
303 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */ 460 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
304 461
305 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */ 462 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */
306 str++; 463 str++;
307 if (!strstr(str, "'")) 464 if (!strstr(str, "'")) {
308 return -1; /* balanced? */ 465 return -1; /* balanced? */
466 }
309 cmd = 1 + strstr(str, "'"); 467 cmd = 1 + strstr(str, "'");
310 str[strcspn(str, "'")] = 0; 468 str[strcspn(str, "'")] = 0;
311 } else { 469 } else {
@@ -317,8 +475,9 @@ int cmd_run(const char *cmdstring, output *out, output *err, int flags) {
317 } 475 }
318 } 476 }
319 477
320 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n")) 478 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n")) {
321 cmd = NULL; 479 cmd = NULL;
480 }
322 481
323 argv[i++] = str; 482 argv[i++] = str;
324 } 483 }
@@ -326,54 +485,199 @@ int cmd_run(const char *cmdstring, output *out, output *err, int flags) {
326 return cmd_run_array(argv, out, err, flags); 485 return cmd_run_array(argv, out, err, flags);
327} 486}
328 487
329int cmd_run_array(char *const *argv, output *out, output *err, int flags) { 488cmd_run_result cmd_run2(const char *cmd_string, int flags) {
330 int fd, pfd_out[2], pfd_err[2]; 489 cmd_run_result result = {
490 .cmd_error_code = 0,
491 .error_code = 0,
492 .err =
493 {
494 .buf = NULL,
495 .buflen = 0,
496 .line = NULL,
497 .lines = 0,
498 },
499 .out =
500 {
501 .buf = NULL,
502 .buflen = 0,
503 .line = NULL,
504 .lines = 0,
505 },
506 };
507
508 if (cmd_string == NULL) {
509 result.error_code = -1;
510 return result;
511 }
512
513 /* make copy of command string so strtok() doesn't silently modify it */
514 /* (the calling program may want to access it later) */
515 char *cmd = strdup(cmd_string);
516 if (cmd == NULL) {
517 result.error_code = -1;
518 return result;
519 }
520
521 /* This is not a shell, so we don't handle "???" */
522 if (strstr(cmd, "\"")) {
523 result.error_code = -1;
524 return result;
525 }
526
527 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
528 if (strstr(cmd, " ' ") || strstr(cmd, "'''")) {
529 result.error_code = -1;
530 return result;
531 }
532
533 /* each arg must be whitespace-separated, so args can be a maximum
534 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */
535 size_t cmdlen = strlen(cmd_string);
536 size_t argc = (cmdlen >> 1) + 2;
537 char **argv = calloc(argc, sizeof(char *));
538
539 if (argv == NULL) {
540 printf("%s\n", _("Could not malloc argv array in popen()"));
541 result.error_code = -1;
542 return result;
543 }
331 544
545 /* get command arguments (stupidly, but fairly quickly) */
546 for (int i = 0; cmd; i++) {
547 char *str = cmd;
548 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
549
550 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */
551 str++;
552 if (!strstr(str, "'")) {
553 result.error_code = -1;
554 return result; /* balanced? */
555 }
556
557 cmd = 1 + strstr(str, "'");
558 str[strcspn(str, "'")] = 0;
559 } else {
560 if (strpbrk(str, " \t\r\n")) {
561 cmd = 1 + strpbrk(str, " \t\r\n");
562 str[strcspn(str, " \t\r\n")] = 0;
563 } else {
564 cmd = NULL;
565 }
566 }
567
568 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n")) {
569 cmd = NULL;
570 }
571
572 argv[i++] = str;
573 }
574
575 result = cmd_run_array2(argv, flags);
576
577 return result;
578}
579
580cmd_run_result cmd_run_array2(char *const *cmd, int flags) {
581 cmd_run_result result = {
582 .cmd_error_code = 0,
583 .error_code = 0,
584 .err =
585 {
586 .buf = NULL,
587 .buflen = 0,
588 .line = NULL,
589 .lines = 0,
590 },
591 .out =
592 {
593 .buf = NULL,
594 .buflen = 0,
595 .line = NULL,
596 .lines = 0,
597 },
598 };
599
600 int_cmd_open_result cmd_open_result = _cmd_open2(cmd);
601 if (cmd_open_result.error_code != 0) {
602 // result.error_code = -1;
603 // return result;
604 // TODO properly handle this without dying
605 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd[0]);
606 }
607
608 int file_descriptor = cmd_open_result.file_descriptor;
609 int pfd_out[2] = {cmd_open_result.stdout_pipe_fd[0], cmd_open_result.stdout_pipe_fd[1]};
610 int pfd_err[2] = {cmd_open_result.stderr_pipe_fd[0], cmd_open_result.stderr_pipe_fd[1]};
611
612 int_cmd_fetch_output2 tmp_stdout = _cmd_fetch_output2(pfd_out[0], flags);
613 result.out = tmp_stdout.output_container;
614 int_cmd_fetch_output2 tmp_stderr = _cmd_fetch_output2(pfd_err[0], flags);
615 result.err = tmp_stderr.output_container;
616
617 result.cmd_error_code = _cmd_close(file_descriptor);
618 return result;
619}
620
621int cmd_run_array(char *const *argv, output *out, output *err, int flags) {
332 /* initialize the structs */ 622 /* initialize the structs */
333 if (out) 623 if (out) {
334 memset(out, 0, sizeof(output)); 624 memset(out, 0, sizeof(output));
335 if (err) 625 }
626 if (err) {
336 memset(err, 0, sizeof(output)); 627 memset(err, 0, sizeof(output));
628 }
337 629
338 if ((fd = _cmd_open(argv, pfd_out, pfd_err)) == -1) 630 int fd;
631 int pfd_out[2];
632 int pfd_err[2];
633 if ((fd = _cmd_open(argv, pfd_out, pfd_err)) == -1) {
339 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), argv[0]); 634 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), argv[0]);
635 }
340 636
341 if (out) 637 if (out) {
342 out->lines = _cmd_fetch_output(pfd_out[0], out, flags); 638 out->lines = _cmd_fetch_output(pfd_out[0], out, flags);
343 if (err) 639 }
640 if (err) {
344 err->lines = _cmd_fetch_output(pfd_err[0], err, flags); 641 err->lines = _cmd_fetch_output(pfd_err[0], err, flags);
642 }
345 643
346 return _cmd_close(fd); 644 return _cmd_close(fd);
347} 645}
348 646
349int cmd_file_read(char *filename, output *out, int flags) { 647int cmd_file_read(const char *filename, output *out, int flags) {
350 int fd; 648 int fd;
351 if (out) 649 if (out) {
352 memset(out, 0, sizeof(output)); 650 memset(out, 0, sizeof(output));
651 }
353 652
354 if ((fd = open(filename, O_RDONLY)) == -1) { 653 if ((fd = open(filename, O_RDONLY)) == -1) {
355 die(STATE_UNKNOWN, _("Error opening %s: %s"), filename, strerror(errno)); 654 die(STATE_UNKNOWN, _("Error opening %s: %s"), filename, strerror(errno));
356 } 655 }
357 656
358 if (out) 657 if (out) {
359 out->lines = _cmd_fetch_output(fd, out, flags); 658 out->lines = _cmd_fetch_output(fd, out, flags);
659 }
360 660
361 if (close(fd) == -1) 661 if (close(fd) == -1) {
362 die(STATE_UNKNOWN, _("Error closing %s: %s"), filename, strerror(errno)); 662 die(STATE_UNKNOWN, _("Error closing %s: %s"), filename, strerror(errno));
663 }
363 664
364 return 0; 665 return 0;
365} 666}
366 667
367void timeout_alarm_handler(int signo) { 668void timeout_alarm_handler(int signo) {
368 if (signo == SIGALRM) { 669 if (signo == SIGALRM) {
369 printf(_("%s - Plugin timed out after %d seconds\n"), state_text(timeout_state), timeout_interval); 670 printf(_("%s - Plugin timed out after %d seconds\n"), state_text(timeout_state),
671 timeout_interval);
370 672
371 long maxfd = mp_open_max(); 673 long maxfd = mp_open_max();
372 if (_cmd_pids) 674 if (_cmd_pids) {
373 for (long int i = 0; i < maxfd; i++) { 675 for (long int i = 0; i < maxfd; i++) {
374 if (_cmd_pids[i] != 0) 676 if (_cmd_pids[i] != 0) {
375 kill(_cmd_pids[i], SIGKILL); 677 kill(_cmd_pids[i], SIGKILL);
678 }
376 } 679 }
680 }
377 681
378 exit(timeout_state); 682 exit(timeout_state);
379 } 683 }
diff --git a/lib/utils_cmd.h b/lib/utils_cmd.h
index d00069c9..04a624b8 100644
--- a/lib/utils_cmd.h
+++ b/lib/utils_cmd.h
@@ -5,22 +5,30 @@
5 * Header file for Monitoring Plugins utils_cmd.c 5 * Header file for Monitoring Plugins utils_cmd.c
6 * 6 *
7 */ 7 */
8#include "../config.h"
9#include <stddef.h>
8 10
9/** types **/ 11/** types **/
10struct output { 12typedef struct {
11 char *buf; /* output buffer */ 13 char *buf; /* output buffer */
12 size_t buflen; /* output buffer content length */ 14 size_t buflen; /* output buffer content length */
13 char **line; /* array of lines (points to buf) */ 15 char **line; /* array of lines (points to buf) */
14 size_t *lens; /* string lengths */
15 size_t lines; /* lines of output */ 16 size_t lines; /* lines of output */
16}; 17} output;
17
18typedef struct output output;
19 18
20/** prototypes **/ 19/** prototypes **/
21int cmd_run(const char *, output *, output *, int); 20int cmd_run(const char *, output *, output *, int);
22int cmd_run_array(char *const *, output *, output *, int); 21int cmd_run_array(char *const *, output *, output *, int);
23int cmd_file_read(char *, output *, int); 22int cmd_file_read(const char *, output *, int);
23
24typedef struct {
25 int error_code;
26 int cmd_error_code;
27 output out;
28 output err;
29} cmd_run_result;
30cmd_run_result cmd_run2(const char *cmd, int flags);
31cmd_run_result cmd_run_array2(char * const *cmd, int flags);
24 32
25/* only multi-threaded plugins need to bother with this */ 33/* only multi-threaded plugins need to bother with this */
26void cmd_init(void); 34void cmd_init(void);
diff --git a/lib/utils_disk.c b/lib/utils_disk.c
deleted file mode 100644
index 2b761f5e..00000000
--- a/lib/utils_disk.c
+++ /dev/null
@@ -1,255 +0,0 @@
1/*****************************************************************************
2 *
3 * Library for check_disk
4 *
5 * License: GPL
6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7 *
8 * Description:
9 *
10 * This file contains utilities for check_disk. These are tested by libtap
11 *
12 *
13 * This program is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 *
26 *
27 *****************************************************************************/
28
29#include "common.h"
30#include "utils_disk.h"
31#include "gl/fsusage.h"
32#include <string.h>
33
34void np_add_name(struct name_list **list, const char *name) {
35 struct name_list *new_entry;
36 new_entry = (struct name_list *)malloc(sizeof *new_entry);
37 new_entry->name = (char *)name;
38 new_entry->next = *list;
39 *list = new_entry;
40}
41
42/* @brief Initialises a new regex at the begin of list via regcomp(3)
43 *
44 * @details if the regex fails to compile the error code of regcomp(3) is returned
45 * and list is not modified, otherwise list is modified to point to the new
46 * element
47 * @param list Pointer to a linked list of regex_list elements
48 * @param regex the string containing the regex which should be inserted into the list
49 * @param clags the cflags parameter for regcomp(3)
50 */
51int np_add_regex(struct regex_list **list, const char *regex, int cflags) {
52 struct regex_list *new_entry = (struct regex_list *)malloc(sizeof *new_entry);
53
54 if (new_entry == NULL) {
55 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
56 }
57
58 int regcomp_result = regcomp(&new_entry->regex, regex, cflags);
59
60 if (!regcomp_result) {
61 // regcomp succeeded
62 new_entry->next = *list;
63 *list = new_entry;
64
65 return 0;
66 } else {
67 // regcomp failed
68 free(new_entry);
69
70 return regcomp_result;
71 }
72}
73
74/* Initialises a new parameter at the end of list */
75struct parameter_list *np_add_parameter(struct parameter_list **list, const char *name) {
76 struct parameter_list *current = *list;
77 struct parameter_list *new_path;
78 new_path = (struct parameter_list *)malloc(sizeof *new_path);
79 new_path->name = (char *)malloc(strlen(name) + 1);
80 new_path->best_match = NULL;
81 new_path->name_next = NULL;
82 new_path->name_prev = NULL;
83 new_path->freespace_bytes = NULL;
84 new_path->freespace_units = NULL;
85 new_path->freespace_percent = NULL;
86 new_path->usedspace_bytes = NULL;
87 new_path->usedspace_units = NULL;
88 new_path->usedspace_percent = NULL;
89 new_path->usedinodes_percent = NULL;
90 new_path->freeinodes_percent = NULL;
91 new_path->group = NULL;
92 new_path->dfree_pct = -1;
93 new_path->dused_pct = -1;
94 new_path->total = 0;
95 new_path->available = 0;
96 new_path->available_to_root = 0;
97 new_path->used = 0;
98 new_path->dused_units = 0;
99 new_path->dfree_units = 0;
100 new_path->dtotal_units = 0;
101 new_path->inodes_total = 0;
102 new_path->inodes_free = 0;
103 new_path->inodes_free_to_root = 0;
104 new_path->inodes_used = 0;
105 new_path->dused_inodes_percent = 0;
106 new_path->dfree_inodes_percent = 0;
107
108 strcpy(new_path->name, name);
109
110 if (current == NULL) {
111 *list = new_path;
112 new_path->name_prev = NULL;
113 } else {
114 while (current->name_next) {
115 current = current->name_next;
116 }
117 current->name_next = new_path;
118 new_path->name_prev = current;
119 }
120 return new_path;
121}
122
123/* Delete a given parameter from list and return pointer to next element*/
124struct parameter_list *np_del_parameter(struct parameter_list *item, struct parameter_list *prev) {
125 if (item == NULL) {
126 return NULL;
127 }
128 struct parameter_list *next;
129
130 if (item->name_next)
131 next = item->name_next;
132 else
133 next = NULL;
134
135 if (next)
136 next->name_prev = prev;
137
138 if (prev)
139 prev->name_next = next;
140
141 if (item->name) {
142 free(item->name);
143 }
144 free(item);
145
146 return next;
147}
148
149/* returns a pointer to the struct found in the list */
150struct parameter_list *np_find_parameter(struct parameter_list *list, const char *name) {
151 struct parameter_list *temp_list;
152 for (temp_list = list; temp_list; temp_list = temp_list->name_next) {
153 if (!strcmp(temp_list->name, name))
154 return temp_list;
155 }
156
157 return NULL;
158}
159
160void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact) {
161 struct parameter_list *d;
162 for (d = desired; d; d = d->name_next) {
163 if (!d->best_match) {
164 struct mount_entry *me;
165 size_t name_len = strlen(d->name);
166 size_t best_match_len = 0;
167 struct mount_entry *best_match = NULL;
168 struct fs_usage fsp;
169
170 /* set best match if path name exactly matches a mounted device name */
171 for (me = mount_list; me; me = me->me_next) {
172 if (strcmp(me->me_devname, d->name) == 0) {
173 if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) {
174 best_match = me;
175 }
176 }
177 }
178
179 /* set best match by directory name if no match was found by devname */
180 if (!best_match) {
181 for (me = mount_list; me; me = me->me_next) {
182 size_t len = strlen(me->me_mountdir);
183 if ((!exact &&
184 (best_match_len <= len && len <= name_len && (len == 1 || strncmp(me->me_mountdir, d->name, len) == 0))) ||
185 (exact && strcmp(me->me_mountdir, d->name) == 0)) {
186 if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) {
187 best_match = me;
188 best_match_len = len;
189 }
190 }
191 }
192 }
193
194 if (best_match) {
195 d->best_match = best_match;
196 } else {
197 d->best_match = NULL; /* Not sure why this is needed as it should be null on initialisation */
198 }
199 }
200 }
201}
202
203/* Returns true if name is in list */
204bool np_find_name(struct name_list *list, const char *name) {
205 const struct name_list *n;
206
207 if (list == NULL || name == NULL) {
208 return false;
209 }
210 for (n = list; n; n = n->next) {
211 if (!strcmp(name, n->name)) {
212 return true;
213 }
214 }
215 return false;
216}
217
218/* Returns true if name is in list */
219bool np_find_regmatch(struct regex_list *list, const char *name) {
220 int len;
221 regmatch_t m;
222
223 if (name == NULL) {
224 return false;
225 }
226
227 len = strlen(name);
228
229 for (; list; list = list->next) {
230 /* Emulate a full match as if surrounded with ^( )$
231 by checking whether the match spans the whole name */
232 if (!regexec(&list->regex, name, 1, &m, 0) && m.rm_so == 0 && m.rm_eo == len) {
233 return true;
234 }
235 }
236
237 return false;
238}
239
240bool np_seen_name(struct name_list *list, const char *name) {
241 const struct name_list *s;
242 for (s = list; s; s = s->next) {
243 if (!strcmp(s->name, name)) {
244 return true;
245 }
246 }
247 return false;
248}
249
250bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re) {
251 if (regexec(re, me->me_devname, (size_t)0, NULL, 0) == 0 || regexec(re, me->me_mountdir, (size_t)0, NULL, 0) == 0) {
252 return true;
253 }
254 return false;
255}
diff --git a/lib/utils_disk.h b/lib/utils_disk.h
deleted file mode 100644
index c5e81dc1..00000000
--- a/lib/utils_disk.h
+++ /dev/null
@@ -1,48 +0,0 @@
1/* Header file for utils_disk */
2
3#include "mountlist.h"
4#include "utils_base.h"
5#include "regex.h"
6
7struct name_list {
8 char *name;
9 struct name_list *next;
10};
11
12struct regex_list {
13 regex_t regex;
14 struct regex_list *next;
15};
16
17struct parameter_list {
18 char *name;
19 thresholds *freespace_bytes;
20 thresholds *freespace_units;
21 thresholds *freespace_percent;
22 thresholds *usedspace_bytes;
23 thresholds *usedspace_units;
24 thresholds *usedspace_percent;
25 thresholds *usedinodes_percent;
26 thresholds *freeinodes_percent;
27 char *group;
28 struct mount_entry *best_match;
29 struct parameter_list *name_next;
30 struct parameter_list *name_prev;
31 uintmax_t total, available, available_to_root, used, inodes_free, inodes_free_to_root, inodes_used, inodes_total;
32 double dfree_pct, dused_pct;
33 uint64_t dused_units, dfree_units, dtotal_units;
34 double dused_inodes_percent, dfree_inodes_percent;
35};
36
37void np_add_name(struct name_list **list, const char *name);
38bool np_find_name(struct name_list *list, const char *name);
39bool np_seen_name(struct name_list *list, const char *name);
40int np_add_regex(struct regex_list **list, const char *regex, int cflags);
41bool np_find_regmatch(struct regex_list *list, const char *name);
42struct parameter_list *np_add_parameter(struct parameter_list **list, const char *name);
43struct parameter_list *np_find_parameter(struct parameter_list *list, const char *name);
44struct parameter_list *np_del_parameter(struct parameter_list *item, struct parameter_list *prev);
45
46int search_parameter_list(struct parameter_list *list, const char *name);
47void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact);
48bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re);
diff --git a/lib/utils_tcp.c b/lib/utils_tcp.c
index daae1d54..a82d5a3f 100644
--- a/lib/utils_tcp.c
+++ b/lib/utils_tcp.c
@@ -26,28 +26,35 @@
26 * 26 *
27 *****************************************************************************/ 27 *****************************************************************************/
28 28
29#include "common.h" 29#include "../config.h"
30#include "utils_tcp.h" 30#include "utils_tcp.h"
31#include <stdio.h>
32#include <string.h>
31 33
32#define VERBOSE(message) \ 34#define VERBOSE(message) \
33 do { \ 35 do { \
34 if (flags & NP_MATCH_VERBOSE) \ 36 if (flags & NP_MATCH_VERBOSE) \
35 puts(message); \ 37 puts(message); \
36 } while (0) 38 } while (0)
37 39
38enum np_match_result np_expect_match(char *status, char **server_expect, int expect_count, int flags) { 40enum np_match_result np_expect_match(char *status, char **server_expect, int expect_count,
39 int i, match = 0, partial = 0; 41 int flags) {
40 42 int match = 0;
41 for (i = 0; i < expect_count; i++) { 43 int partial = 0;
42 if (flags & NP_MATCH_VERBOSE) 44 for (int i = 0; i < expect_count; i++) {
43 printf("looking for [%s] %s [%s]\n", server_expect[i], (flags & NP_MATCH_EXACT) ? "in beginning of" : "anywhere in", status); 45 if (flags & NP_MATCH_VERBOSE) {
46 printf("looking for [%s] %s [%s]\n", server_expect[i],
47 (flags & NP_MATCH_EXACT) ? "in beginning of" : "anywhere in", status);
48 }
44 49
45 if (flags & NP_MATCH_EXACT) { 50 if (flags & NP_MATCH_EXACT) {
46 if (strncmp(status, server_expect[i], strlen(server_expect[i])) == 0) { 51 if (strncmp(status, server_expect[i], strlen(server_expect[i])) == 0) {
47 VERBOSE("found it"); 52 VERBOSE("found it");
48 match++; 53 match++;
49 continue; 54 continue;
50 } else if (strncmp(status, server_expect[i], strlen(status)) == 0) { 55 }
56
57 if (strncmp(status, server_expect[i], strlen(status)) == 0) {
51 VERBOSE("found a substring"); 58 VERBOSE("found a substring");
52 partial++; 59 partial++;
53 continue; 60 continue;
@@ -60,10 +67,12 @@ enum np_match_result np_expect_match(char *status, char **server_expect, int exp
60 VERBOSE("couldn't find it"); 67 VERBOSE("couldn't find it");
61 } 68 }
62 69
63 if ((flags & NP_MATCH_ALL && match == expect_count) || (!(flags & NP_MATCH_ALL) && match >= 1)) 70 if ((flags & NP_MATCH_ALL && match == expect_count) ||
71 (!(flags & NP_MATCH_ALL) && match >= 1)) {
64 return NP_MATCH_SUCCESS; 72 return NP_MATCH_SUCCESS;
65 else if (partial > 0 || !(flags & NP_MATCH_EXACT)) 73 }
74 if (partial > 0 || !(flags & NP_MATCH_EXACT)) {
66 return NP_MATCH_RETRY; 75 return NP_MATCH_RETRY;
67 else 76 }
68 return NP_MATCH_FAILURE; 77 return NP_MATCH_FAILURE;
69} 78}
diff --git a/lib/utils_tcp.h b/lib/utils_tcp.h
index d5999e9b..e5cdbb82 100644
--- a/lib/utils_tcp.h
+++ b/lib/utils_tcp.h
@@ -11,9 +11,11 @@
11 * server. 11 * server.
12 */ 12 */
13enum np_match_result { 13enum np_match_result {
14 NP_MATCH_NONE,
14 NP_MATCH_FAILURE, 15 NP_MATCH_FAILURE,
15 NP_MATCH_SUCCESS, 16 NP_MATCH_SUCCESS,
16 NP_MATCH_RETRY 17 NP_MATCH_RETRY
17}; 18};
18 19
19enum np_match_result np_expect_match(char *status, char **server_expect, int server_expect_count, int flags); 20enum np_match_result np_expect_match(char *status, char **server_expect, int server_expect_count,
21 int flags);
diff --git a/plugins-root/Makefile.am b/plugins-root/Makefile.am
index a80229e2..b6342909 100644
--- a/plugins-root/Makefile.am
+++ b/plugins-root/Makefile.am
@@ -24,7 +24,9 @@ noinst_PROGRAMS = check_dhcp check_icmp @EXTRAS_ROOT@
24 24
25EXTRA_PROGRAMS = pst3 25EXTRA_PROGRAMS = pst3
26 26
27EXTRA_DIST = t pst3.c 27EXTRA_DIST = t pst3.c \
28 check_icmp.d \
29 check_dhcp.d
28 30
29BASEOBJS = ../plugins/utils.o ../lib/libmonitoringplug.a ../gl/libgnu.a 31BASEOBJS = ../plugins/utils.o ../lib/libmonitoringplug.a ../gl/libgnu.a
30NETOBJS = ../plugins/netutils.o $(BASEOBJS) $(EXTRA_NETOBJS) 32NETOBJS = ../plugins/netutils.o $(BASEOBJS) $(EXTRA_NETOBJS)
@@ -82,6 +84,7 @@ install-exec-local: $(noinst_PROGRAMS)
82# the actual targets 84# the actual targets
83check_dhcp_LDADD = @LTLIBINTL@ $(NETLIBS) $(LIB_CRYPTO) 85check_dhcp_LDADD = @LTLIBINTL@ $(NETLIBS) $(LIB_CRYPTO)
84check_icmp_LDADD = @LTLIBINTL@ $(NETLIBS) $(SOCKETLIBS) $(LIB_CRYPTO) 86check_icmp_LDADD = @LTLIBINTL@ $(NETLIBS) $(SOCKETLIBS) $(LIB_CRYPTO)
87check_icmp_SOURCES = check_icmp.c check_icmp.d/check_icmp_helpers.c
85 88
86# -m64 needed at compiler and linker phase 89# -m64 needed at compiler and linker phase
87pst3_CFLAGS = @PST3CFLAGS@ 90pst3_CFLAGS = @PST3CFLAGS@
@@ -89,7 +92,7 @@ pst3_LDFLAGS = @PST3CFLAGS@
89# pst3 must not use monitoringplug/gnulib includes! 92# pst3 must not use monitoringplug/gnulib includes!
90pst3_CPPFLAGS = 93pst3_CPPFLAGS =
91 94
92check_dhcp_DEPENDENCIES = check_dhcp.c $(NETOBJS) $(DEPLIBS) 95check_dhcp_DEPENDENCIES = check_dhcp.c $(NETOBJS) $(DEPLIBS)
93check_icmp_DEPENDENCIES = check_icmp.c $(NETOBJS) 96check_icmp_DEPENDENCIES = check_icmp.c $(NETOBJS)
94 97
95clean-local: 98clean-local:
diff --git a/plugins-root/check_dhcp.c b/plugins-root/check_dhcp.c
index 6802232e..9a96547f 100644
--- a/plugins-root/check_dhcp.c
+++ b/plugins-root/check_dhcp.c
@@ -4,7 +4,7 @@
4 * 4 *
5 * License: GPL 5 * License: GPL
6 * Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org) 6 * Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org)
7 * Copyright (c) 2001-2023 Monitoring Plugins Development Team 7 * Copyright (c) 2001-2025 Monitoring Plugins Development Team
8 * 8 *
9 * Description: 9 * Description:
10 * 10 *
@@ -34,13 +34,17 @@
34 *****************************************************************************/ 34 *****************************************************************************/
35 35
36const char *progname = "check_dhcp"; 36const char *progname = "check_dhcp";
37const char *copyright = "2001-2024"; 37const char *copyright = "2001-2025";
38const char *email = "devel@monitoring-plugins.org"; 38const char *email = "devel@monitoring-plugins.org";
39 39
40#include "common.h" 40#include "../plugins/common.h"
41#include "netutils.h" 41#include "../plugins/utils.h"
42#include "utils.h" 42#include "./check_dhcp.d/config.h"
43#include "../lib/output.h"
44#include "../lib/utils_base.h"
43 45
46#include "states.h"
47#include <stdint.h>
44#include <ctype.h> 48#include <ctype.h>
45#include <stdio.h> 49#include <stdio.h>
46#include <stdlib.h> 50#include <stdlib.h>
@@ -111,8 +115,9 @@ static long mac_addr_dlpi(const char *, int, u_char *);
111 115
112/**** Common definitions ****/ 116/**** Common definitions ****/
113 117
114#define OK 0 118#define OK 0
115#define ERROR -1 119#define ERROR -1
120#define MAC_ADDR_LEN 6
116 121
117/**** DHCP definitions ****/ 122/**** DHCP definitions ****/
118 123
@@ -122,17 +127,17 @@ static long mac_addr_dlpi(const char *, int, u_char *);
122#define MAX_DHCP_OPTIONS_LENGTH 312 127#define MAX_DHCP_OPTIONS_LENGTH 312
123 128
124typedef struct dhcp_packet_struct { 129typedef struct dhcp_packet_struct {
125 uint8_t op; /* packet type */ 130 uint8_t op; /* packet type */
126 uint8_t htype; /* type of hardware address for this machine (Ethernet, etc) */ 131 uint8_t htype; /* type of hardware address for this machine (Ethernet, etc) */
127 uint8_t hlen; /* length of hardware address (of this machine) */ 132 uint8_t hlen; /* length of hardware address (of this machine) */
128 uint8_t hops; /* hops */ 133 uint8_t hops; /* hops */
129 uint32_t xid; /* random transaction id number - chosen by this machine */ 134 uint32_t xid; /* random transaction id number - chosen by this machine */
130 uint16_t secs; /* seconds used in timing */ 135 uint16_t secs; /* seconds used in timing */
131 uint16_t flags; /* flags */ 136 uint16_t flags; /* flags */
132 struct in_addr ciaddr; /* IP address of this machine (if we already have one) */ 137 struct in_addr ciaddr; /* IP address of this machine (if we already have one) */
133 struct in_addr yiaddr; /* IP address of this machine (offered by the DHCP server) */ 138 struct in_addr yiaddr; /* IP address of this machine (offered by the DHCP server) */
134 struct in_addr siaddr; /* IP address of next server */ 139 struct in_addr siaddr; /* IP address of next server */
135 struct in_addr giaddr; /* IP address of DHCP relay */ 140 struct in_addr giaddr; /* IP address of DHCP relay */
136 unsigned char chaddr[MAX_DHCP_CHADDR_LENGTH]; /* hardware address of this machine */ 141 unsigned char chaddr[MAX_DHCP_CHADDR_LENGTH]; /* hardware address of this machine */
137 char sname[MAX_DHCP_SNAME_LENGTH]; /* name of DHCP server */ 142 char sname[MAX_DHCP_SNAME_LENGTH]; /* name of DHCP server */
138 char file[MAX_DHCP_FILE_LENGTH]; /* boot file name (used for diskless booting?) */ 143 char file[MAX_DHCP_FILE_LENGTH]; /* boot file name (used for diskless booting?) */
@@ -149,12 +154,6 @@ typedef struct dhcp_offer_struct {
149 struct dhcp_offer_struct *next; 154 struct dhcp_offer_struct *next;
150} dhcp_offer; 155} dhcp_offer;
151 156
152typedef struct requested_server_struct {
153 struct in_addr server_address;
154 bool answered;
155 struct requested_server_struct *next;
156} requested_server;
157
158#define BOOTREQUEST 1 157#define BOOTREQUEST 1
159#define BOOTREPLY 2 158#define BOOTREPLY 2
160 159
@@ -186,65 +185,69 @@ typedef struct requested_server_struct {
186#define ETHERNET_HARDWARE_ADDRESS 1 /* used in htype field of dhcp packet */ 185#define ETHERNET_HARDWARE_ADDRESS 1 /* used in htype field of dhcp packet */
187#define ETHERNET_HARDWARE_ADDRESS_LENGTH 6 /* length of Ethernet hardware addresses */ 186#define ETHERNET_HARDWARE_ADDRESS_LENGTH 6 /* length of Ethernet hardware addresses */
188 187
189static bool unicast = false; /* unicast mode: mimic a DHCP relay */
190static bool exclusive = false; /* exclusive mode aka "rogue DHCP server detection" */
191static struct in_addr my_ip; /* our address (required for relay) */
192static struct in_addr dhcp_ip; /* server to query (if in unicast mode) */
193static unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH] = "";
194static unsigned char *user_specified_mac = NULL;
195
196static char network_interface_name[IFNAMSIZ] = "eth0";
197
198static uint32_t packet_xid = 0;
199
200static uint32_t dhcp_lease_time = 0;
201static uint32_t dhcp_renewal_time = 0;
202static uint32_t dhcp_rebinding_time = 0;
203
204static int dhcpoffer_timeout = 2;
205
206static dhcp_offer *dhcp_offer_list = NULL;
207static requested_server *requested_server_list = NULL;
208
209static int valid_responses = 0; /* number of valid DHCPOFFERs we received */
210static int requested_servers = 0;
211static int requested_responses = 0;
212
213static bool request_specific_address = false;
214static bool received_requested_address = false;
215static int verbose = 0; 188static int verbose = 0;
216static struct in_addr requested_address;
217 189
218static int process_arguments(int, char **); 190typedef struct process_arguments_wrapper {
219static int call_getopt(int, char **); 191 int error;
220static int validate_arguments(int); 192 check_dhcp_config config;
193} process_arguments_wrapper;
194
195static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
221void print_usage(void); 196void print_usage(void);
222static void print_help(void); 197static void print_help(void);
223 198
224static void resolve_host(const char *in, struct in_addr *out); 199static void resolve_host(const char * /*in*/, struct in_addr * /*out*/);
225static unsigned char *mac_aton(const char *); 200static unsigned char *mac_aton(const char * /*string*/);
226static void print_hardware_address(const unsigned char *); 201static void print_hardware_address(const unsigned char * /*address*/);
227static int get_hardware_address(int, char *); 202static int get_hardware_address(int /*sock*/, char * /*interface_name*/,
228static int get_ip_address(int, char *); 203 unsigned char *client_hardware_address);
229 204
230static int send_dhcp_discover(int); 205typedef struct get_ip_address_wrapper {
231static int get_dhcp_offer(int); 206 int error;
232 207 struct in_addr my_ip;
233static int get_results(void); 208} get_ip_address_wrapper;
234 209static get_ip_address_wrapper get_ip_address(int /*sock*/, char * /*interface_name*/);
235static int add_dhcp_offer(struct in_addr, dhcp_packet *); 210
236static int free_dhcp_offer_list(void); 211typedef struct send_dhcp_discover_wrapper {
237static int free_requested_server_list(void); 212 int error;
238 213 uint32_t packet_xid;
239static int create_dhcp_socket(void); 214} send_dhcp_discover_wrapper;
240static int close_dhcp_socket(int); 215static send_dhcp_discover_wrapper
241static int send_dhcp_packet(void *, int, int, struct sockaddr_in *); 216send_dhcp_discover(int socket, bool unicast, struct in_addr dhcp_ip,
242static int receive_dhcp_packet(void *, int, int, int, struct sockaddr_in *); 217 struct in_addr requested_address, bool request_specific_address,
218 struct in_addr my_ip, unsigned char *client_hardware_address);
219typedef struct get_dhcp_offer_wrapper {
220 int error;
221 int valid_responses;
222 dhcp_offer *dhcp_offer_list;
223} get_dhcp_offer_wrapper;
224static get_dhcp_offer_wrapper get_dhcp_offer(int /*sock*/, int dhcpoffer_timeout,
225 uint32_t packet_xid, dhcp_offer *dhcp_offer_list,
226 const unsigned char *client_hardware_address);
227
228static mp_subcheck get_results(bool exclusive, int requested_servers,
229 struct in_addr requested_address, bool request_specific_address,
230 requested_server *requested_server_list, int valid_responses,
231 dhcp_offer *dhcp_offer_list);
232
233typedef struct add_dhcp_offer_wrapper {
234 int error;
235 dhcp_offer *dhcp_offer_list;
236} add_dhcp_offer_wrapper;
237static add_dhcp_offer_wrapper add_dhcp_offer(struct in_addr /*source*/,
238 dhcp_packet * /*offer_packet*/,
239 dhcp_offer *dhcp_offer_list);
240static int free_dhcp_offer_list(dhcp_offer *dhcp_offer_list);
241static int free_requested_server_list(requested_server *requested_server_list);
242
243static int create_dhcp_socket(bool /*unicast*/, char *network_interface_name);
244static int close_dhcp_socket(int /*sock*/);
245static int send_dhcp_packet(void * /*buffer*/, int /*buffer_size*/, int /*sock*/,
246 struct sockaddr_in * /*dest*/);
247static int receive_dhcp_packet(void * /*buffer*/, int /*buffer_size*/, int /*sock*/,
248 int /*timeout*/, struct sockaddr_in * /*address*/);
243 249
244int main(int argc, char **argv) { 250int main(int argc, char **argv) {
245 int dhcp_socket;
246 int result = STATE_UNKNOWN;
247
248 setlocale(LC_ALL, ""); 251 setlocale(LC_ALL, "");
249 bindtextdomain(PACKAGE, LOCALEDIR); 252 bindtextdomain(PACKAGE, LOCALEDIR);
250 textdomain(PACKAGE); 253 textdomain(PACKAGE);
@@ -252,43 +255,84 @@ int main(int argc, char **argv) {
252 /* Parse extra opts if any */ 255 /* Parse extra opts if any */
253 argv = np_extra_opts(&argc, argv, progname); 256 argv = np_extra_opts(&argc, argv, progname);
254 257
255 if (process_arguments(argc, argv) != OK) { 258 process_arguments_wrapper tmp = process_arguments(argc, argv);
259
260 if (tmp.error != OK) {
256 usage4(_("Could not parse arguments")); 261 usage4(_("Could not parse arguments"));
257 } 262 }
258 263
264 check_dhcp_config config = tmp.config;
265 if (config.output_format_is_set) {
266 mp_set_format(config.output_format);
267 }
268
259 /* create socket for DHCP communications */ 269 /* create socket for DHCP communications */
260 dhcp_socket = create_dhcp_socket(); 270 int dhcp_socket = create_dhcp_socket(config.unicast_mode, config.network_interface_name);
261 271
262 /* get hardware address of client machine */ 272 /* get hardware address of client machine */
263 if (user_specified_mac != NULL) 273 unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH] = "";
264 memcpy(client_hardware_address, user_specified_mac, 6); 274 if (config.user_specified_mac != NULL) {
265 else 275 memcpy(client_hardware_address, config.user_specified_mac, MAC_ADDR_LEN);
266 get_hardware_address(dhcp_socket, network_interface_name); 276 } else {
277 get_hardware_address(dhcp_socket, config.network_interface_name, client_hardware_address);
278 }
267 279
268 if (unicast) /* get IP address of client machine */ 280 struct in_addr my_ip = {0};
269 get_ip_address(dhcp_socket, network_interface_name); 281
282 if (config.unicast_mode) { /* get IP address of client machine */
283 get_ip_address_wrapper tmp_get_ip =
284 get_ip_address(dhcp_socket, config.network_interface_name);
285 if (tmp_get_ip.error == OK) {
286 my_ip = tmp_get_ip.my_ip;
287 } else {
288 // TODO failed to get own IP
289 die(STATE_UNKNOWN, "Failed to retrieve my own IP address in unicast mode");
290 }
291 }
270 292
271 /* send DHCPDISCOVER packet */ 293 /* send DHCPDISCOVER packet */
272 send_dhcp_discover(dhcp_socket); 294 send_dhcp_discover_wrapper disco_res = send_dhcp_discover(
295 dhcp_socket, config.unicast_mode, config.dhcp_ip, config.requested_address,
296 config.request_specific_address, my_ip, client_hardware_address);
297
298 if (disco_res.error != OK) {
299 // DO something?
300 die(STATE_UNKNOWN, "Failed to send DHCP discover");
301 }
273 302
274 /* wait for a DHCPOFFER packet */ 303 /* wait for a DHCPOFFER packet */
275 get_dhcp_offer(dhcp_socket); 304 get_dhcp_offer_wrapper offer_res = get_dhcp_offer(
305 dhcp_socket, config.dhcpoffer_timeout, disco_res.packet_xid, NULL, client_hardware_address);
306
307 int valid_responses = 0;
308 dhcp_offer *dhcp_offer_list = NULL;
309 if (offer_res.error == OK) {
310 valid_responses = offer_res.valid_responses;
311 dhcp_offer_list = offer_res.dhcp_offer_list;
312 } else {
313 die(STATE_UNKNOWN, "Failed to get DHCP offers");
314 }
276 315
277 /* close socket we created */ 316 /* close socket we created */
278 close_dhcp_socket(dhcp_socket); 317 close_dhcp_socket(dhcp_socket);
279 318
280 /* determine state/plugin output to return */ 319 mp_check overall = mp_check_init();
281 result = get_results();
282 320
321 /* determine state/plugin output to return */
322 mp_subcheck sc_res =
323 get_results(config.exclusive_mode, config.num_of_requested_servers,
324 config.requested_address, config.request_specific_address,
325 config.requested_server_list, valid_responses, dhcp_offer_list);
326 mp_add_subcheck_to_check(&overall, sc_res);
283 /* free allocated memory */ 327 /* free allocated memory */
284 free_dhcp_offer_list(); 328 free_dhcp_offer_list(dhcp_offer_list);
285 free_requested_server_list(); 329 free_requested_server_list(config.requested_server_list);
286 330
287 return result; 331 mp_exit(overall);
288} 332}
289 333
290/* determines hardware address on client machine */ 334/* determines hardware address on client machine */
291static int get_hardware_address(int sock, char *interface_name) { 335int get_hardware_address(int sock, char *interface_name, unsigned char *client_hardware_address) {
292 336
293#if defined(__linux__) 337#if defined(__linux__)
294 struct ifreq ifr; 338 struct ifreq ifr;
@@ -302,7 +346,7 @@ static int get_hardware_address(int sock, char *interface_name) {
302 exit(STATE_UNKNOWN); 346 exit(STATE_UNKNOWN);
303 } 347 }
304 348
305 memcpy(&client_hardware_address[0], &ifr.ifr_hwaddr.sa_data, 6); 349 memcpy(&client_hardware_address[0], &ifr.ifr_hwaddr.sa_data, MAC_ADDR_LEN);
306 350
307#elif defined(__bsd__) 351#elif defined(__bsd__)
308 /* King 2004 see ACKNOWLEDGEMENTS */ 352 /* King 2004 see ACKNOWLEDGEMENTS */
@@ -326,17 +370,20 @@ static int get_hardware_address(int sock, char *interface_name) {
326 } 370 }
327 371
328 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { 372 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
329 printf(_("Error: Couldn't get hardware address from %s. sysctl 1 error - %s.\n"), interface_name, strerror(errno)); 373 printf(_("Error: Couldn't get hardware address from %s. sysctl 1 error - %s.\n"),
374 interface_name, strerror(errno));
330 exit(STATE_UNKNOWN); 375 exit(STATE_UNKNOWN);
331 } 376 }
332 377
333 if ((buf = malloc(len)) == NULL) { 378 if ((buf = malloc(len)) == NULL) {
334 printf(_("Error: Couldn't get hardware address from interface %s. malloc error - %s.\n"), interface_name, strerror(errno)); 379 printf(_("Error: Couldn't get hardware address from interface %s. malloc error - %s.\n"),
380 interface_name, strerror(errno));
335 exit(4); 381 exit(4);
336 } 382 }
337 383
338 if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { 384 if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
339 printf(_("Error: Couldn't get hardware address from %s. sysctl 2 error - %s.\n"), interface_name, strerror(errno)); 385 printf(_("Error: Couldn't get hardware address from %s. sysctl 2 error - %s.\n"),
386 interface_name, strerror(errno));
340 exit(STATE_UNKNOWN); 387 exit(STATE_UNKNOWN);
341 } 388 }
342 389
@@ -358,20 +405,25 @@ static int get_hardware_address(int sock, char *interface_name) {
358 int i; 405 int i;
359 p = interface_name + strlen(interface_name) - 1; 406 p = interface_name + strlen(interface_name) - 1;
360 for (i = strlen(interface_name) - 1; i > 0; p--) { 407 for (i = strlen(interface_name) - 1; i > 0; p--) {
361 if (isalpha(*p)) 408 if (isalpha(*p)) {
362 break; 409 break;
410 }
363 } 411 }
364 p++; 412 p++;
365 if (p != interface_name) { 413 if (p != interface_name) {
366 unit = atoi(p); 414 unit = atoi(p);
367 strncat(dev, interface_name, 6); 415 strncat(dev, interface_name, 6);
368 } else { 416 } else {
369 printf(_("Error: can't find unit number in interface_name (%s) - expecting TypeNumber eg lnc0.\n"), interface_name); 417 printf(_("Error: can't find unit number in interface_name (%s) - expecting TypeNumber eg "
418 "lnc0.\n"),
419 interface_name);
370 exit(STATE_UNKNOWN); 420 exit(STATE_UNKNOWN);
371 } 421 }
372 stat = mac_addr_dlpi(dev, unit, client_hardware_address); 422 stat = mac_addr_dlpi(dev, unit, client_hardware_address);
373 if (stat != 0) { 423 if (stat != 0) {
374 printf(_("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"), dev, unit); 424 printf(
425 _("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"),
426 dev, unit);
375 exit(STATE_UNKNOWN); 427 exit(STATE_UNKNOWN);
376 } 428 }
377 429
@@ -383,7 +435,9 @@ static int get_hardware_address(int sock, char *interface_name) {
383 435
384 stat = mac_addr_dlpi(dev, unit, client_hardware_address); 436 stat = mac_addr_dlpi(dev, unit, client_hardware_address);
385 if (stat != 0) { 437 if (stat != 0) {
386 printf(_("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"), dev, unit); 438 printf(
439 _("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"),
440 dev, unit);
387 exit(STATE_UNKNOWN); 441 exit(STATE_UNKNOWN);
388 } 442 }
389 /* Kompf 2000-2003 */ 443 /* Kompf 2000-2003 */
@@ -393,14 +447,15 @@ static int get_hardware_address(int sock, char *interface_name) {
393 exit(STATE_UNKNOWN); 447 exit(STATE_UNKNOWN);
394#endif 448#endif
395 449
396 if (verbose) 450 if (verbose) {
397 print_hardware_address(client_hardware_address); 451 print_hardware_address(client_hardware_address);
452 }
398 453
399 return OK; 454 return OK;
400} 455}
401 456
402/* determines IP address of the client interface */ 457/* determines IP address of the client interface */
403static int get_ip_address(int sock, char *interface_name) { 458get_ip_address_wrapper get_ip_address(int sock, char *interface_name) {
404#if defined(SIOCGIFADDR) 459#if defined(SIOCGIFADDR)
405 struct ifreq ifr; 460 struct ifreq ifr;
406 461
@@ -412,28 +467,30 @@ static int get_ip_address(int sock, char *interface_name) {
412 exit(STATE_UNKNOWN); 467 exit(STATE_UNKNOWN);
413 } 468 }
414 469
415 my_ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
416
417#else 470#else
418 printf(_("Error: Cannot get interface IP address on this platform.\n")); 471 printf(_("Error: Cannot get interface IP address on this platform.\n"));
419 exit(STATE_UNKNOWN); 472 exit(STATE_UNKNOWN);
420#endif 473#endif
421 474
422 if (verbose) 475 get_ip_address_wrapper result = {
423 printf(_("Pretending to be relay client %s\n"), inet_ntoa(my_ip)); 476 .error = OK,
477 .my_ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr,
478 };
424 479
425 return OK; 480 if (verbose) {
481 printf(_("Pretending to be relay client %s\n"), inet_ntoa(result.my_ip));
482 }
483
484 return result;
426} 485}
427 486
428/* sends a DHCPDISCOVER broadcast message in an attempt to find DHCP servers */ 487/* sends a DHCPDISCOVER broadcast message in an attempt to find DHCP servers */
429static int send_dhcp_discover(int sock) { 488static send_dhcp_discover_wrapper send_dhcp_discover(int sock, bool unicast, struct in_addr dhcp_ip,
430 dhcp_packet discover_packet; 489 struct in_addr requested_address,
431 struct sockaddr_in sockaddr_broadcast; 490 bool request_specific_address,
432 unsigned short opts; 491 struct in_addr my_ip,
433 492 unsigned char *client_hardware_address) {
434 /* clear the packet data structure */ 493 dhcp_packet discover_packet = {0};
435 bzero(&discover_packet, sizeof(discover_packet));
436
437 /* boot request flag (backward compatible with BOOTP servers) */ 494 /* boot request flag (backward compatible with BOOTP servers) */
438 discover_packet.op = BOOTREQUEST; 495 discover_packet.op = BOOTREQUEST;
439 496
@@ -443,12 +500,15 @@ static int send_dhcp_discover(int sock) {
443 /* length of our hardware address */ 500 /* length of our hardware address */
444 discover_packet.hlen = ETHERNET_HARDWARE_ADDRESS_LENGTH; 501 discover_packet.hlen = ETHERNET_HARDWARE_ADDRESS_LENGTH;
445 502
503 send_dhcp_discover_wrapper result = {
504 .error = OK,
505 };
446 /* 506 /*
447 * transaction ID is supposed to be random. 507 * transaction ID is supposed to be random.
448 */ 508 */
449 srand(time(NULL) ^ getpid()); 509 srand(time(NULL) ^ getpid());
450 packet_xid = random(); 510 result.packet_xid = random();
451 discover_packet.xid = htonl(packet_xid); 511 discover_packet.xid = htonl(result.packet_xid);
452 512
453 /*discover_packet.secs=htons(65535);*/ 513 /*discover_packet.secs=htons(65535);*/
454 discover_packet.secs = 0xFF; 514 discover_packet.secs = 0xFF;
@@ -468,10 +528,11 @@ static int send_dhcp_discover(int sock) {
468 discover_packet.options[2] = '\x53'; 528 discover_packet.options[2] = '\x53';
469 discover_packet.options[3] = '\x63'; 529 discover_packet.options[3] = '\x63';
470 530
471 opts = 4; 531 unsigned short opts = 4;
472 /* DHCP message type is embedded in options field */ 532 /* DHCP message type is embedded in options field */
473 discover_packet.options[opts++] = DHCP_OPTION_MESSAGE_TYPE; /* DHCP message type option identifier */ 533 discover_packet.options[opts++] =
474 discover_packet.options[opts++] = '\x01'; /* DHCP message option length in bytes */ 534 DHCP_OPTION_MESSAGE_TYPE; /* DHCP message type option identifier */
535 discover_packet.options[opts++] = '\x01'; /* DHCP message option length in bytes */
475 discover_packet.options[opts++] = DHCPDISCOVER; 536 discover_packet.options[opts++] = DHCPDISCOVER;
476 537
477 /* the IP address we're requesting */ 538 /* the IP address we're requesting */
@@ -484,21 +545,25 @@ static int send_dhcp_discover(int sock) {
484 discover_packet.options[opts++] = (char)DHCP_OPTION_END; 545 discover_packet.options[opts++] = (char)DHCP_OPTION_END;
485 546
486 /* unicast fields */ 547 /* unicast fields */
487 if (unicast) 548 if (unicast) {
488 discover_packet.giaddr.s_addr = my_ip.s_addr; 549 discover_packet.giaddr.s_addr = my_ip.s_addr;
550 }
489 551
490 /* see RFC 1542, 4.1.1 */ 552 /* see RFC 1542, 4.1.1 */
491 discover_packet.hops = unicast ? 1 : 0; 553 discover_packet.hops = unicast ? 1 : 0;
492 554
493 /* send the DHCPDISCOVER packet to broadcast address */ 555 /* send the DHCPDISCOVER packet to broadcast address */
494 sockaddr_broadcast.sin_family = AF_INET; 556 struct sockaddr_in sockaddr_broadcast = {
495 sockaddr_broadcast.sin_port = htons(DHCP_SERVER_PORT); 557 .sin_family = AF_INET,
496 sockaddr_broadcast.sin_addr.s_addr = unicast ? dhcp_ip.s_addr : INADDR_BROADCAST; 558 .sin_port = htons(DHCP_SERVER_PORT),
497 bzero(&sockaddr_broadcast.sin_zero, sizeof(sockaddr_broadcast.sin_zero)); 559 .sin_addr.s_addr = unicast ? dhcp_ip.s_addr : INADDR_BROADCAST,
560 };
498 561
499 if (verbose) { 562 if (verbose) {
500 printf(_("DHCPDISCOVER to %s port %d\n"), inet_ntoa(sockaddr_broadcast.sin_addr), ntohs(sockaddr_broadcast.sin_port)); 563 printf(_("DHCPDISCOVER to %s port %d\n"), inet_ntoa(sockaddr_broadcast.sin_addr),
501 printf("DHCPDISCOVER XID: %u (0x%X)\n", ntohl(discover_packet.xid), ntohl(discover_packet.xid)); 564 ntohs(sockaddr_broadcast.sin_port));
565 printf("DHCPDISCOVER XID: %u (0x%X)\n", ntohl(discover_packet.xid),
566 ntohl(discover_packet.xid));
502 printf("DHCDISCOVER ciaddr: %s\n", inet_ntoa(discover_packet.ciaddr)); 567 printf("DHCDISCOVER ciaddr: %s\n", inet_ntoa(discover_packet.ciaddr));
503 printf("DHCDISCOVER yiaddr: %s\n", inet_ntoa(discover_packet.yiaddr)); 568 printf("DHCDISCOVER yiaddr: %s\n", inet_ntoa(discover_packet.yiaddr));
504 printf("DHCDISCOVER siaddr: %s\n", inet_ntoa(discover_packet.siaddr)); 569 printf("DHCDISCOVER siaddr: %s\n", inet_ntoa(discover_packet.siaddr));
@@ -508,56 +573,58 @@ static int send_dhcp_discover(int sock) {
508 /* send the DHCPDISCOVER packet out */ 573 /* send the DHCPDISCOVER packet out */
509 send_dhcp_packet(&discover_packet, sizeof(discover_packet), sock, &sockaddr_broadcast); 574 send_dhcp_packet(&discover_packet, sizeof(discover_packet), sock, &sockaddr_broadcast);
510 575
511 if (verbose) 576 if (verbose) {
512 printf("\n\n"); 577 printf("\n\n");
578 }
513 579
514 return OK; 580 return result;
515} 581}
516 582
517/* waits for a DHCPOFFER message from one or more DHCP servers */ 583/* waits for a DHCPOFFER message from one or more DHCP servers */
518static int get_dhcp_offer(int sock) { 584get_dhcp_offer_wrapper get_dhcp_offer(int sock, int dhcpoffer_timeout, uint32_t packet_xid,
519 dhcp_packet offer_packet; 585 dhcp_offer *dhcp_offer_list,
520 struct sockaddr_in source; 586 const unsigned char *client_hardware_address) {
521 struct sockaddr_in via;
522 int result = OK;
523 int responses = 0;
524 int x;
525 time_t start_time; 587 time_t start_time;
526 time_t current_time;
527
528 time(&start_time); 588 time(&start_time);
529 589
590 int result = OK;
591 int responses = 0;
592 int valid_responses = 0;
530 /* receive as many responses as we can */ 593 /* receive as many responses as we can */
531 for (responses = 0, valid_responses = 0;;) { 594 for (;;) {
532 595 time_t current_time;
533 time(&current_time); 596 time(&current_time);
534 if ((current_time - start_time) >= dhcpoffer_timeout) 597 if ((current_time - start_time) >= dhcpoffer_timeout) {
535 break; 598 break;
599 }
536 600
537 if (verbose) 601 if (verbose) {
538 printf("\n\n"); 602 printf("\n\n");
603 }
539 604
540 bzero(&source, sizeof(source)); 605 struct sockaddr_in source = {0};
541 bzero(&via, sizeof(via)); 606 dhcp_packet offer_packet = {0};
542 bzero(&offer_packet, sizeof(offer_packet));
543 607
544 result = OK; 608 result = OK;
545 result = receive_dhcp_packet(&offer_packet, sizeof(offer_packet), sock, dhcpoffer_timeout, &source); 609 result = receive_dhcp_packet(&offer_packet, sizeof(offer_packet), sock, dhcpoffer_timeout,
610 &source);
546 611
547 if (result != OK) { 612 if (result != OK) {
548 if (verbose) 613 if (verbose) {
549 printf(_("Result=ERROR\n")); 614 printf(_("Result=ERROR\n"));
615 }
550 616
551 continue; 617 continue;
552 } else { 618 }
553 if (verbose) 619 if (verbose) {
554 printf(_("Result=OK\n")); 620 printf(_("Result=OK\n"));
555
556 responses++;
557 } 621 }
558 622
623 responses++;
624
559 /* The "source" is either a server or a relay. */ 625 /* The "source" is either a server or a relay. */
560 /* Save a copy of "source" into "via" even if it's via itself */ 626 /* Save a copy of "source" into "via" even if it's via itself */
627 struct sockaddr_in via = {0};
561 memcpy(&via, &source, sizeof(source)); 628 memcpy(&via, &source, sizeof(source));
562 629
563 if (verbose) { 630 if (verbose) {
@@ -568,30 +635,38 @@ static int get_dhcp_offer(int sock) {
568 635
569 /* check packet xid to see if its the same as the one we used in the discover packet */ 636 /* check packet xid to see if its the same as the one we used in the discover packet */
570 if (ntohl(offer_packet.xid) != packet_xid) { 637 if (ntohl(offer_packet.xid) != packet_xid) {
571 if (verbose) 638 if (verbose) {
572 printf(_("DHCPOFFER XID (%u) did not match DHCPDISCOVER XID (%u) - ignoring packet\n"), ntohl(offer_packet.xid), packet_xid); 639 printf(
640 _("DHCPOFFER XID (%u) did not match DHCPDISCOVER XID (%u) - ignoring packet\n"),
641 ntohl(offer_packet.xid), packet_xid);
642 }
573 643
574 continue; 644 continue;
575 } 645 }
576 646
577 /* check hardware address */ 647 /* check hardware address */
578 result = OK; 648 result = OK;
579 if (verbose) 649 if (verbose) {
580 printf("DHCPOFFER chaddr: "); 650 printf("DHCPOFFER chaddr: ");
651 }
581 652
582 for (x = 0; x < ETHERNET_HARDWARE_ADDRESS_LENGTH; x++) { 653 for (int i = 0; i < ETHERNET_HARDWARE_ADDRESS_LENGTH; i++) {
583 if (verbose) 654 if (verbose) {
584 printf("%02X", (unsigned char)offer_packet.chaddr[x]); 655 printf("%02X", offer_packet.chaddr[i]);
656 }
585 657
586 if (offer_packet.chaddr[x] != client_hardware_address[x]) 658 if (offer_packet.chaddr[i] != client_hardware_address[i]) {
587 result = ERROR; 659 result = ERROR;
660 }
588 } 661 }
589 if (verbose) 662 if (verbose) {
590 printf("\n"); 663 printf("\n");
664 }
591 665
592 if (result == ERROR) { 666 if (result == ERROR) {
593 if (verbose) 667 if (verbose) {
594 printf(_("DHCPOFFER hardware address did not match our own - ignoring packet\n")); 668 printf(_("DHCPOFFER hardware address did not match our own - ignoring packet\n"));
669 }
595 670
596 continue; 671 continue;
597 } 672 }
@@ -603,7 +678,13 @@ static int get_dhcp_offer(int sock) {
603 printf("DHCPOFFER giaddr: %s\n", inet_ntoa(offer_packet.giaddr)); 678 printf("DHCPOFFER giaddr: %s\n", inet_ntoa(offer_packet.giaddr));
604 } 679 }
605 680
606 add_dhcp_offer(source.sin_addr, &offer_packet); 681 add_dhcp_offer_wrapper add_res =
682 add_dhcp_offer(source.sin_addr, &offer_packet, dhcp_offer_list);
683 if (add_res.error != OK) {
684 // TODO
685 } else {
686 dhcp_offer_list = add_res.dhcp_offer_list;
687 }
607 688
608 valid_responses++; 689 valid_responses++;
609 } 690 }
@@ -613,104 +694,104 @@ static int get_dhcp_offer(int sock) {
613 printf(_("Valid responses for this machine: %d\n"), valid_responses); 694 printf(_("Valid responses for this machine: %d\n"), valid_responses);
614 } 695 }
615 696
616 return OK; 697 get_dhcp_offer_wrapper ret_val = {
698 .error = OK,
699 .valid_responses = valid_responses,
700 .dhcp_offer_list = dhcp_offer_list,
701 };
702 return ret_val;
617} 703}
618 704
619/* sends a DHCP packet */ 705/* sends a DHCP packet */
620static int send_dhcp_packet(void *buffer, int buffer_size, int sock, struct sockaddr_in *dest) { 706int send_dhcp_packet(void *buffer, int buffer_size, int sock, struct sockaddr_in *dest) {
621 int result; 707 int result =
622 708 sendto(sock, (char *)buffer, buffer_size, 0, (struct sockaddr *)dest, sizeof(*dest));
623 result = sendto(sock, (char *)buffer, buffer_size, 0, (struct sockaddr *)dest, sizeof(*dest));
624 709
625 if (verbose) 710 if (verbose) {
626 printf(_("send_dhcp_packet result: %d\n"), result); 711 printf(_("send_dhcp_packet result: %d\n"), result);
712 }
627 713
628 if (result < 0) 714 if (result < 0) {
629 return ERROR; 715 return ERROR;
716 }
630 717
631 return OK; 718 return OK;
632} 719}
633 720
634/* receives a DHCP packet */ 721/* receives a DHCP packet */
635static int receive_dhcp_packet(void *buffer, int buffer_size, int sock, int timeout, struct sockaddr_in *address) { 722int receive_dhcp_packet(void *buffer, int buffer_size, int sock, int timeout,
636 struct timeval tv; 723 struct sockaddr_in *address) {
637 fd_set readfds;
638 fd_set oobfds;
639 int recv_result;
640 socklen_t address_size;
641 struct sockaddr_in source_address;
642 int nfound;
643
644 /* wait for data to arrive (up time timeout) */ 724 /* wait for data to arrive (up time timeout) */
645 tv.tv_sec = timeout; 725 struct timeval timeout_val = {
646 tv.tv_usec = 0; 726 .tv_sec = timeout,
727 .tv_usec = 0,
728 };
729 fd_set readfds;
647 FD_ZERO(&readfds); 730 FD_ZERO(&readfds);
731 fd_set oobfds;
648 FD_ZERO(&oobfds); 732 FD_ZERO(&oobfds);
649 FD_SET(sock, &readfds); 733 FD_SET(sock, &readfds);
650 FD_SET(sock, &oobfds); 734 FD_SET(sock, &oobfds);
651 nfound = select(sock + 1, &readfds, NULL, &oobfds, &tv); 735 int nfound = select(sock + 1, &readfds, NULL, &oobfds, &timeout_val);
652 736
653 /* make sure some data has arrived */ 737 /* make sure some data has arrived */
654 if (!FD_ISSET(sock, &readfds)) { 738 if (!FD_ISSET(sock, &readfds)) {
655 if (verbose) 739 if (verbose) {
656 printf(_("No (more) data received (nfound: %d)\n"), nfound); 740 printf(_("No (more) data received (nfound: %d)\n"), nfound);
741 }
657 return ERROR; 742 return ERROR;
658 } 743 }
659 744
660 else { 745 struct sockaddr_in source_address = {0};
661 bzero(&source_address, sizeof(source_address)); 746 socklen_t address_size = sizeof(source_address);
662 address_size = sizeof(source_address); 747 int recv_result = recvfrom(sock, (char *)buffer, buffer_size, 0,
663 recv_result = recvfrom(sock, (char *)buffer, buffer_size, 0, (struct sockaddr *)&source_address, &address_size); 748 (struct sockaddr *)&source_address, &address_size);
664 if (verbose) 749 if (verbose) {
665 printf("recv_result: %d\n", recv_result); 750 printf("recv_result: %d\n", recv_result);
666 751 }
667 if (recv_result == -1) {
668 if (verbose) {
669 printf(_("recvfrom() failed, "));
670 printf("errno: (%d) -> %s\n", errno, strerror(errno));
671 }
672 return ERROR;
673 } else {
674 if (verbose) {
675 printf(_("receive_dhcp_packet() result: %d\n"), recv_result);
676 printf(_("receive_dhcp_packet() source: %s\n"), inet_ntoa(source_address.sin_addr));
677 }
678 752
679 memcpy(address, &source_address, sizeof(source_address)); 753 if (recv_result == -1) {
680 return OK; 754 if (verbose) {
755 printf(_("recvfrom() failed, "));
756 printf("errno: (%d) -> %s\n", errno, strerror(errno));
681 } 757 }
758 return ERROR;
759 }
760 if (verbose) {
761 printf(_("receive_dhcp_packet() result: %d\n"), recv_result);
762 printf(_("receive_dhcp_packet() source: %s\n"), inet_ntoa(source_address.sin_addr));
682 } 763 }
683 764
765 memcpy(address, &source_address, sizeof(source_address));
684 return OK; 766 return OK;
685} 767}
686 768
687/* creates a socket for DHCP communication */ 769/* creates a socket for DHCP communication */
688static int create_dhcp_socket(void) { 770int create_dhcp_socket(bool unicast, char *network_interface_name) {
689 struct sockaddr_in myname;
690 struct ifreq interface;
691 int sock;
692 int flag = 1;
693
694 /* Set up the address we're going to bind to. */ 771 /* Set up the address we're going to bind to. */
695 bzero(&myname, sizeof(myname));
696 myname.sin_family = AF_INET;
697 /* listen to DHCP server port if we're in unicast mode */ 772 /* listen to DHCP server port if we're in unicast mode */
698 myname.sin_port = htons(unicast ? DHCP_SERVER_PORT : DHCP_CLIENT_PORT); 773 struct sockaddr_in myname = {
699 myname.sin_addr.s_addr = unicast ? my_ip.s_addr : INADDR_ANY; 774 .sin_family = AF_INET,
700 bzero(&myname.sin_zero, sizeof(myname.sin_zero)); 775 .sin_port = htons(unicast ? DHCP_SERVER_PORT : DHCP_CLIENT_PORT),
776 // TODO previously the next line was trying to use our own IP, we was not set
777 // until some point later, so it was removed. Recheck whether it is actually
778 // necessary/useful
779 .sin_addr.s_addr = INADDR_ANY,
780 };
701 781
702 /* create a socket for DHCP communications */ 782 /* create a socket for DHCP communications */
703 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 783 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
704 if (sock < 0) { 784 if (sock < 0) {
705 printf(_("Error: Could not create socket!\n")); 785 printf(_("Error: Could not create socket!\n"));
706 exit(STATE_UNKNOWN); 786 exit(STATE_UNKNOWN);
707 } 787 }
708 788
709 if (verbose) 789 if (verbose) {
710 printf("DHCP socket: %d\n", sock); 790 printf("DHCP socket: %d\n", sock);
791 }
711 792
712 /* set the reuse address flag so we don't get errors when restarting */ 793 /* set the reuse address flag so we don't get errors when restarting */
713 flag = 1; 794 int flag = 1;
714 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(flag)) < 0) { 795 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(flag)) < 0) {
715 printf(_("Error: Could not set reuse address option on DHCP socket!\n")); 796 printf(_("Error: Could not set reuse address option on DHCP socket!\n"));
716 exit(STATE_UNKNOWN); 797 exit(STATE_UNKNOWN);
@@ -722,12 +803,14 @@ static int create_dhcp_socket(void) {
722 exit(STATE_UNKNOWN); 803 exit(STATE_UNKNOWN);
723 } 804 }
724 805
806 struct ifreq interface;
725 /* bind socket to interface */ 807 /* bind socket to interface */
726#if defined(__linux__) 808#if defined(__linux__)
727 strncpy(interface.ifr_ifrn.ifrn_name, network_interface_name, IFNAMSIZ - 1); 809 strncpy(interface.ifr_ifrn.ifrn_name, network_interface_name, IFNAMSIZ - 1);
728 interface.ifr_ifrn.ifrn_name[IFNAMSIZ - 1] = '\0'; 810 interface.ifr_ifrn.ifrn_name[IFNAMSIZ - 1] = '\0';
729 if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)&interface, sizeof(interface)) < 0) { 811 if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)&interface, sizeof(interface)) < 0) {
730 printf(_("Error: Could not bind socket to interface %s. Check your privileges...\n"), network_interface_name); 812 printf(_("Error: Could not bind socket to interface %s. Check your privileges...\n"),
813 network_interface_name);
731 exit(STATE_UNKNOWN); 814 exit(STATE_UNKNOWN);
732 } 815 }
733 816
@@ -738,7 +821,8 @@ static int create_dhcp_socket(void) {
738 821
739 /* bind the socket */ 822 /* bind the socket */
740 if (bind(sock, (struct sockaddr *)&myname, sizeof(myname)) < 0) { 823 if (bind(sock, (struct sockaddr *)&myname, sizeof(myname)) < 0) {
741 printf(_("Error: Could not bind to DHCP socket (port %d)! Check your privileges...\n"), DHCP_CLIENT_PORT); 824 printf(_("Error: Could not bind to DHCP socket (port %d)! Check your privileges...\n"),
825 DHCP_CLIENT_PORT);
742 exit(STATE_UNKNOWN); 826 exit(STATE_UNKNOWN);
743 } 827 }
744 828
@@ -746,105 +830,121 @@ static int create_dhcp_socket(void) {
746} 830}
747 831
748/* closes DHCP socket */ 832/* closes DHCP socket */
749static int close_dhcp_socket(int sock) { 833int close_dhcp_socket(int sock) {
750
751 close(sock); 834 close(sock);
752
753 return OK; 835 return OK;
754} 836}
755 837
756/* adds a requested server address to list in memory */ 838/* adds a requested server address to list in memory */
757static int add_requested_server(struct in_addr server_address) { 839int add_requested_server(struct in_addr server_address, int *requested_servers,
758 requested_server *new_server; 840 requested_server **requested_server_list) {
759 841 requested_server *new_server = (requested_server *)malloc(sizeof(requested_server));
760 new_server = (requested_server *)malloc(sizeof(requested_server)); 842 if (new_server == NULL) {
761 if (new_server == NULL)
762 return ERROR; 843 return ERROR;
844 }
763 845
764 new_server->server_address = server_address; 846 new_server->server_address = server_address;
765 new_server->answered = false; 847 new_server->answered = false;
766 848
767 new_server->next = requested_server_list; 849 new_server->next = *requested_server_list;
768 requested_server_list = new_server; 850 *requested_server_list = new_server;
769 851
770 requested_servers++; 852 *requested_servers += 1;
771 853
772 if (verbose) 854 if (verbose) {
773 printf(_("Requested server address: %s\n"), inet_ntoa(new_server->server_address)); 855 printf(_("Requested server address: %s\n"), inet_ntoa(new_server->server_address));
856 }
774 857
775 return OK; 858 return OK;
776} 859}
777 860
778/* adds a DHCP OFFER to list in memory */ 861/* adds a DHCP OFFER to list in memory */
779static int add_dhcp_offer(struct in_addr source, dhcp_packet *offer_packet) { 862add_dhcp_offer_wrapper add_dhcp_offer(struct in_addr source, dhcp_packet *offer_packet,
863 dhcp_offer *dhcp_offer_list) {
864 if (offer_packet == NULL) {
865 add_dhcp_offer_wrapper tmp = {
866 .error = ERROR,
867 };
868 return tmp;
869 }
870
871 uint32_t dhcp_lease_time = 0;
872 uint32_t dhcp_renewal_time = 0;
873 uint32_t dhcp_rebinding_time = 0;
780 dhcp_offer *new_offer; 874 dhcp_offer *new_offer;
781 int x;
782 unsigned option_type;
783 unsigned option_length;
784 struct in_addr serv_ident = {0}; 875 struct in_addr serv_ident = {0};
785
786 if (offer_packet == NULL)
787 return ERROR;
788
789 /* process all DHCP options present in the packet */ 876 /* process all DHCP options present in the packet */
790 for (x = 4; x < MAX_DHCP_OPTIONS_LENGTH - 1;) { 877 for (int dchp_opt_idx = 4; dchp_opt_idx < MAX_DHCP_OPTIONS_LENGTH - 1;) {
791 878
792 if ((int)offer_packet->options[x] == -1) 879 if ((int)offer_packet->options[dchp_opt_idx] == -1) {
793 break; 880 break;
881 }
794 882
795 /* get option type */ 883 /* get option type */
796 option_type = offer_packet->options[x++]; 884 unsigned option_type = offer_packet->options[dchp_opt_idx++];
797 885
798 /* get option length */ 886 /* get option length */
799 option_length = offer_packet->options[x++]; 887 unsigned option_length = offer_packet->options[dchp_opt_idx++];
800 888
801 if (verbose) 889 if (verbose) {
802 printf("Option: %d (0x%02X)\n", option_type, option_length); 890 printf("Option: %d (0x%02X)\n", option_type, option_length);
891 }
803 892
804 /* get option data */ 893 /* get option data */
805 switch (option_type) { 894 switch (option_type) {
806 case DHCP_OPTION_LEASE_TIME: 895 case DHCP_OPTION_LEASE_TIME:
807 memcpy(&dhcp_lease_time, &offer_packet->options[x], sizeof(dhcp_lease_time)); 896 memcpy(&dhcp_lease_time, &offer_packet->options[dchp_opt_idx], sizeof(dhcp_lease_time));
808 dhcp_lease_time = ntohl(dhcp_lease_time); 897 dhcp_lease_time = ntohl(dhcp_lease_time);
809 break; 898 break;
810 case DHCP_OPTION_RENEWAL_TIME: 899 case DHCP_OPTION_RENEWAL_TIME:
811 memcpy(&dhcp_renewal_time, &offer_packet->options[x], sizeof(dhcp_renewal_time)); 900 memcpy(&dhcp_renewal_time, &offer_packet->options[dchp_opt_idx],
901 sizeof(dhcp_renewal_time));
812 dhcp_renewal_time = ntohl(dhcp_renewal_time); 902 dhcp_renewal_time = ntohl(dhcp_renewal_time);
813 break; 903 break;
814 case DHCP_OPTION_REBINDING_TIME: 904 case DHCP_OPTION_REBINDING_TIME:
815 memcpy(&dhcp_rebinding_time, &offer_packet->options[x], sizeof(dhcp_rebinding_time)); 905 memcpy(&dhcp_rebinding_time, &offer_packet->options[dchp_opt_idx],
906 sizeof(dhcp_rebinding_time));
816 dhcp_rebinding_time = ntohl(dhcp_rebinding_time); 907 dhcp_rebinding_time = ntohl(dhcp_rebinding_time);
817 break; 908 break;
818 case DHCP_OPTION_SERVER_IDENTIFIER: 909 case DHCP_OPTION_SERVER_IDENTIFIER:
819 memcpy(&serv_ident.s_addr, &offer_packet->options[x], sizeof(serv_ident.s_addr)); 910 memcpy(&serv_ident.s_addr, &offer_packet->options[dchp_opt_idx],
911 sizeof(serv_ident.s_addr));
820 break; 912 break;
821 } 913 }
822 914
823 /* skip option data we're ignoring */ 915 /* skip option data we're ignoring */
824 if (option_type == 0) /* "pad" option, see RFC 2132 (3.1) */ 916 if (option_type == 0) { /* "pad" option, see RFC 2132 (3.1) */
825 x += 1; 917 dchp_opt_idx += 1;
826 else 918 } else {
827 x += option_length; 919 dchp_opt_idx += option_length;
920 }
828 } 921 }
829 922
830 if (verbose) { 923 if (verbose) {
831 if (dhcp_lease_time == DHCP_INFINITE_TIME) 924 if (dhcp_lease_time == DHCP_INFINITE_TIME) {
832 printf(_("Lease Time: Infinite\n")); 925 printf(_("Lease Time: Infinite\n"));
833 else 926 } else {
834 printf(_("Lease Time: %lu seconds\n"), (unsigned long)dhcp_lease_time); 927 printf(_("Lease Time: %lu seconds\n"), (unsigned long)dhcp_lease_time);
835 if (dhcp_renewal_time == DHCP_INFINITE_TIME) 928 }
929 if (dhcp_renewal_time == DHCP_INFINITE_TIME) {
836 printf(_("Renewal Time: Infinite\n")); 930 printf(_("Renewal Time: Infinite\n"));
837 else 931 } else {
838 printf(_("Renewal Time: %lu seconds\n"), (unsigned long)dhcp_renewal_time); 932 printf(_("Renewal Time: %lu seconds\n"), (unsigned long)dhcp_renewal_time);
839 if (dhcp_rebinding_time == DHCP_INFINITE_TIME) 933 }
934 if (dhcp_rebinding_time == DHCP_INFINITE_TIME) {
840 printf(_("Rebinding Time: Infinite\n")); 935 printf(_("Rebinding Time: Infinite\n"));
936 }
841 printf(_("Rebinding Time: %lu seconds\n"), (unsigned long)dhcp_rebinding_time); 937 printf(_("Rebinding Time: %lu seconds\n"), (unsigned long)dhcp_rebinding_time);
842 } 938 }
843 939
844 new_offer = (dhcp_offer *)malloc(sizeof(dhcp_offer)); 940 new_offer = (dhcp_offer *)malloc(sizeof(dhcp_offer));
845 941
846 if (new_offer == NULL) 942 if (new_offer == NULL) {
847 return ERROR; 943 add_dhcp_offer_wrapper tmp = {
944 .error = ERROR,
945 };
946 return tmp;
947 }
848 948
849 /* 949 /*
850 * RFC 2131 (2.) says: "DHCP clarifies the interpretation of the 950 * RFC 2131 (2.) says: "DHCP clarifies the interpretation of the
@@ -874,15 +974,18 @@ static int add_dhcp_offer(struct in_addr source, dhcp_packet *offer_packet) {
874 new_offer->next = dhcp_offer_list; 974 new_offer->next = dhcp_offer_list;
875 dhcp_offer_list = new_offer; 975 dhcp_offer_list = new_offer;
876 976
877 return OK; 977 add_dhcp_offer_wrapper result = {
978 .error = OK,
979 .dhcp_offer_list = dhcp_offer_list,
980 };
981
982 return result;
878} 983}
879 984
880/* frees memory allocated to DHCP OFFER list */ 985/* frees memory allocated to DHCP OFFER list */
881static int free_dhcp_offer_list(void) { 986int free_dhcp_offer_list(dhcp_offer *dhcp_offer_list) {
882 dhcp_offer *this_offer;
883 dhcp_offer *next_offer; 987 dhcp_offer *next_offer;
884 988 for (dhcp_offer *this_offer = dhcp_offer_list; this_offer != NULL; this_offer = next_offer) {
885 for (this_offer = dhcp_offer_list; this_offer != NULL; this_offer = next_offer) {
886 next_offer = this_offer->next; 989 next_offer = this_offer->next;
887 free(this_offer); 990 free(this_offer);
888 } 991 }
@@ -891,11 +994,10 @@ static int free_dhcp_offer_list(void) {
891} 994}
892 995
893/* frees memory allocated to requested server list */ 996/* frees memory allocated to requested server list */
894static int free_requested_server_list(void) { 997int free_requested_server_list(requested_server *requested_server_list) {
895 requested_server *this_server;
896 requested_server *next_server; 998 requested_server *next_server;
897 999 for (requested_server *this_server = requested_server_list; this_server != NULL;
898 for (this_server = requested_server_list; this_server != NULL; this_server = next_server) { 1000 this_server = next_server) {
899 next_server = this_server->next; 1001 next_server = this_server->next;
900 free(this_server); 1002 free(this_server);
901 } 1003 }
@@ -904,39 +1006,68 @@ static int free_requested_server_list(void) {
904} 1006}
905 1007
906/* gets state and plugin output to return */ 1008/* gets state and plugin output to return */
907static int get_results(void) { 1009mp_subcheck get_results(bool exclusive, const int requested_servers,
908 dhcp_offer *temp_offer, *undesired_offer = NULL; 1010 const struct in_addr requested_address, bool request_specific_address,
909 requested_server *temp_server; 1011 requested_server *requested_server_list, int valid_responses,
910 int result; 1012 dhcp_offer *dhcp_offer_list) {
911 uint32_t max_lease_time = 0; 1013 mp_subcheck sc_dhcp_results = mp_subcheck_init();
1014 sc_dhcp_results = mp_set_subcheck_default_state(sc_dhcp_results, STATE_OK);
912 1015
913 received_requested_address = false; 1016 /* we didn't receive any DHCPOFFERs */
914 1017 if (dhcp_offer_list == NULL) {
915 /* checks responses from requested servers */ 1018 sc_dhcp_results = mp_set_subcheck_state(sc_dhcp_results, STATE_CRITICAL);
916 requested_responses = 0; 1019 xasprintf(&sc_dhcp_results.output, "%s", "No DHCPOFFERs were received");
917 if (requested_servers > 0) { 1020 return sc_dhcp_results;
1021 }
918 1022
919 for (temp_server = requested_server_list; temp_server != NULL; temp_server = temp_server->next) { 1023 if (valid_responses == 0) {
1024 // No valid responses at all, so early exit here
1025 sc_dhcp_results = mp_set_subcheck_state(sc_dhcp_results, STATE_CRITICAL);
1026 xasprintf(&sc_dhcp_results.output, "No valid responses received");
1027 return sc_dhcp_results;
1028 }
920 1029
921 for (temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) { 1030 if (valid_responses == 1) {
1031 xasprintf(&sc_dhcp_results.output, "Received %d DHCPOFFER", valid_responses);
1032 } else {
1033 xasprintf(&sc_dhcp_results.output, "Received %d DHCPOFFERs", valid_responses);
1034 }
922 1035
1036 bool received_requested_address = false;
1037 dhcp_offer *undesired_offer = NULL;
1038 uint32_t max_lease_time = 0;
1039 /* checks responses from requested servers */
1040 int requested_responses = 0;
1041 if (requested_servers > 0) {
1042 for (requested_server *temp_server = requested_server_list; temp_server != NULL;
1043 temp_server = temp_server->next) {
1044 for (dhcp_offer *temp_offer = dhcp_offer_list; temp_offer != NULL;
1045 temp_offer = temp_offer->next) {
923 /* get max lease time we were offered */ 1046 /* get max lease time we were offered */
924 if (temp_offer->lease_time > max_lease_time || temp_offer->lease_time == DHCP_INFINITE_TIME) 1047 if (temp_offer->lease_time > max_lease_time ||
1048 temp_offer->lease_time == DHCP_INFINITE_TIME) {
925 max_lease_time = temp_offer->lease_time; 1049 max_lease_time = temp_offer->lease_time;
1050 }
926 1051
927 /* see if we got the address we requested */ 1052 /* see if we got the address we requested */
928 if (!memcmp(&requested_address, &temp_offer->offered_address, sizeof(requested_address))) 1053 if (!memcmp(&requested_address, &temp_offer->offered_address,
1054 sizeof(requested_address))) {
929 received_requested_address = true; 1055 received_requested_address = true;
1056 }
930 1057
931 /* see if the servers we wanted a response from talked to us or not */ 1058 /* see if the servers we wanted a response from, talked to us or not */
932 if (!memcmp(&temp_offer->server_address, &temp_server->server_address, sizeof(temp_server->server_address))) { 1059 if (!memcmp(&temp_offer->server_address, &temp_server->server_address,
1060 sizeof(temp_server->server_address))) {
933 if (verbose) { 1061 if (verbose) {
934 printf(_("DHCP Server Match: Offerer=%s"), inet_ntoa(temp_offer->server_address)); 1062 printf(_("DHCP Server Match: Offerer=%s"),
1063 inet_ntoa(temp_offer->server_address));
935 printf(_(" Requested=%s"), inet_ntoa(temp_server->server_address)); 1064 printf(_(" Requested=%s"), inet_ntoa(temp_server->server_address));
936 if (temp_server->answered) 1065 if (temp_server->answered) {
937 printf(_(" (duplicate)")); 1066 printf(_(" (duplicate)"));
1067 }
938 printf(_("\n")); 1068 printf(_("\n"));
939 } 1069 }
1070
940 if (!temp_server->answered) { 1071 if (!temp_server->answered) {
941 requested_responses++; 1072 requested_responses++;
942 temp_server->answered = true; 1073 temp_server->answered = true;
@@ -947,160 +1078,188 @@ static int get_results(void) {
947 } 1078 }
948 1079
949 /* exclusive mode: check for undesired offers */ 1080 /* exclusive mode: check for undesired offers */
950 for (temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) { 1081 for (dhcp_offer *temp_offer = dhcp_offer_list; temp_offer != NULL;
1082 temp_offer = temp_offer->next) {
951 if (!temp_offer->desired) { 1083 if (!temp_offer->desired) {
952 undesired_offer = temp_offer; /* Checks only for the first undesired offer */ 1084 undesired_offer = temp_offer; /* Checks only for the first undesired offer */
953 break; /* no further checks needed */ 1085 break; /* no further checks needed */
954 } 1086 }
955 } 1087 }
956 }
957 1088
958 /* else check and see if we got our requested address from any server */ 1089 mp_subcheck sc_rqust_srvs = mp_subcheck_init();
959 else { 1090 xasprintf(&sc_rqust_srvs.output, "%d of %d requested servers responded",
1091 requested_responses, requested_servers);
960 1092
961 for (temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) { 1093 if (requested_responses == requested_servers) {
1094 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_OK);
1095 } else if (requested_responses == 0) {
1096 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_CRITICAL);
1097 } else if (requested_responses < requested_servers) {
1098 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_WARNING);
1099 } else {
1100 // We received more(!) responses than we asked for?
1101 // This case shouldn't happen, but is here for completion
1102 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_WARNING);
1103 }
1104 mp_add_subcheck_to_subcheck(&sc_dhcp_results, sc_rqust_srvs);
962 1105
1106 } else {
1107 /* else check and see if we got our requested address from any server */
1108 for (dhcp_offer *temp_offer = dhcp_offer_list; temp_offer != NULL;
1109 temp_offer = temp_offer->next) {
963 /* get max lease time we were offered */ 1110 /* get max lease time we were offered */
964 if (temp_offer->lease_time > max_lease_time || temp_offer->lease_time == DHCP_INFINITE_TIME) 1111 if (temp_offer->lease_time > max_lease_time ||
1112 temp_offer->lease_time == DHCP_INFINITE_TIME) {
965 max_lease_time = temp_offer->lease_time; 1113 max_lease_time = temp_offer->lease_time;
1114 }
966 1115
967 /* see if we got the address we requested */ 1116 /* see if we got the address we requested */
968 if (!memcmp(&requested_address, &temp_offer->offered_address, sizeof(requested_address))) 1117 if (!memcmp(&requested_address, &temp_offer->offered_address,
1118 sizeof(requested_address))) {
969 received_requested_address = true; 1119 received_requested_address = true;
1120 }
970 } 1121 }
971 } 1122 }
972 1123
973 result = STATE_OK; 1124 if (max_lease_time == DHCP_INFINITE_TIME) {
974 if (valid_responses == 0) 1125 xasprintf(&sc_dhcp_results.output, "%s, max lease time = Infinity", sc_dhcp_results.output);
975 result = STATE_CRITICAL; 1126 } else {
976 else if (requested_servers > 0 && requested_responses == 0) 1127 xasprintf(&sc_dhcp_results.output, "%s, max lease time = %" PRIu32 " seconds",
977 result = STATE_CRITICAL; 1128 sc_dhcp_results.output, max_lease_time);
978 else if (requested_responses < requested_servers)
979 result = STATE_WARNING;
980 else if (request_specific_address && !received_requested_address)
981 result = STATE_WARNING;
982
983 if (exclusive && undesired_offer)
984 result = STATE_CRITICAL;
985
986 if (result == 0) /* garrett honeycutt 2005 */
987 printf("OK: ");
988 else if (result == 1)
989 printf("WARNING: ");
990 else if (result == 2)
991 printf("CRITICAL: ");
992 else if (result == 3)
993 printf("UNKNOWN: ");
994
995 /* we didn't receive any DHCPOFFERs */
996 if (dhcp_offer_list == NULL) {
997 printf(_("No DHCPOFFERs were received.\n"));
998 return result;
999 } 1129 }
1000 1130
1001 printf(_("Received %d DHCPOFFER(s)"), valid_responses); 1131 if (exclusive) {
1132 mp_subcheck sc_rogue_server = mp_subcheck_init();
1002 1133
1003 if (exclusive && undesired_offer) { 1134 if (undesired_offer != NULL) {
1004 printf(_(", Rogue DHCP Server detected! Server %s"), inet_ntoa(undesired_offer->server_address)); 1135 // We wanted to get a DHCPOFFER exclusively from one machine, but another one
1005 printf(_(" offered %s \n"), inet_ntoa(undesired_offer->offered_address)); 1136 // sent one (too)
1006 return result; 1137 sc_rogue_server = mp_set_subcheck_state(sc_rogue_server, STATE_CRITICAL);
1007 }
1008 1138
1009 if (requested_servers > 0) 1139 // Get the addresses for printout
1010 printf(_(", %s%d of %d requested servers responded"), ((requested_responses < requested_servers) && requested_responses > 0) ? "only " : "", requested_responses, 1140 // 1.address of the sending server
1011 requested_servers); 1141 char server_address[INET_ADDRSTRLEN];
1142 const char *server_address_transformed = inet_ntop(
1143 AF_INET, &undesired_offer->server_address, server_address, sizeof(server_address));
1012 1144
1013 if (request_specific_address) 1145 if (server_address != server_address_transformed) {
1014 printf(_(", requested address (%s) was %soffered"), inet_ntoa(requested_address), (received_requested_address) ? "" : _("not ")); 1146 die(STATE_UNKNOWN, "inet_ntop failed");
1147 }
1015 1148
1016 printf(_(", max lease time = ")); 1149 // 2.address offered
1017 if (max_lease_time == DHCP_INFINITE_TIME) 1150 char offered_address[INET_ADDRSTRLEN];
1018 printf(_("Infinity")); 1151 const char *offered_address_transformed =
1019 else 1152 inet_ntop(AF_INET, &undesired_offer->offered_address, offered_address,
1020 printf("%lu sec", (unsigned long)max_lease_time); 1153 sizeof(offered_address));
1021 1154
1022 printf(".\n"); 1155 if (offered_address != offered_address_transformed) {
1156 die(STATE_UNKNOWN, "inet_ntop failed");
1157 }
1023 1158
1024 return result; 1159 xasprintf(&sc_rogue_server.output, "Rogue DHCP Server detected! Server %s offered %s",
1160 server_address, offered_address);
1161 } else {
1162 sc_rogue_server = mp_set_subcheck_state(sc_rogue_server, STATE_OK);
1163 xasprintf(&sc_rogue_server.output, "No Rogue DHCP Server detected");
1164 }
1165 mp_add_subcheck_to_subcheck(&sc_dhcp_results, sc_rogue_server);
1166 }
1167
1168 if (request_specific_address) {
1169 mp_subcheck sc_rqustd_addr = mp_subcheck_init();
1170
1171 if (received_requested_address) {
1172 sc_rqustd_addr = mp_set_subcheck_state(sc_rqustd_addr, STATE_OK);
1173 xasprintf(&sc_rqustd_addr.output, "Requested address (%s) was offered",
1174 inet_ntoa(requested_address));
1175 } else {
1176 sc_rqustd_addr = mp_set_subcheck_state(sc_rqustd_addr, STATE_WARNING);
1177 xasprintf(&sc_rqustd_addr.output, "Requested address (%s) was NOT offered",
1178 inet_ntoa(requested_address));
1179 }
1180
1181 mp_add_subcheck_to_subcheck(&sc_dhcp_results, sc_rqustd_addr);
1182 }
1183
1184 return sc_dhcp_results;
1025} 1185}
1026 1186
1027/* process command-line arguments */ 1187/* process command-line arguments */
1028static int process_arguments(int argc, char **argv) { 1188process_arguments_wrapper process_arguments(int argc, char **argv) {
1029 if (argc < 1) 1189 if (argc < 1) {
1030 return ERROR; 1190 process_arguments_wrapper tmp = {
1191 .error = ERROR,
1192 };
1193 return tmp;
1194 }
1031 1195
1032 call_getopt(argc, argv); 1196 enum {
1033 return validate_arguments(argc); 1197 output_format_index = CHAR_MAX + 1,
1034} 1198 };
1035 1199
1036static int call_getopt(int argc, char **argv) {
1037 extern int optind;
1038 int option_index = 0; 1200 int option_index = 0;
1039 static struct option long_options[] = {{"serverip", required_argument, 0, 's'}, 1201 static struct option long_options[] = {
1040 {"requestedip", required_argument, 0, 'r'}, 1202 {"serverip", required_argument, 0, 's'},
1041 {"timeout", required_argument, 0, 't'}, 1203 {"requestedip", required_argument, 0, 'r'},
1042 {"interface", required_argument, 0, 'i'}, 1204 {"timeout", required_argument, 0, 't'},
1043 {"mac", required_argument, 0, 'm'}, 1205 {"interface", required_argument, 0, 'i'},
1044 {"unicast", no_argument, 0, 'u'}, 1206 {"mac", required_argument, 0, 'm'},
1045 {"exclusive", no_argument, 0, 'x'}, 1207 {"unicast", no_argument, 0, 'u'},
1046 {"verbose", no_argument, 0, 'v'}, 1208 {"exclusive", no_argument, 0, 'x'},
1047 {"version", no_argument, 0, 'V'}, 1209 {"verbose", no_argument, 0, 'v'},
1048 {"help", no_argument, 0, 'h'}, 1210 {"version", no_argument, 0, 'V'},
1049 {0, 0, 0, 0}}; 1211 {"help", no_argument, 0, 'h'},
1050 1212 {"output-format", required_argument, 0, output_format_index},
1051 int c = 0; 1213 {0, 0, 0, 0}};
1214
1215 check_dhcp_config config = check_dhcp_config_init();
1216 int option_char = 0;
1052 while (true) { 1217 while (true) {
1053 c = getopt_long(argc, argv, "+hVvxt:s:r:t:i:m:u", long_options, &option_index); 1218 option_char = getopt_long(argc, argv, "+hVvxt:s:r:t:i:m:u", long_options, &option_index);
1054 1219
1055 if (c == -1 || c == EOF || c == 1) 1220 if (option_char == -1 || option_char == EOF || option_char == 1) {
1056 break; 1221 break;
1222 }
1057 1223
1058 switch (c) { 1224 switch (option_char) {
1059
1060 case 's': /* DHCP server address */ 1225 case 's': /* DHCP server address */
1061 resolve_host(optarg, &dhcp_ip); 1226 resolve_host(optarg, &config.dhcp_ip);
1062 add_requested_server(dhcp_ip); 1227 add_requested_server(config.dhcp_ip, &config.num_of_requested_servers,
1228 &config.requested_server_list);
1063 break; 1229 break;
1064 1230
1065 case 'r': /* address we are requested from DHCP servers */ 1231 case 'r': /* address we are requested from DHCP servers */
1066 resolve_host(optarg, &requested_address); 1232 resolve_host(optarg, &config.requested_address);
1067 request_specific_address = true; 1233 config.request_specific_address = true;
1068 break; 1234 break;
1069 1235
1070 case 't': /* timeout */ 1236 case 't': /* timeout */
1071 1237 if (atoi(optarg) > 0) {
1072 /* 1238 config.dhcpoffer_timeout = atoi(optarg);
1073 if(is_intnonneg(optarg)) 1239 }
1074 */
1075 if (atoi(optarg) > 0)
1076 dhcpoffer_timeout = atoi(optarg);
1077 /*
1078 else
1079 usage("Time interval must be a nonnegative integer\n");
1080 */
1081 break; 1240 break;
1082 1241
1083 case 'm': /* MAC address */ 1242 case 'm': /* MAC address */
1084 1243 if ((config.user_specified_mac = mac_aton(optarg)) == NULL) {
1085 if ((user_specified_mac = mac_aton(optarg)) == NULL)
1086 usage("Cannot parse MAC address.\n"); 1244 usage("Cannot parse MAC address.\n");
1087 if (verbose) 1245 }
1088 print_hardware_address(user_specified_mac); 1246 if (verbose) {
1089 1247 print_hardware_address(config.user_specified_mac);
1248 }
1090 break; 1249 break;
1091 1250
1092 case 'i': /* interface name */ 1251 case 'i': /* interface name */
1093 1252 strncpy(config.network_interface_name, optarg,
1094 strncpy(network_interface_name, optarg, sizeof(network_interface_name) - 1); 1253 sizeof(config.network_interface_name) - 1);
1095 network_interface_name[sizeof(network_interface_name) - 1] = '\x0'; 1254 config.network_interface_name[sizeof(config.network_interface_name) - 1] = '\x0';
1096
1097 break; 1255 break;
1098 1256
1099 case 'u': /* unicast testing */ 1257 case 'u': /* unicast testing */
1100 unicast = true; 1258 config.unicast_mode = true;
1101 break; 1259 break;
1260
1102 case 'x': /* exclusive testing aka "rogue DHCP server detection" */ 1261 case 'x': /* exclusive testing aka "rogue DHCP server detection" */
1103 exclusive = true; 1262 config.exclusive_mode = true;
1104 break; 1263 break;
1105 1264
1106 case 'V': /* version */ 1265 case 'V': /* version */
@@ -1114,6 +1273,18 @@ static int call_getopt(int argc, char **argv) {
1114 case 'v': /* verbose */ 1273 case 'v': /* verbose */
1115 verbose = 1; 1274 verbose = 1;
1116 break; 1275 break;
1276 case output_format_index: {
1277 parsed_output_format parser = mp_parse_output_format(optarg);
1278 if (!parser.parsing_success) {
1279 // TODO List all available formats here, maybe add anothoer usage function
1280 printf("Invalid output format: %s\n", optarg);
1281 exit(STATE_UNKNOWN);
1282 }
1283
1284 config.output_format_is_set = true;
1285 config.output_format = parser.output_format;
1286 break;
1287 }
1117 case '?': /* help */ 1288 case '?': /* help */
1118 usage5(); 1289 usage5();
1119 break; 1290 break;
@@ -1122,15 +1293,16 @@ static int call_getopt(int argc, char **argv) {
1122 break; 1293 break;
1123 } 1294 }
1124 } 1295 }
1125 return optind;
1126}
1127 1296
1128static int validate_arguments(int argc) { 1297 if (argc - optind > 0) {
1129
1130 if (argc - optind > 0)
1131 usage(_("Got unexpected non-option argument")); 1298 usage(_("Got unexpected non-option argument"));
1299 }
1132 1300
1133 return OK; 1301 process_arguments_wrapper result = {
1302 .config = config,
1303 .error = OK,
1304 };
1305 return result;
1134} 1306}
1135 1307
1136#if defined(__sun__) || defined(__solaris__) || defined(__hpux__) 1308#if defined(__sun__) || defined(__solaris__) || defined(__hpux__)
@@ -1180,7 +1352,8 @@ static int put_ctrl(int fd, int len, int pri) {
1180 1352
1181 ctl.len = len; 1353 ctl.len = len;
1182 if (putmsg(fd, &ctl, 0, pri) < 0) { 1354 if (putmsg(fd, &ctl, 0, pri) < 0) {
1183 printf(_("Error: DLPI stream API failed to get MAC in put_ctrl/putmsg(): %s.\n"), strerror(errno)); 1355 printf(_("Error: DLPI stream API failed to get MAC in put_ctrl/putmsg(): %s.\n"),
1356 strerror(errno));
1184 exit(STATE_UNKNOWN); 1357 exit(STATE_UNKNOWN);
1185 } 1358 }
1186 1359
@@ -1193,7 +1366,8 @@ static int put_both(int fd, int clen, int dlen, int pri) {
1193 ctl.len = clen; 1366 ctl.len = clen;
1194 dat.len = dlen; 1367 dat.len = dlen;
1195 if (putmsg(fd, &ctl, &dat, pri) < 0) { 1368 if (putmsg(fd, &ctl, &dat, pri) < 0) {
1196 printf(_("Error: DLPI stream API failed to get MAC in put_both/putmsg().\n"), strerror(errno)); 1369 printf(_("Error: DLPI stream API failed to get MAC in put_both/putmsg().\n"),
1370 strerror(errno));
1197 exit(STATE_UNKNOWN); 1371 exit(STATE_UNKNOWN);
1198 } 1372 }
1199 1373
@@ -1205,7 +1379,8 @@ static int dl_open(const char *dev, int unit, int *fd) {
1205 dl_attach_req_t *attach_req = (dl_attach_req_t *)ctl_area; 1379 dl_attach_req_t *attach_req = (dl_attach_req_t *)ctl_area;
1206 1380
1207 if ((*fd = open(dev, O_RDWR)) == -1) { 1381 if ((*fd = open(dev, O_RDWR)) == -1) {
1208 printf(_("Error: DLPI stream API failed to get MAC in dl_attach_req/open(%s..): %s.\n"), dev, strerror(errno)); 1382 printf(_("Error: DLPI stream API failed to get MAC in dl_attach_req/open(%s..): %s.\n"),
1383 dev, strerror(errno));
1209 exit(STATE_UNKNOWN); 1384 exit(STATE_UNKNOWN);
1210 } 1385 }
1211 attach_req->dl_primitive = DL_ATTACH_REQ; 1386 attach_req->dl_primitive = DL_ATTACH_REQ;
@@ -1229,7 +1404,8 @@ static int dl_bind(int fd, int sap, u_char *addr) {
1229 put_ctrl(fd, sizeof(dl_bind_req_t), 0); 1404 put_ctrl(fd, sizeof(dl_bind_req_t), 0);
1230 get_msg(fd); 1405 get_msg(fd);
1231 if (GOT_ERR == check_ctrl(DL_BIND_ACK)) { 1406 if (GOT_ERR == check_ctrl(DL_BIND_ACK)) {
1232 printf(_("Error: DLPI stream API failed to get MAC in dl_bind/check_ctrl(): %s.\n"), strerror(errno)); 1407 printf(_("Error: DLPI stream API failed to get MAC in dl_bind/check_ctrl(): %s.\n"),
1408 strerror(errno));
1233 exit(STATE_UNKNOWN); 1409 exit(STATE_UNKNOWN);
1234 } 1410 }
1235 bcopy((u_char *)bind_ack + bind_ack->dl_addr_offset, addr, bind_ack->dl_addr_length); 1411 bcopy((u_char *)bind_ack + bind_ack->dl_addr_offset, addr, bind_ack->dl_addr_length);
@@ -1249,7 +1425,7 @@ static int dl_bind(int fd, int sap, u_char *addr) {
1249 * 1425 *
1250 ***********************************************************************/ 1426 ***********************************************************************/
1251 1427
1252static long mac_addr_dlpi(const char *dev, int unit, u_char *addr) { 1428long mac_addr_dlpi(const char *dev, int unit, u_char *addr) {
1253 int fd; 1429 int fd;
1254 u_char mac_addr[25]; 1430 u_char mac_addr[25];
1255 1431
@@ -1268,51 +1444,53 @@ static long mac_addr_dlpi(const char *dev, int unit, u_char *addr) {
1268#endif 1444#endif
1269 1445
1270/* resolve host name or die (TODO: move this to netutils.c!) */ 1446/* resolve host name or die (TODO: move this to netutils.c!) */
1271static void resolve_host(const char *in, struct in_addr *out) { 1447void resolve_host(const char *name, struct in_addr *out) {
1272 struct addrinfo hints, *ai; 1448 struct addrinfo hints = {
1449 .ai_family = PF_INET,
1450 };
1451 struct addrinfo *addr_info;
1273 1452
1274 memset(&hints, 0, sizeof(hints)); 1453 if (getaddrinfo(name, NULL, &hints, &addr_info) != 0) {
1275 hints.ai_family = PF_INET;
1276 if (getaddrinfo(in, NULL, &hints, &ai) != 0)
1277 usage_va(_("Invalid hostname/address - %s"), optarg); 1454 usage_va(_("Invalid hostname/address - %s"), optarg);
1455 }
1278 1456
1279 memcpy(out, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, sizeof(*out)); 1457 memcpy(out, &((struct sockaddr_in *)addr_info->ai_addr)->sin_addr, sizeof(*out));
1280 freeaddrinfo(ai); 1458 freeaddrinfo(addr_info);
1281} 1459}
1282 1460
1283/* parse MAC address string, return 6 bytes (unterminated) or NULL */ 1461/* parse MAC address string, return 6 bytes (unterminated) or NULL */
1284static unsigned char *mac_aton(const char *string) { 1462unsigned char *mac_aton(const char *string) {
1285 static unsigned char result[6]; 1463 static unsigned char result[MAC_ADDR_LEN];
1286 char tmp[3]; 1464 char tmp[3];
1287 unsigned i, j; 1465 unsigned byte_counter = 0;
1288 1466
1289 for (i = 0, j = 0; string[i] != '\0' && j < sizeof(result); i++) { 1467 for (int i = 0; string[i] != '\0' && byte_counter < sizeof(result); i++) {
1290 /* ignore ':' and any other non-hex character */ 1468 /* ignore ':' and any other non-hex character */
1291 if (!isxdigit(string[i]) || !isxdigit(string[i + 1])) 1469 if (!isxdigit(string[i]) || !isxdigit(string[i + 1])) {
1292 continue; 1470 continue;
1471 }
1293 tmp[0] = string[i]; 1472 tmp[0] = string[i];
1294 tmp[1] = string[i + 1]; 1473 tmp[1] = string[i + 1];
1295 tmp[2] = '\0'; 1474 tmp[2] = '\0';
1296 result[j] = strtol(tmp, (char **)NULL, 16); 1475 result[byte_counter] = strtol(tmp, (char **)NULL, 16);
1297 i++; 1476 i++;
1298 j++; 1477 byte_counter++;
1299 } 1478 }
1300 1479
1301 return (j == 6) ? result : NULL; 1480 return (byte_counter == MAC_ADDR_LEN) ? result : NULL;
1302} 1481}
1303 1482
1304static void print_hardware_address(const unsigned char *address) { 1483void print_hardware_address(const unsigned char *address) {
1305 int i;
1306 1484
1307 printf(_("Hardware address: ")); 1485 printf(_("Hardware address: "));
1308 for (i = 0; i < 5; i++) 1486 for (int addr_idx = 0; addr_idx < MAC_ADDR_LEN; addr_idx++) {
1309 printf("%2.2x:", address[i]); 1487 printf("%2.2x:", address[addr_idx]);
1310 printf("%2.2x", address[i]); 1488 }
1311 putchar('\n'); 1489 putchar('\n');
1312} 1490}
1313 1491
1314/* print usage help */ 1492/* print usage help */
1315static void print_help(void) { 1493void print_help(void) {
1316 1494
1317 print_revision(progname, NP_VERSION); 1495 print_revision(progname, NP_VERSION);
1318 1496
@@ -1328,6 +1506,7 @@ static void print_help(void) {
1328 printf(UT_HELP_VRSN); 1506 printf(UT_HELP_VRSN);
1329 printf(UT_EXTRA_OPTS); 1507 printf(UT_EXTRA_OPTS);
1330 1508
1509 printf(UT_OUTPUT_FORMAT);
1331 printf(UT_VERBOSE); 1510 printf(UT_VERBOSE);
1332 1511
1333 printf(" %s\n", "-s, --serverip=IPADDRESS"); 1512 printf(" %s\n", "-s, --serverip=IPADDRESS");
@@ -1343,10 +1522,10 @@ static void print_help(void) {
1343 printf(" %s\n", "-u, --unicast"); 1522 printf(" %s\n", "-u, --unicast");
1344 printf(" %s\n", _("Unicast testing: mimic a DHCP relay, requires -s")); 1523 printf(" %s\n", _("Unicast testing: mimic a DHCP relay, requires -s"));
1345 printf(" %s\n", "-x, --exclusive"); 1524 printf(" %s\n", "-x, --exclusive");
1346 printf(" %s\n", _("Only requested DHCP server may response (rogue DHCP server detection), requires -s")); 1525 printf(" %s\n",
1526 _("Only requested DHCP server may response (rogue DHCP server detection), requires -s"));
1347 1527
1348 printf(UT_SUPPORT); 1528 printf(UT_SUPPORT);
1349 return;
1350} 1529}
1351 1530
1352void print_usage(void) { 1531void print_usage(void) {
@@ -1354,6 +1533,4 @@ void print_usage(void) {
1354 printf("%s\n", _("Usage:")); 1533 printf("%s\n", _("Usage:"));
1355 printf(" %s [-v] [-u] [-x] [-s serverip] [-r requestedip] [-t timeout]\n", progname); 1534 printf(" %s [-v] [-u] [-x] [-s serverip] [-r requestedip] [-t timeout]\n", progname);
1356 printf(" [-i interface] [-m mac]\n"); 1535 printf(" [-i interface] [-m mac]\n");
1357
1358 return;
1359} 1536}
diff --git a/plugins-root/check_dhcp.d/config.h b/plugins-root/check_dhcp.d/config.h
new file mode 100644
index 00000000..f189068b
--- /dev/null
+++ b/plugins-root/check_dhcp.d/config.h
@@ -0,0 +1,50 @@
1#pragma once
2
3#include "../../config.h"
4#include "../lib/states.h"
5#include <stdbool.h>
6#include <netinet/in.h>
7#include "net/if.h"
8#include "output.h"
9
10typedef struct requested_server_struct {
11 struct in_addr server_address;
12 bool answered;
13 struct requested_server_struct *next;
14} requested_server;
15
16typedef struct check_dhcp_config {
17 bool unicast_mode; /* unicast mode: mimic a DHCP relay */
18 bool exclusive_mode; /* exclusive mode aka "rogue DHCP server detection" */
19 int num_of_requested_servers;
20 struct in_addr dhcp_ip; /* server to query (if in unicast mode) */
21 struct in_addr requested_address;
22 bool request_specific_address;
23
24 int dhcpoffer_timeout;
25 unsigned char *user_specified_mac;
26 char network_interface_name[IFNAMSIZ];
27 requested_server *requested_server_list;
28
29 mp_output_format output_format;
30 bool output_format_is_set;
31} check_dhcp_config;
32
33check_dhcp_config check_dhcp_config_init(void) {
34 check_dhcp_config tmp = {
35 .unicast_mode = false,
36 .exclusive_mode = false,
37 .num_of_requested_servers = 0,
38 .dhcp_ip = {0},
39 .requested_address = {0},
40 .request_specific_address = false,
41
42 .dhcpoffer_timeout = 2,
43 .user_specified_mac = NULL,
44 .network_interface_name = "eth0",
45 .requested_server_list = NULL,
46
47 .output_format_is_set = false,
48 };
49 return tmp;
50}
diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c
index dcaceddb..35cae3ed 100644
--- a/plugins-root/check_icmp.c
+++ b/plugins-root/check_icmp.c
@@ -46,12 +46,17 @@ const char *email = "devel@monitoring-plugins.org";
46#include "../plugins/common.h" 46#include "../plugins/common.h"
47#include "netutils.h" 47#include "netutils.h"
48#include "utils.h" 48#include "utils.h"
49#include "output.h"
50#include "perfdata.h"
49 51
50#if HAVE_SYS_SOCKIO_H 52#if HAVE_SYS_SOCKIO_H
51# include <sys/sockio.h> 53# include <sys/sockio.h>
52#endif 54#endif
53 55
54#include <sys/time.h> 56#include <sys/time.h>
57#if defined(SIOCGIFADDR)
58#include <sys/ioctl.h>
59#endif /* SIOCGIFADDR */
55#include <errno.h> 60#include <errno.h>
56#include <signal.h> 61#include <signal.h>
57#include <ctype.h> 62#include <ctype.h>
@@ -65,6 +70,17 @@ const char *email = "devel@monitoring-plugins.org";
65#include <netinet/icmp6.h> 70#include <netinet/icmp6.h>
66#include <arpa/inet.h> 71#include <arpa/inet.h>
67#include <math.h> 72#include <math.h>
73#include <netdb.h>
74#include <sys/types.h>
75#include <unistd.h>
76#include <stdint.h>
77#include <sys/socket.h>
78#include <assert.h>
79#include <sys/select.h>
80
81#include "../lib/states.h"
82#include "./check_icmp.d/config.h"
83#include "./check_icmp.d/check_icmp_helpers.h"
68 84
69/** sometimes undefined system macros (quite a few, actually) **/ 85/** sometimes undefined system macros (quite a few, actually) **/
70#ifndef MAXTTL 86#ifndef MAXTTL
@@ -96,56 +112,8 @@ const char *email = "devel@monitoring-plugins.org";
96# define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 112# define ICMP_UNREACH_PRECEDENCE_CUTOFF 15
97#endif 113#endif
98 114
99typedef unsigned short range_t; /* type for get_range() -- unimplemented */
100
101typedef struct rta_host {
102 unsigned short id; /* id in **table, and icmp pkts */
103 char *name; /* arg used for adding this host */
104 char *msg; /* icmp error message, if any */
105 struct sockaddr_storage saddr_in; /* the address of this host */
106 struct sockaddr_storage error_addr; /* stores address of error replies */
107 unsigned long long time_waited; /* total time waited, in usecs */
108 unsigned int icmp_sent, icmp_recv, icmp_lost; /* counters */
109 unsigned char icmp_type, icmp_code; /* type and code from errors */
110 unsigned short flags; /* control/status flags */
111 double rta; /* measured RTA */
112 int rta_status; // check result for RTA checks
113 double rtmax; /* max rtt */
114 double rtmin; /* min rtt */
115 double jitter; /* measured jitter */
116 int jitter_status; // check result for Jitter checks
117 double jitter_max; /* jitter rtt maximum */
118 double jitter_min; /* jitter rtt minimum */
119 double EffectiveLatency;
120 double mos; /* Mean opnion score */
121 int mos_status; // check result for MOS checks
122 double score; /* score */
123 int score_status; // check result for score checks
124 u_int last_tdiff;
125 u_int last_icmp_seq; /* Last ICMP_SEQ to check out of order pkts */
126 unsigned char pl; /* measured packet loss */
127 int pl_status; // check result for packet loss checks
128 struct rta_host *next; /* linked list */
129 int order_status; // check result for packet order checks
130} rta_host;
131
132#define FLAG_LOST_CAUSE 0x01 /* decidedly dead target. */ 115#define FLAG_LOST_CAUSE 0x01 /* decidedly dead target. */
133 116
134/* threshold structure. all values are maximum allowed, exclusive */
135typedef struct threshold {
136 unsigned char pl; /* max allowed packet loss in percent */
137 unsigned int rta; /* roundtrip time average, microseconds */
138 double jitter; /* jitter time average, microseconds */
139 double mos; /* MOS */
140 double score; /* Score */
141} threshold;
142
143/* the data structure */
144typedef struct icmp_ping_data {
145 struct timeval stime; /* timestamp (saved in protocol struct as well) */
146 unsigned short ping_id;
147} icmp_ping_data;
148
149typedef union ip_hdr { 117typedef union ip_hdr {
150 struct ip ip; 118 struct ip ip;
151 struct ip6_hdr ip6; 119 struct ip6_hdr ip6;
@@ -158,24 +126,6 @@ typedef union icmp_packet {
158 u_short *cksum_in; 126 u_short *cksum_in;
159} icmp_packet; 127} icmp_packet;
160 128
161/* the different modes of this program are as follows:
162 * MODE_RTA: send all packets no matter what (mimic check_icmp and check_ping)
163 * MODE_HOSTCHECK: Return immediately upon any sign of life
164 * In addition, sends packets to ALL addresses assigned
165 * to this host (as returned by gethostbyname() or
166 * gethostbyaddr() and expects one host only to be checked at
167 * a time. Therefore, any packet response what so ever will
168 * count as a sign of life, even when received outside
169 * crit.rta limit. Do not misspell any additional IP's.
170 * MODE_ALL: Requires packets from ALL requested IP to return OK (default).
171 * MODE_ICMP: implement something similar to check_icmp (MODE_RTA without
172 * tcp and udp args does this)
173 */
174#define MODE_RTA 0
175#define MODE_HOSTCHECK 1
176#define MODE_ALL 2
177#define MODE_ICMP 3
178
179enum enum_threshold_mode { 129enum enum_threshold_mode {
180 const_rta_mode, 130 const_rta_mode,
181 const_packet_loss_mode, 131 const_packet_loss_mode,
@@ -186,89 +136,487 @@ enum enum_threshold_mode {
186 136
187typedef enum enum_threshold_mode threshold_mode; 137typedef enum enum_threshold_mode threshold_mode;
188 138
189/* the different ping types we can do
190 * TODO: investigate ARP ping as well */
191#define HAVE_ICMP 1
192#define HAVE_UDP 2
193#define HAVE_TCP 4
194#define HAVE_ARP 8
195
196#define MIN_PING_DATA_SIZE sizeof(struct icmp_ping_data)
197#define MAX_IP_PKT_SIZE 65536 /* (theoretical) max IP packet size */
198#define IP_HDR_SIZE 20
199#define MAX_PING_DATA (MAX_IP_PKT_SIZE - IP_HDR_SIZE - ICMP_MINLEN)
200#define DEFAULT_PING_DATA_SIZE (MIN_PING_DATA_SIZE + 44)
201
202/* various target states */
203#define TSTATE_INACTIVE 0x01 /* don't ping this host anymore */
204#define TSTATE_WAITING 0x02 /* unanswered packets on the wire */
205#define TSTATE_ALIVE 0x04 /* target is alive (has answered something) */
206#define TSTATE_UNREACH 0x08
207
208/** prototypes **/ 139/** prototypes **/
209void print_help(void); 140void print_help();
210void print_usage(void); 141void print_usage(void);
211static u_int get_timevar(const char *); 142
212static u_int get_timevaldiff(struct timeval *, struct timeval *); 143/* Time related */
213static in_addr_t get_ip_address(const char *); 144typedef struct {
214static int wait_for_reply(int, u_int); 145 int error_code;
215static int recvfrom_wto(int, void *, unsigned int, struct sockaddr *, u_int *, struct timeval *); 146 time_t time_range;
216static int send_icmp_ping(int, struct rta_host *); 147} get_timevar_wrapper;
217static int get_threshold(char *str, threshold *th); 148static get_timevar_wrapper get_timevar(const char *str);
218static bool get_threshold2(char *str, size_t length, threshold *, threshold *, threshold_mode mode); 149static time_t get_timevaldiff(struct timeval earlier, struct timeval later);
219static bool parse_threshold2_helper(char *s, size_t length, threshold *thr, threshold_mode mode); 150static time_t get_timevaldiff_to_now(struct timeval earlier);
220static void run_checks(void); 151
221static void set_source_ip(char *); 152static in_addr_t get_ip_address(const char *ifname, const int icmp_sock);
222static int add_target(char *); 153static void set_source_ip(char *arg, int icmp_sock, sa_family_t addr_family);
223static int add_target_ip(char *, struct sockaddr_storage *); 154
224static int handle_random_icmp(unsigned char *, struct sockaddr_storage *); 155/* Receiving data */
225static void parse_address(struct sockaddr_storage *, char *, int); 156static int wait_for_reply(check_icmp_socket_set sockset, time_t time_interval,
226static unsigned short icmp_checksum(uint16_t *, size_t); 157 unsigned short icmp_pkt_size, time_t *target_interval, uint16_t sender_id,
227static void finish(int); 158 ping_target **table, unsigned short packets,
228static void crash(const char *, ...); 159 unsigned short number_of_targets, check_icmp_state *program_state);
229 160
230/** external **/ 161typedef struct {
231extern int optind; 162 sa_family_t recv_proto;
232extern char *optarg; 163 ssize_t received;
233extern char **environ; 164} recvfrom_wto_wrapper;
165static recvfrom_wto_wrapper recvfrom_wto(check_icmp_socket_set sockset, void *buf, unsigned int len,
166 struct sockaddr *saddr, time_t *timeout,
167 struct timeval *received_timestamp);
168static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr,
169 time_t *target_interval, uint16_t sender_id, ping_target **table,
170 unsigned short packets, unsigned short number_of_targets,
171 check_icmp_state *program_state);
172
173/* Sending data */
174static int send_icmp_ping(check_icmp_socket_set sockset, ping_target *host,
175 unsigned short icmp_pkt_size, uint16_t sender_id,
176 check_icmp_state *program_state);
177
178/* Threshold related */
179typedef struct {
180 int errorcode;
181 check_icmp_threshold threshold;
182} get_threshold_wrapper;
183static get_threshold_wrapper get_threshold(char *str, check_icmp_threshold threshold);
184
185typedef struct {
186 int errorcode;
187 check_icmp_threshold warn;
188 check_icmp_threshold crit;
189} get_threshold2_wrapper;
190static get_threshold2_wrapper get_threshold2(char *str, size_t length, check_icmp_threshold warn,
191 check_icmp_threshold crit, threshold_mode mode);
192
193typedef struct {
194 int errorcode;
195 check_icmp_threshold result;
196} parse_threshold2_helper_wrapper;
197static parse_threshold2_helper_wrapper parse_threshold2_helper(char *threshold_string,
198 size_t length,
199 check_icmp_threshold thr,
200 threshold_mode mode);
201
202/* main test function */
203static void run_checks(unsigned short icmp_pkt_size, time_t *target_interval, uint16_t sender_id,
204 check_icmp_execution_mode mode, time_t max_completion_time,
205 struct timeval prog_start, ping_target **table, unsigned short packets,
206 check_icmp_socket_set sockset, unsigned short number_of_targets,
207 check_icmp_state *program_state);
208mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes,
209 check_icmp_threshold warn, check_icmp_threshold crit);
210
211typedef struct {
212 int targets_ok;
213 int targets_warn;
214 mp_subcheck sc_host;
215} evaluate_host_wrapper;
216evaluate_host_wrapper evaluate_host(check_icmp_target_container host,
217 check_icmp_mode_switches modes, check_icmp_threshold warn,
218 check_icmp_threshold crit);
219
220/* Target acquisition */
221typedef struct {
222 int error_code;
223 check_icmp_target_container host;
224 bool has_v4;
225 bool has_v6;
226} add_host_wrapper;
227static add_host_wrapper add_host(char *arg, check_icmp_execution_mode mode,
228 sa_family_t enforced_proto);
229
230typedef struct {
231 int error_code;
232 ping_target *targets;
233 unsigned int number_of_targets;
234 bool has_v4;
235 bool has_v6;
236} add_target_wrapper;
237static add_target_wrapper add_target(char *arg, check_icmp_execution_mode mode,
238 sa_family_t enforced_proto);
239
240typedef struct {
241 int error_code;
242 ping_target *target;
243} add_target_ip_wrapper;
244static add_target_ip_wrapper add_target_ip(struct sockaddr_storage address);
245
246static void parse_address(const struct sockaddr_storage *addr, char *dst, socklen_t size);
247
248static unsigned short icmp_checksum(uint16_t *packet, size_t packet_size);
249
250/* End of run function */
251static void finish(int sign, check_icmp_mode_switches modes, int min_hosts_alive,
252 check_icmp_threshold warn, check_icmp_threshold crit,
253 unsigned short number_of_targets, check_icmp_state *program_state,
254 check_icmp_target_container host_list[], unsigned short number_of_hosts,
255 mp_check overall[static 1]);
256
257/* Error exit */
258static void crash(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
234 259
235/** global variables **/ 260/** global variables **/
236static struct rta_host **table, *cursor, *list; 261static int debug = 0;
237 262
238static threshold crit = {.pl = 80, .rta = 500000, .jitter = 0.0, .mos = 0.0, .score = 0.0}; 263extern unsigned int timeout;
239static threshold warn = {.pl = 40, .rta = 200000, .jitter = 0.0, .mos = 0.0, .score = 0.0}; 264
240 265/** the working code **/
241static int mode, protocols, sockets, debug = 0, timeout = 10; 266static inline unsigned short targets_alive(unsigned short targets, unsigned short targets_down) {
242static unsigned short icmp_data_size = DEFAULT_PING_DATA_SIZE; 267 return targets - targets_down;
243static unsigned short icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN; 268}
244 269static inline unsigned int icmp_pkts_en_route(unsigned int icmp_sent, unsigned int icmp_recv,
245static unsigned int icmp_sent = 0, icmp_recv = 0, icmp_lost = 0, ttl = 0; 270 unsigned int icmp_lost) {
246#define icmp_pkts_en_route (icmp_sent - (icmp_recv + icmp_lost)) 271 return icmp_sent - (icmp_recv + icmp_lost);
247static unsigned short targets_down = 0, targets = 0, packets = 0; 272}
248#define targets_alive (targets - targets_down) 273
249static unsigned int retry_interval, pkt_interval, target_interval; 274// Create configuration from cli parameters
250static int icmp_sock, tcp_sock, udp_sock, status = STATE_OK; 275typedef struct {
251static pid_t pid; 276 int errorcode;
252static struct timezone tz; 277 check_icmp_config config;
253static struct timeval prog_start; 278} check_icmp_config_wrapper;
254static unsigned long long max_completion_time = 0; 279check_icmp_config_wrapper process_arguments(int argc, char **argv) {
255static unsigned int warn_down = 1, crit_down = 1; /* host down threshold values */ 280 /* get calling name the old-fashioned way for portability instead
256static int min_hosts_alive = -1; 281 * of relying on the glibc-ism __progname */
257static float pkt_backoff_factor = 1.5; 282 char *ptr = strrchr(argv[0], '/');
258static float target_backoff_factor = 1.5; 283 if (ptr) {
259static bool rta_mode = false; 284 progname = &ptr[1];
260static bool pl_mode = false; 285 } else {
261static bool jitter_mode = false; 286 progname = argv[0];
262static bool score_mode = false; 287 }
263static bool mos_mode = false; 288
264static bool order_mode = false; 289 check_icmp_config_wrapper result = {
290 .errorcode = OK,
291 .config = check_icmp_config_init(),
292 };
293
294 /* use the pid to mark packets as ours */
295 /* Some systems have 32-bit pid_t so mask off only 16 bits */
296 result.config.sender_id = getpid() & 0xffff;
297
298 if (!strcmp(progname, "check_icmp") || !strcmp(progname, "check_ping")) {
299 result.config.mode = MODE_ICMP;
300 } else if (!strcmp(progname, "check_host")) {
301 result.config.mode = MODE_HOSTCHECK;
302 result.config.number_of_packets = 5;
303 result.config.crit.rta = result.config.warn.rta = 1000000;
304 result.config.crit.pl = result.config.warn.pl = 100;
305 } else if (!strcmp(progname, "check_rta_multi")) {
306 result.config.mode = MODE_ALL;
307 result.config.target_interval = 0;
308 result.config.number_of_packets = 5;
309 }
310 /* support "--help" and "--version" */
311 if (argc == 2) {
312 if (!strcmp(argv[1], "--help")) {
313 strcpy(argv[1], "-h");
314 }
315 if (!strcmp(argv[1], "--version")) {
316 strcpy(argv[1], "-V");
317 }
318 }
319
320 sa_family_t enforced_ai_family = AF_UNSPEC;
321
322 enum {
323 output_format_index = CHAR_MAX + 1,
324 };
325
326 struct option longopts[] = {
327 {"version", no_argument, 0, 'V'},
328 {"help", no_argument, 0, 'h'},
329 {"verbose", no_argument, 0, 'v'},
330 {"Host", required_argument, 0, 'H'},
331 {"ipv4-only", no_argument, 0, '4'},
332 {"ipv6-only", no_argument, 0, '6'},
333 {"warning", required_argument, 0, 'w'},
334 {"critical", required_argument, 0, 'c'},
335 {"rta-mode-thresholds", required_argument, 0, 'R'},
336 {"packet-loss-mode-thresholds", required_argument, 0, 'P'},
337 {"jitter-mode-thresholds", required_argument, 0, 'J'},
338 {"mos-mode-thresholds", required_argument, 0, 'M'},
339 {"score-mode-thresholds", required_argument, 0, 'S'},
340 {"out-of-order-packets", no_argument, 0, 'O'},
341 {"number-of-packets", required_argument, 0, 'n'},
342 {"number-of-packets", required_argument, 0, 'p'},
343 {"packet-interval", required_argument, 0, 'i'},
344 {"target-interval", required_argument, 0, 'I'},
345 {"minimal-host-alive", required_argument, 0, 'm'},
346 {"outgoing-ttl", required_argument, 0, 'l'},
347 {"size", required_argument, 0, 'b'},
348 {"output-format", required_argument, 0, output_format_index},
349 {},
350 };
351
352 // Parse protocol arguments first
353 // and count hosts here
354 char *opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:P:R:J:S:M:O64";
355 for (int i = 1; i < argc; i++) {
356 long int arg;
357 while ((arg = getopt_long(argc, argv, opts_str, longopts, NULL)) != EOF) {
358 switch (arg) {
359
360 case '4':
361 if (enforced_ai_family != AF_UNSPEC) {
362 crash("Multiple protocol versions not supported");
363 }
364 enforced_ai_family = AF_INET;
365 break;
366 case '6':
367 if (enforced_ai_family != AF_UNSPEC) {
368 crash("Multiple protocol versions not supported");
369 }
370 enforced_ai_family = AF_INET6;
371 break;
372 case 'H': {
373 result.config.number_of_hosts++;
374 break;
375 }
376 case 'h': /* help */
377 // Trigger help here to avoid adding hosts before that (and doing DNS queries)
378 print_help();
379 exit(STATE_UNKNOWN);
380 break;
381 case 'v':
382 debug++;
383 break;
384 }
385 }
386 }
387
388 char **tmp = &argv[optind];
389 while (*tmp) {
390 result.config.number_of_hosts++;
391 tmp++;
392 }
393
394 // Sanity check: if hostmode is selected,only a single host is allowed
395 if (result.config.mode == MODE_HOSTCHECK && result.config.number_of_hosts > 1) {
396 usage("check_host only allows a single host");
397 }
398
399 // Allocate hosts
400 result.config.hosts =
401 calloc(result.config.number_of_hosts, sizeof(check_icmp_target_container));
402 if (result.config.hosts == NULL) {
403 crash("failed to allocate memory");
404 }
405
406 /* Reset argument scanning */
407 optind = 1;
408
409 int host_counter = 0;
410 /* parse the arguments */
411 for (int i = 1; i < argc; i++) {
412 long int arg;
413 while ((arg = getopt_long(argc, argv, opts_str, longopts, NULL)) != EOF) {
414 switch (arg) {
415 case 'b': {
416 long size = strtol(optarg, NULL, 0);
417 if ((unsigned long)size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) &&
418 size < MAX_PING_DATA) {
419 result.config.icmp_data_size = (unsigned short)size;
420 } else {
421 usage_va("ICMP data length must be between: %lu and %lu",
422 sizeof(struct icmp) + sizeof(struct icmp_ping_data),
423 MAX_PING_DATA - 1);
424 }
425 } break;
426 case 'i': {
427 // packet_interval was unused and is now removed
428 } break;
429 case 'I': {
430 get_timevar_wrapper parsed_time = get_timevar(optarg);
431
432 if (parsed_time.error_code == OK) {
433 result.config.target_interval = parsed_time.time_range;
434 } else {
435 crash("failed to parse target interval");
436 }
437 } break;
438 case 'w': {
439 get_threshold_wrapper warn = get_threshold(optarg, result.config.warn);
440 if (warn.errorcode == OK) {
441 result.config.warn = warn.threshold;
442 } else {
443 crash("failed to parse warning threshold");
444 }
445 } break;
446 case 'c': {
447 get_threshold_wrapper crit = get_threshold(optarg, result.config.crit);
448 if (crit.errorcode == OK) {
449 result.config.crit = crit.threshold;
450 } else {
451 crash("failed to parse critical threshold");
452 }
453 } break;
454 case 'n':
455 case 'p':
456 result.config.number_of_packets = (unsigned short)strtoul(optarg, NULL, 0);
457 if (result.config.number_of_packets > 20) {
458 errno = 0;
459 crash("packets is > 20 (%d)", result.config.number_of_packets);
460 }
461 break;
462 case 't':
463 // WARNING Deprecated since execution time is determined by the other factors
464 break;
465 case 'H': {
466 add_host_wrapper host_add_result =
467 add_host(optarg, result.config.mode, enforced_ai_family);
468 if (host_add_result.error_code == OK) {
469 result.config.hosts[host_counter] = host_add_result.host;
470 host_counter++;
471
472 if (result.config.targets != NULL) {
473 result.config.number_of_targets += ping_target_list_append(
474 result.config.targets, host_add_result.host.target_list);
475 } else {
476 result.config.targets = host_add_result.host.target_list;
477 result.config.number_of_targets += host_add_result.host.number_of_targets;
478 }
479
480 if (host_add_result.has_v4) {
481 result.config.need_v4 = true;
482 }
483 if (host_add_result.has_v6) {
484 result.config.need_v6 = true;
485 }
486 } else {
487 crash("Failed to add host, unable to parse it correctly");
488 }
489 } break;
490 case 'l':
491 result.config.ttl = strtoul(optarg, NULL, 0);
492 break;
493 case 'm':
494 result.config.min_hosts_alive = (int)strtoul(optarg, NULL, 0);
495 break;
496 case 's': /* specify source IP address */
497 result.config.source_ip = optarg;
498 break;
499 case 'V': /* version */
500 print_revision(progname, NP_VERSION);
501 exit(STATE_UNKNOWN);
502 case 'R': /* RTA mode */ {
503 get_threshold2_wrapper rta_th = get_threshold2(
504 optarg, strlen(optarg), result.config.warn, result.config.crit, const_rta_mode);
505
506 if (rta_th.errorcode != OK) {
507 crash("Failed to parse RTA threshold");
508 }
509
510 result.config.warn = rta_th.warn;
511 result.config.crit = rta_th.crit;
512 result.config.modes.rta_mode = true;
513 } break;
514 case 'P': /* packet loss mode */ {
515 get_threshold2_wrapper pl_th =
516 get_threshold2(optarg, strlen(optarg), result.config.warn, result.config.crit,
517 const_packet_loss_mode);
518 if (pl_th.errorcode != OK) {
519 crash("Failed to parse packet loss threshold");
520 }
521
522 result.config.warn = pl_th.warn;
523 result.config.crit = pl_th.crit;
524 result.config.modes.pl_mode = true;
525 } break;
526 case 'J': /* jitter mode */ {
527 get_threshold2_wrapper jitter_th =
528 get_threshold2(optarg, strlen(optarg), result.config.warn, result.config.crit,
529 const_jitter_mode);
530 if (jitter_th.errorcode != OK) {
531 crash("Failed to parse jitter threshold");
532 }
533
534 result.config.warn = jitter_th.warn;
535 result.config.crit = jitter_th.crit;
536 result.config.modes.jitter_mode = true;
537 } break;
538 case 'M': /* MOS mode */ {
539 get_threshold2_wrapper mos_th = get_threshold2(
540 optarg, strlen(optarg), result.config.warn, result.config.crit, const_mos_mode);
541 if (mos_th.errorcode != OK) {
542 crash("Failed to parse MOS threshold");
543 }
544
545 result.config.warn = mos_th.warn;
546 result.config.crit = mos_th.crit;
547 result.config.modes.mos_mode = true;
548 } break;
549 case 'S': /* score mode */ {
550 get_threshold2_wrapper score_th =
551 get_threshold2(optarg, strlen(optarg), result.config.warn, result.config.crit,
552 const_score_mode);
553 if (score_th.errorcode != OK) {
554 crash("Failed to parse score threshold");
555 }
556
557 result.config.warn = score_th.warn;
558 result.config.crit = score_th.crit;
559 result.config.modes.score_mode = true;
560 } break;
561 case 'O': /* out of order mode */
562 result.config.modes.order_mode = true;
563 break;
564 case output_format_index: {
565 parsed_output_format parser = mp_parse_output_format(optarg);
566 if (!parser.parsing_success) {
567 // TODO List all available formats here, maybe add anothoer usage function
568 printf("Invalid output format: %s\n", optarg);
569 exit(STATE_UNKNOWN);
570 }
571
572 result.config.output_format_is_set = true;
573 result.config.output_format = parser.output_format;
574 break;
575 }
576 }
577 }
578 }
579
580 argv = &argv[optind];
581 while (*argv) {
582 add_target(*argv, result.config.mode, enforced_ai_family);
583 argv++;
584 }
585
586 if (!result.config.number_of_targets) {
587 errno = 0;
588 crash("No hosts to check");
589 }
590
591 /* stupid users should be able to give whatever thresholds they want
592 * (nothing will break if they do), but some anal plugin maintainer
593 * will probably add some printf() thing here later, so it might be
594 * best to at least show them where to do it. ;) */
595 if (result.config.warn.pl > result.config.crit.pl) {
596 result.config.warn.pl = result.config.crit.pl;
597 }
598 if (result.config.warn.rta > result.config.crit.rta) {
599 result.config.warn.rta = result.config.crit.rta;
600 }
601 if (result.config.warn.jitter > result.config.crit.jitter) {
602 result.config.crit.jitter = result.config.warn.jitter;
603 }
604 if (result.config.warn.mos < result.config.crit.mos) {
605 result.config.warn.mos = result.config.crit.mos;
606 }
607 if (result.config.warn.score < result.config.crit.score) {
608 result.config.warn.score = result.config.crit.score;
609 }
610
611 return result;
612}
265 613
266/** code start **/ 614/** code start **/
267static void crash(const char *fmt, ...) { 615static void crash(const char *fmt, ...) {
268 va_list ap;
269 616
270 printf("%s: ", progname); 617 printf("%s: ", progname);
271 618
619 va_list ap;
272 va_start(ap, fmt); 620 va_start(ap, fmt);
273 vprintf(fmt, ap); 621 vprintf(fmt, ap);
274 va_end(ap); 622 va_end(ap);
@@ -385,18 +733,20 @@ static const char *get_icmp_error_msg(unsigned char icmp_type, unsigned char icm
385 return msg; 733 return msg;
386} 734}
387 735
388static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr) { 736static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr,
389 struct icmp p, sent_icmp; 737 time_t *target_interval, const uint16_t sender_id,
390 struct rta_host *host = NULL; 738 ping_target **table, unsigned short packets,
391 739 const unsigned short number_of_targets,
392 memcpy(&p, packet, sizeof(p)); 740 check_icmp_state *program_state) {
393 if (p.icmp_type == ICMP_ECHO && ntohs(p.icmp_id) == pid) { 741 struct icmp icmp_packet;
742 memcpy(&icmp_packet, packet, sizeof(icmp_packet));
743 if (icmp_packet.icmp_type == ICMP_ECHO && ntohs(icmp_packet.icmp_id) == sender_id) {
394 /* echo request from us to us (pinging localhost) */ 744 /* echo request from us to us (pinging localhost) */
395 return 0; 745 return 0;
396 } 746 }
397 747
398 if (debug) { 748 if (debug) {
399 printf("handle_random_icmp(%p, %p)\n", (void *)&p, (void *)addr); 749 printf("handle_random_icmp(%p, %p)\n", (void *)&icmp_packet, (void *)addr);
400 } 750 }
401 751
402 /* only handle a few types, since others can't possibly be replies to 752 /* only handle a few types, since others can't possibly be replies to
@@ -409,14 +759,17 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad
409 * TIMXCEED actually sends a proper icmp response we will have passed 759 * TIMXCEED actually sends a proper icmp response we will have passed
410 * too many hops to have a hope of reaching it later, in which case it 760 * too many hops to have a hope of reaching it later, in which case it
411 * indicates overconfidence in the network, poor routing or both. */ 761 * indicates overconfidence in the network, poor routing or both. */
412 if (p.icmp_type != ICMP_UNREACH && p.icmp_type != ICMP_TIMXCEED && p.icmp_type != ICMP_SOURCEQUENCH && p.icmp_type != ICMP_PARAMPROB) { 762 if (icmp_packet.icmp_type != ICMP_UNREACH && icmp_packet.icmp_type != ICMP_TIMXCEED &&
763 icmp_packet.icmp_type != ICMP_SOURCEQUENCH && icmp_packet.icmp_type != ICMP_PARAMPROB) {
413 return 0; 764 return 0;
414 } 765 }
415 766
416 /* might be for us. At least it holds the original package (according 767 /* might be for us. At least it holds the original package (according
417 * to RFC 792). If it isn't, just ignore it */ 768 * to RFC 792). If it isn't, just ignore it */
769 struct icmp sent_icmp;
418 memcpy(&sent_icmp, packet + 28, sizeof(sent_icmp)); 770 memcpy(&sent_icmp, packet + 28, sizeof(sent_icmp));
419 if (sent_icmp.icmp_type != ICMP_ECHO || ntohs(sent_icmp.icmp_id) != pid || ntohs(sent_icmp.icmp_seq) >= targets * packets) { 771 if (sent_icmp.icmp_type != ICMP_ECHO || ntohs(sent_icmp.icmp_id) != sender_id ||
772 ntohs(sent_icmp.icmp_seq) >= number_of_targets * packets) {
420 if (debug) { 773 if (debug) {
421 printf("Packet is no response to a packet we sent\n"); 774 printf("Packet is no response to a packet we sent\n");
422 } 775 }
@@ -424,14 +777,15 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad
424 } 777 }
425 778
426 /* it is indeed a response for us */ 779 /* it is indeed a response for us */
427 host = table[ntohs(sent_icmp.icmp_seq) / packets]; 780 ping_target *host = table[ntohs(sent_icmp.icmp_seq) / packets];
428 if (debug) { 781 if (debug) {
429 char address[INET6_ADDRSTRLEN]; 782 char address[INET6_ADDRSTRLEN];
430 parse_address(addr, address, sizeof(address)); 783 parse_address(addr, address, sizeof(address));
431 printf("Received \"%s\" from %s for ICMP ECHO sent to %s.\n", get_icmp_error_msg(p.icmp_type, p.icmp_code), address, host->name); 784 printf("Received \"%s\" from %s for ICMP ECHO sent.\n",
785 get_icmp_error_msg(icmp_packet.icmp_type, icmp_packet.icmp_code), address);
432 } 786 }
433 787
434 icmp_lost++; 788 program_state->icmp_lost++;
435 host->icmp_lost++; 789 host->icmp_lost++;
436 /* don't spend time on lost hosts any more */ 790 /* don't spend time on lost hosts any more */
437 if (host->flags & FLAG_LOST_CAUSE) { 791 if (host->flags & FLAG_LOST_CAUSE) {
@@ -440,305 +794,104 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad
440 794
441 /* source quench means we're sending too fast, so increase the 795 /* source quench means we're sending too fast, so increase the
442 * interval and mark this packet lost */ 796 * interval and mark this packet lost */
443 if (p.icmp_type == ICMP_SOURCEQUENCH) { 797 if (icmp_packet.icmp_type == ICMP_SOURCEQUENCH) {
444 pkt_interval *= pkt_backoff_factor; 798 *target_interval = (unsigned int)((double)*target_interval * TARGET_BACKOFF_FACTOR);
445 target_interval *= target_backoff_factor;
446 } else { 799 } else {
447 targets_down++; 800 program_state->targets_down++;
448 host->flags |= FLAG_LOST_CAUSE; 801 host->flags |= FLAG_LOST_CAUSE;
449 } 802 }
450 host->icmp_type = p.icmp_type; 803 host->icmp_type = icmp_packet.icmp_type;
451 host->icmp_code = p.icmp_code; 804 host->icmp_code = icmp_packet.icmp_code;
452 host->error_addr = *addr; 805 host->error_addr = *addr;
453 806
454 return 0; 807 return 0;
455} 808}
456 809
457void parse_address(struct sockaddr_storage *addr, char *address, int size) { 810void parse_address(const struct sockaddr_storage *addr, char *dst, socklen_t size) {
458 switch (address_family) { 811 switch (addr->ss_family) {
459 case AF_INET: 812 case AF_INET:
460 inet_ntop(address_family, &((struct sockaddr_in *)addr)->sin_addr, address, size); 813 inet_ntop(AF_INET, &((struct sockaddr_in *)addr)->sin_addr, dst, size);
461 break; 814 break;
462 case AF_INET6: 815 case AF_INET6:
463 inet_ntop(address_family, &((struct sockaddr_in6 *)addr)->sin6_addr, address, size); 816 inet_ntop(AF_INET6, &((struct sockaddr_in6 *)addr)->sin6_addr, dst, size);
464 break; 817 break;
818 default:
819 assert(false);
465 } 820 }
466} 821}
467 822
468int main(int argc, char **argv) { 823int main(int argc, char **argv) {
469 int i;
470 char *ptr;
471 long int arg;
472 int icmp_sockerrno, udp_sockerrno, tcp_sockerrno;
473 int result;
474 struct rta_host *host;
475#ifdef HAVE_SIGACTION
476 struct sigaction sig_action;
477#endif
478#ifdef SO_TIMESTAMP
479 int on = 1;
480#endif
481 char *source_ip = NULL;
482 char *opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:P:R:J:S:M:O64";
483 setlocale(LC_ALL, ""); 824 setlocale(LC_ALL, "");
484 bindtextdomain(PACKAGE, LOCALEDIR); 825 bindtextdomain(PACKAGE, LOCALEDIR);
485 textdomain(PACKAGE); 826 textdomain(PACKAGE);
486 827
487 /* we only need to be setsuid when we get the sockets, so do 828 /* POSIXLY_CORRECT might break things, so unset it (the portable way) */
488 * that before pointer magic (esp. on network data) */ 829 environ = NULL;
489 icmp_sockerrno = udp_sockerrno = tcp_sockerrno = sockets = 0;
490
491 address_family = -1;
492 int icmp_proto = IPPROTO_ICMP;
493 830
494 /* get calling name the old-fashioned way for portability instead 831 /* Parse extra opts if any */
495 * of relying on the glibc-ism __progname */ 832 argv = np_extra_opts(&argc, argv, progname);
496 ptr = strrchr(argv[0], '/');
497 if (ptr) {
498 progname = &ptr[1];
499 } else {
500 progname = argv[0];
501 }
502 833
503 /* now set defaults. Use progname to set them initially (allows for 834 check_icmp_config_wrapper tmp_config = process_arguments(argc, argv);
504 * superfast check_host program when target host is up */
505 cursor = list = NULL;
506 table = NULL;
507
508 mode = MODE_RTA;
509 /* Default critical thresholds */
510 crit.rta = 500000;
511 crit.pl = 80;
512 crit.jitter = 50;
513 crit.mos = 3;
514 crit.score = 70;
515 /* Default warning thresholds */
516 warn.rta = 200000;
517 warn.pl = 40;
518 warn.jitter = 40;
519 warn.mos = 3.5;
520 warn.score = 80;
521
522 protocols = HAVE_ICMP | HAVE_UDP | HAVE_TCP;
523 pkt_interval = 80000; /* 80 msec packet interval by default */
524 packets = 5;
525 835
526 if (!strcmp(progname, "check_icmp") || !strcmp(progname, "check_ping")) { 836 if (tmp_config.errorcode != OK) {
527 mode = MODE_ICMP; 837 crash("failed to parse config");
528 protocols = HAVE_ICMP;
529 } else if (!strcmp(progname, "check_host")) {
530 mode = MODE_HOSTCHECK;
531 pkt_interval = 1000000;
532 packets = 5;
533 crit.rta = warn.rta = 1000000;
534 crit.pl = warn.pl = 100;
535 } else if (!strcmp(progname, "check_rta_multi")) {
536 mode = MODE_ALL;
537 target_interval = 0;
538 pkt_interval = 50000;
539 packets = 5;
540 } 838 }
541 839
542 /* support "--help" and "--version" */ 840 const check_icmp_config config = tmp_config.config;
543 if (argc == 2) {
544 if (!strcmp(argv[1], "--help")) {
545 strcpy(argv[1], "-h");
546 }
547 if (!strcmp(argv[1], "--version")) {
548 strcpy(argv[1], "-V");
549 }
550 }
551 841
552 /* Parse protocol arguments first */ 842 if (config.output_format_is_set) {
553 for (i = 1; i < argc; i++) { 843 mp_set_format(config.output_format);
554 while ((arg = getopt(argc, argv, opts_str)) != EOF) {
555 switch (arg) {
556 case '4':
557 if (address_family != -1) {
558 crash("Multiple protocol versions not supported");
559 }
560 address_family = AF_INET;
561 break;
562 case '6':
563#ifdef USE_IPV6
564 if (address_family != -1) {
565 crash("Multiple protocol versions not supported");
566 }
567 address_family = AF_INET6;
568#else
569 usage(_("IPv6 support not available\n"));
570#endif
571 break;
572 }
573 }
574 } 844 }
575 845
576 /* Reset argument scanning */ 846 check_icmp_socket_set sockset = {
577 optind = 1; 847 .socket4 = -1,
848 .socket6 = -1,
849 };
578 850
579 unsigned long size; 851 if (config.need_v4) {
580 bool err; 852 sockset.socket4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
581 /* parse the arguments */ 853 if (sockset.socket4 == -1) {
582 for (i = 1; i < argc; i++) { 854 crash("Failed to obtain ICMP v4 socket");
583 while ((arg = getopt(argc, argv, opts_str)) != EOF) { 855 }
584 switch (arg) {
585 case 'v':
586 debug++;
587 break;
588 case 'b':
589 size = strtol(optarg, NULL, 0);
590 if (size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) && size < MAX_PING_DATA) {
591 icmp_data_size = size;
592 icmp_pkt_size = size + ICMP_MINLEN;
593 } else {
594 usage_va("ICMP data length must be between: %lu and %lu", sizeof(struct icmp) + sizeof(struct icmp_ping_data),
595 MAX_PING_DATA - 1);
596 }
597 break;
598 case 'i':
599 pkt_interval = get_timevar(optarg);
600 break;
601 case 'I':
602 target_interval = get_timevar(optarg);
603 break;
604 case 'w':
605 get_threshold(optarg, &warn);
606 break;
607 case 'c':
608 get_threshold(optarg, &crit);
609 break;
610 case 'n':
611 case 'p':
612 packets = strtoul(optarg, NULL, 0);
613 break;
614 case 't':
615 timeout = strtoul(optarg, NULL, 0);
616 if (!timeout) {
617 timeout = 10;
618 }
619 break;
620 case 'H':
621 add_target(optarg);
622 break;
623 case 'l':
624 ttl = (int)strtoul(optarg, NULL, 0);
625 break;
626 case 'm':
627 min_hosts_alive = (int)strtoul(optarg, NULL, 0);
628 break;
629 case 'd': /* implement later, for cluster checks */
630 warn_down = (unsigned char)strtoul(optarg, &ptr, 0);
631 if (ptr) {
632 crit_down = (unsigned char)strtoul(ptr + 1, NULL, 0);
633 }
634 break;
635 case 's': /* specify source IP address */
636 source_ip = optarg;
637 break;
638 case 'V': /* version */
639 print_revision(progname, NP_VERSION);
640 exit(STATE_UNKNOWN);
641 case 'h': /* help */
642 print_help();
643 exit(STATE_UNKNOWN);
644 break;
645 case 'R': /* RTA mode */
646 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_rta_mode);
647 if (!err) {
648 crash("Failed to parse RTA threshold");
649 }
650 856
651 rta_mode = true; 857 if (config.source_ip) {
652 break;
653 case 'P': /* packet loss mode */
654 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_packet_loss_mode);
655 if (!err) {
656 crash("Failed to parse packet loss threshold");
657 }
658 858
659 pl_mode = true; 859 struct in_addr tmp = {};
660 break; 860 int error_code = inet_pton(AF_INET, config.source_ip, &tmp);
661 case 'J': /* jitter mode */ 861 if (error_code == 1) {
662 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_jitter_mode); 862 set_source_ip(config.source_ip, sockset.socket4, AF_INET);
663 if (!err) { 863 } else {
664 crash("Failed to parse jitter threshold"); 864 // just try this mindlessly if it's not a v4 address
665 } 865 set_source_ip(config.source_ip, sockset.socket6, AF_INET6);
866 }
867 }
666 868
667 jitter_mode = true; 869#ifdef SO_TIMESTAMP
668 break; 870 if (sockset.socket4 != -1) {
669 case 'M': /* MOS mode */ 871 int on = 1;
670 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_mos_mode); 872 if (setsockopt(sockset.socket4, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) {
671 if (!err) { 873 if (debug) {
672 crash("Failed to parse MOS threshold"); 874 printf("Warning: no SO_TIMESTAMP support\n");
673 } 875 }
674 876 }
675 mos_mode = true; 877 }
676 break; 878 if (sockset.socket6 != -1) {
677 case 'S': /* score mode */ 879 int on = 1;
678 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_score_mode); 880 if (setsockopt(sockset.socket6, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) {
679 if (!err) { 881 if (debug) {
680 crash("Failed to parse score threshold"); 882 printf("Warning: no SO_TIMESTAMP support\n");
681 } 883 }
682
683 score_mode = true;
684 break;
685 case 'O': /* out of order mode */
686 order_mode = true;
687 break;
688 } 884 }
689 } 885 }
886#endif // SO_TIMESTAMP
690 } 887 }
691 888
692 /* POSIXLY_CORRECT might break things, so unset it (the portable way) */ 889 if (config.need_v6) {
693 environ = NULL; 890 sockset.socket6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
694 891 if (sockset.socket6 == -1) {
695 /* use the pid to mark packets as ours */ 892 crash("Failed to obtain ICMP v6 socket");
696 /* Some systems have 32-bit pid_t so mask off only 16 bits */
697 pid = getpid() & 0xffff;
698 /* printf("pid = %u\n", pid); */
699
700 /* Parse extra opts if any */
701 argv = np_extra_opts(&argc, argv, progname);
702
703 argv = &argv[optind];
704 while (*argv) {
705 add_target(*argv);
706 argv++;
707 }
708
709 if (!targets) {
710 errno = 0;
711 crash("No hosts to check");
712 }
713
714 // add_target might change address_family
715 switch (address_family) {
716 case AF_INET:
717 icmp_proto = IPPROTO_ICMP;
718 break;
719 case AF_INET6:
720 icmp_proto = IPPROTO_ICMPV6;
721 break;
722 default:
723 crash("Address family not supported");
724 }
725 if ((icmp_sock = socket(address_family, SOCK_RAW, icmp_proto)) != -1) {
726 sockets |= HAVE_ICMP;
727 } else {
728 icmp_sockerrno = errno;
729 }
730
731 if (source_ip) {
732 set_source_ip(source_ip);
733 }
734
735#ifdef SO_TIMESTAMP
736 if (setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) {
737 if (debug) {
738 printf("Warning: no SO_TIMESTAMP support\n");
739 } 893 }
740 } 894 }
741#endif // SO_TIMESTAMP
742 895
743 /* now drop privileges (no effect if not setsuid or geteuid() == 0) */ 896 /* now drop privileges (no effect if not setsuid or geteuid() == 0) */
744 if (setuid(getuid()) == -1) { 897 if (setuid(getuid()) == -1) {
@@ -746,186 +899,179 @@ int main(int argc, char **argv) {
746 return 1; 899 return 1;
747 } 900 }
748 901
749 if (!sockets) { 902 if (sockset.socket4) {
750 if (icmp_sock == -1) { 903 int result = setsockopt(sockset.socket4, SOL_IP, IP_TTL, &config.ttl, sizeof(config.ttl));
751 errno = icmp_sockerrno;
752 crash("Failed to obtain ICMP socket");
753 return -1;
754 }
755 /* if(udp_sock == -1) { */
756 /* errno = icmp_sockerrno; */
757 /* crash("Failed to obtain UDP socket"); */
758 /* return -1; */
759 /* } */
760 /* if(tcp_sock == -1) { */
761 /* errno = icmp_sockerrno; */
762 /* crash("Failed to obtain TCP socker"); */
763 /* return -1; */
764 /* } */
765 }
766 if (!ttl) {
767 ttl = 64;
768 }
769
770 if (icmp_sock) {
771 result = setsockopt(icmp_sock, SOL_IP, IP_TTL, &ttl, sizeof(ttl));
772 if (debug) { 904 if (debug) {
773 if (result == -1) { 905 if (result == -1) {
774 printf("setsockopt failed\n"); 906 printf("setsockopt failed\n");
775 } else { 907 } else {
776 printf("ttl set to %u\n", ttl); 908 printf("ttl set to %lu\n", config.ttl);
777 } 909 }
778 } 910 }
779 } 911 }
780 912
781 /* stupid users should be able to give whatever thresholds they want 913 if (sockset.socket6) {
782 * (nothing will break if they do), but some anal plugin maintainer 914 int result = setsockopt(sockset.socket6, SOL_IP, IP_TTL, &config.ttl, sizeof(config.ttl));
783 * will probably add some printf() thing here later, so it might be 915 if (debug) {
784 * best to at least show them where to do it. ;) */ 916 if (result == -1) {
785 if (warn.pl > crit.pl) { 917 printf("setsockopt failed\n");
786 warn.pl = crit.pl; 918 } else {
787 } 919 printf("ttl set to %lu\n", config.ttl);
788 if (warn.rta > crit.rta) { 920 }
789 warn.rta = crit.rta; 921 }
790 }
791 if (warn_down > crit_down) {
792 crit_down = warn_down;
793 }
794 if (warn.jitter > crit.jitter) {
795 crit.jitter = warn.jitter;
796 }
797 if (warn.mos < crit.mos) {
798 warn.mos = crit.mos;
799 }
800 if (warn.score < crit.score) {
801 warn.score = crit.score;
802 }
803
804#ifdef HAVE_SIGACTION
805 sig_action.sa_sigaction = NULL;
806 sig_action.sa_handler = finish;
807 sigfillset(&sig_action.sa_mask);
808 sig_action.sa_flags = SA_NODEFER | SA_RESTART;
809 sigaction(SIGINT, &sig_action, NULL);
810 sigaction(SIGHUP, &sig_action, NULL);
811 sigaction(SIGTERM, &sig_action, NULL);
812 sigaction(SIGALRM, &sig_action, NULL);
813#else /* HAVE_SIGACTION */
814 signal(SIGINT, finish);
815 signal(SIGHUP, finish);
816 signal(SIGTERM, finish);
817 signal(SIGALRM, finish);
818#endif /* HAVE_SIGACTION */
819 if (debug) {
820 printf("Setting alarm timeout to %u seconds\n", timeout);
821 } 922 }
822 alarm(timeout);
823 923
824 /* make sure we don't wait any longer than necessary */ 924 /* make sure we don't wait any longer than necessary */
825 gettimeofday(&prog_start, &tz); 925 struct timeval prog_start;
826 max_completion_time = ((targets * packets * pkt_interval) + (targets * target_interval)) + (targets * packets * crit.rta) + crit.rta; 926 gettimeofday(&prog_start, NULL);
927
928 time_t max_completion_time =
929 (config.target_interval * config.number_of_targets) +
930 (config.crit.rta * config.number_of_targets * config.number_of_packets) + config.crit.rta;
827 931
828 if (debug) { 932 if (debug) {
829 printf("packets: %u, targets: %u\n" 933 printf("packets: %u, targets: %u\n"
830 "target_interval: %0.3f, pkt_interval %0.3f\n" 934 "target_interval: %0.3f\n"
831 "crit.rta: %0.3f\n" 935 "crit.rta: %0.3f\n"
832 "max_completion_time: %0.3f\n", 936 "max_completion_time: %0.3f\n",
833 packets, targets, (float)target_interval / 1000, (float)pkt_interval / 1000, (float)crit.rta / 1000, 937 config.number_of_packets, config.number_of_targets,
938 (float)config.target_interval / 1000, (float)config.crit.rta / 1000,
834 (float)max_completion_time / 1000); 939 (float)max_completion_time / 1000);
835 } 940 }
836 941
837 if (debug) { 942 if (debug) {
838 if (max_completion_time > (u_int)timeout * 1000000) { 943 if (max_completion_time > (timeout * 1000000)) {
839 printf("max_completion_time: %llu timeout: %u\n", max_completion_time, timeout); 944 printf("max_completion_time: %ld timeout: %u\n", max_completion_time, timeout);
840 printf("Timeout must be at least %llu\n", max_completion_time / 1000000 + 1); 945 printf("Timeout must be at least %ld\n", (max_completion_time / 1000000) + 1);
841 } 946 }
842 } 947 }
843 948
844 if (debug) { 949 if (debug) {
845 printf("crit = {%u, %u%%}, warn = {%u, %u%%}\n", crit.rta, crit.pl, warn.rta, warn.pl); 950 printf("crit = {%ld, %u%%}, warn = {%ld, %u%%}\n", config.crit.rta, config.crit.pl,
846 printf("pkt_interval: %u target_interval: %u retry_interval: %u\n", pkt_interval, target_interval, retry_interval); 951 config.warn.rta, config.warn.pl);
847 printf("icmp_pkt_size: %u timeout: %u\n", icmp_pkt_size, timeout); 952 printf("target_interval: %ld\n", config.target_interval);
953 printf("icmp_pkt_size: %u timeout: %u\n", config.icmp_data_size + ICMP_MINLEN, timeout);
848 } 954 }
849 955
850 if (packets > 20) { 956 if (config.min_hosts_alive < -1) {
851 errno = 0; 957 errno = 0;
852 crash("packets is > 20 (%d)", packets); 958 crash("minimum alive hosts is negative (%i)", config.min_hosts_alive);
853 } 959 }
854 960
855 if (min_hosts_alive < -1) { 961 // Build an index table of all targets
856 errno = 0; 962 ping_target *host = config.targets;
857 crash("minimum alive hosts is negative (%i)", min_hosts_alive); 963 ping_target **table = malloc(sizeof(ping_target *) * config.number_of_targets);
858 }
859
860 host = list;
861 table = malloc(sizeof(struct rta_host *) * targets);
862 if (!table) { 964 if (!table) {
863 crash("main(): malloc failed for host table"); 965 crash("main(): malloc failed for host table");
864 } 966 }
865 967
866 i = 0; 968 unsigned short target_index = 0;
867 while (host) { 969 while (host) {
868 host->id = i * packets; 970 host->id = target_index * config.number_of_packets;
869 table[i] = host; 971 table[target_index] = host;
870 host = host->next; 972 host = host->next;
871 i++; 973 target_index++;
872 } 974 }
873 975
874 run_checks(); 976 time_t target_interval = config.target_interval;
977
978 check_icmp_state program_state = check_icmp_state_init();
979
980 run_checks(config.icmp_data_size, &target_interval, config.sender_id, config.mode,
981 max_completion_time, prog_start, table, config.number_of_packets, sockset,
982 config.number_of_targets, &program_state);
875 983
876 errno = 0; 984 errno = 0;
877 finish(0);
878 985
879 return (0); 986 mp_check overall = mp_check_init();
880} 987 finish(0, config.modes, config.min_hosts_alive, config.warn, config.crit,
988 config.number_of_targets, &program_state, config.hosts, config.number_of_hosts,
989 &overall);
990
991 if (sockset.socket4) {
992 close(sockset.socket4);
993 }
994 if (sockset.socket6) {
995 close(sockset.socket6);
996 }
881 997
882static void run_checks(void) { 998 mp_exit(overall);
883 u_int i, t; 999}
884 u_int final_wait, time_passed;
885 1000
1001static void run_checks(unsigned short icmp_pkt_size, time_t *target_interval,
1002 const uint16_t sender_id, const check_icmp_execution_mode mode,
1003 const time_t max_completion_time, const struct timeval prog_start,
1004 ping_target **table, const unsigned short packets,
1005 const check_icmp_socket_set sockset, const unsigned short number_of_targets,
1006 check_icmp_state *program_state) {
886 /* this loop might actually violate the pkt_interval or target_interval 1007 /* this loop might actually violate the pkt_interval or target_interval
887 * settings, but only if there aren't any packets on the wire which 1008 * settings, but only if there aren't any packets on the wire which
888 * indicates that the target can handle an increased packet rate */ 1009 * indicates that the target can handle an increased packet rate */
889 for (i = 0; i < packets; i++) { 1010 for (unsigned int packet_index = 0; packet_index < packets; packet_index++) {
890 for (t = 0; t < targets; t++) { 1011 for (unsigned int target_index = 0; target_index < number_of_targets; target_index++) {
891 /* don't send useless packets */ 1012 /* don't send useless packets */
892 if (!targets_alive) { 1013 if (!targets_alive(number_of_targets, program_state->targets_down)) {
893 finish(0); 1014 return;
894 } 1015 }
895 if (table[t]->flags & FLAG_LOST_CAUSE) { 1016 if (table[target_index]->flags & FLAG_LOST_CAUSE) {
896 if (debug) { 1017 if (debug) {
897 printf("%s is a lost cause. not sending any more\n", table[t]->name); 1018
1019 char address[INET6_ADDRSTRLEN];
1020 parse_address(&table[target_index]->address, address, sizeof(address));
1021 printf("%s is a lost cause. not sending any more\n", address);
898 } 1022 }
899 continue; 1023 continue;
900 } 1024 }
901 1025
902 /* we're still in the game, so send next packet */ 1026 /* we're still in the game, so send next packet */
903 (void)send_icmp_ping(icmp_sock, table[t]); 1027 (void)send_icmp_ping(sockset, table[target_index], icmp_pkt_size, sender_id,
904 wait_for_reply(icmp_sock, target_interval); 1028 program_state);
1029
1030 /* wrap up if all targets are declared dead */
1031 if (targets_alive(number_of_targets, program_state->targets_down) ||
1032 get_timevaldiff(prog_start, prog_start) < max_completion_time ||
1033 !(mode == MODE_HOSTCHECK && program_state->targets_down)) {
1034 wait_for_reply(sockset, *target_interval, icmp_pkt_size, target_interval, sender_id,
1035 table, packets, number_of_targets, program_state);
1036 }
1037 }
1038 if (targets_alive(number_of_targets, program_state->targets_down) ||
1039 get_timevaldiff_to_now(prog_start) < max_completion_time ||
1040 !(mode == MODE_HOSTCHECK && program_state->targets_down)) {
1041 wait_for_reply(sockset, number_of_targets, icmp_pkt_size, target_interval, sender_id,
1042 table, packets, number_of_targets, program_state);
905 } 1043 }
906 wait_for_reply(icmp_sock, pkt_interval * targets);
907 } 1044 }
908 1045
909 if (icmp_pkts_en_route && targets_alive) { 1046 if (icmp_pkts_en_route(program_state->icmp_sent, program_state->icmp_recv,
910 time_passed = get_timevaldiff(NULL, NULL); 1047 program_state->icmp_lost) &&
911 final_wait = max_completion_time - time_passed; 1048 targets_alive(number_of_targets, program_state->targets_down)) {
1049 time_t time_passed = get_timevaldiff_to_now(prog_start);
1050 time_t final_wait = max_completion_time - time_passed;
912 1051
913 if (debug) { 1052 if (debug) {
914 printf("time_passed: %u final_wait: %u max_completion_time: %llu\n", time_passed, final_wait, max_completion_time); 1053 printf("time_passed: %ld final_wait: %ld max_completion_time: %ld\n", time_passed,
1054 final_wait, max_completion_time);
915 } 1055 }
916 if (time_passed > max_completion_time) { 1056 if (time_passed > max_completion_time) {
917 if (debug) { 1057 if (debug) {
918 printf("Time passed. Finishing up\n"); 1058 printf("Time passed. Finishing up\n");
919 } 1059 }
920 finish(0); 1060 return;
921 } 1061 }
922 1062
923 /* catch the packets that might come in within the timeframe, but 1063 /* catch the packets that might come in within the timeframe, but
924 * haven't yet */ 1064 * haven't yet */
925 if (debug) { 1065 if (debug) {
926 printf("Waiting for %u micro-seconds (%0.3f msecs)\n", final_wait, (float)final_wait / 1000); 1066 printf("Waiting for %ld micro-seconds (%0.3f msecs)\n", final_wait,
1067 (float)final_wait / 1000);
1068 }
1069 if (targets_alive(number_of_targets, program_state->targets_down) ||
1070 get_timevaldiff_to_now(prog_start) < max_completion_time ||
1071 !(mode == MODE_HOSTCHECK && program_state->targets_down)) {
1072 wait_for_reply(sockset, final_wait, icmp_pkt_size, target_interval, sender_id, table,
1073 packets, number_of_targets, program_state);
927 } 1074 }
928 wait_for_reply(icmp_sock, final_wait);
929 } 1075 }
930} 1076}
931 1077
@@ -939,18 +1085,11 @@ static void run_checks(void) {
939 * both: 1085 * both:
940 * icmp echo reply : the rest 1086 * icmp echo reply : the rest
941 */ 1087 */
942static int wait_for_reply(int sock, u_int t) { 1088static int wait_for_reply(check_icmp_socket_set sockset, const time_t time_interval,
943 int n, hlen; 1089 unsigned short icmp_pkt_size, time_t *target_interval, uint16_t sender_id,
944 static unsigned char buf[65536]; 1090 ping_target **table, const unsigned short packets,
945 struct sockaddr_storage resp_addr; 1091 const unsigned short number_of_targets, check_icmp_state *program_state) {
946 union ip_hdr *ip;
947 union icmp_packet packet; 1092 union icmp_packet packet;
948 struct rta_host *host;
949 struct icmp_ping_data data;
950 struct timeval wait_start, now;
951 u_int tdiff, i, per_pkt_wait;
952 double jitter_tmp;
953
954 if (!(packet.buf = malloc(icmp_pkt_size))) { 1093 if (!(packet.buf = malloc(icmp_pkt_size))) {
955 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", icmp_pkt_size); 1094 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", icmp_pkt_size);
956 return -1; /* might be reached if we're in debug mode */ 1095 return -1; /* might be reached if we're in debug mode */
@@ -959,177 +1098,174 @@ static int wait_for_reply(int sock, u_int t) {
959 memset(packet.buf, 0, icmp_pkt_size); 1098 memset(packet.buf, 0, icmp_pkt_size);
960 1099
961 /* if we can't listen or don't have anything to listen to, just return */ 1100 /* if we can't listen or don't have anything to listen to, just return */
962 if (!t || !icmp_pkts_en_route) { 1101 if (!time_interval || !icmp_pkts_en_route(program_state->icmp_sent, program_state->icmp_recv,
1102 program_state->icmp_lost)) {
963 free(packet.buf); 1103 free(packet.buf);
964 return 0; 1104 return 0;
965 } 1105 }
966 1106
967 gettimeofday(&wait_start, &tz); 1107 // Get current time stamp
968 1108 struct timeval wait_start;
969 i = t; 1109 gettimeofday(&wait_start, NULL);
970 per_pkt_wait = t / icmp_pkts_en_route;
971 while (icmp_pkts_en_route && get_timevaldiff(&wait_start, NULL) < i) {
972 t = per_pkt_wait;
973 1110
974 /* wrap up if all targets are declared dead */ 1111 struct sockaddr_storage resp_addr;
975 if (!targets_alive || get_timevaldiff(&prog_start, NULL) >= max_completion_time || (mode == MODE_HOSTCHECK && targets_down)) { 1112 time_t per_pkt_wait =
976 finish(0); 1113 time_interval / icmp_pkts_en_route(program_state->icmp_sent, program_state->icmp_recv,
977 } 1114 program_state->icmp_lost);
1115 static unsigned char buf[65536];
1116 union ip_hdr *ip_header;
1117 struct timeval packet_received_timestamp;
1118 while (icmp_pkts_en_route(program_state->icmp_sent, program_state->icmp_recv,
1119 program_state->icmp_lost) &&
1120 get_timevaldiff_to_now(wait_start) < time_interval) {
1121 time_t loop_time_interval = per_pkt_wait;
978 1122
979 /* reap responses until we hit a timeout */ 1123 /* reap responses until we hit a timeout */
980 n = recvfrom_wto(sock, buf, sizeof(buf), (struct sockaddr *)&resp_addr, &t, &now); 1124 recvfrom_wto_wrapper recv_foo =
981 if (!n) { 1125 recvfrom_wto(sockset, buf, sizeof(buf), (struct sockaddr *)&resp_addr,
1126 &loop_time_interval, &packet_received_timestamp);
1127 if (!recv_foo.received) {
982 if (debug > 1) { 1128 if (debug > 1) {
983 printf("recvfrom_wto() timed out during a %u usecs wait\n", per_pkt_wait); 1129 printf("recvfrom_wto() timed out during a %ld usecs wait\n", per_pkt_wait);
984 } 1130 }
985 continue; /* timeout for this one, so keep trying */ 1131 continue; /* timeout for this one, so keep trying */
986 } 1132 }
987 if (n < 0) { 1133
1134 if (recv_foo.received < 0) {
988 if (debug) { 1135 if (debug) {
989 printf("recvfrom_wto() returned errors\n"); 1136 printf("recvfrom_wto() returned errors\n");
990 } 1137 }
991 free(packet.buf); 1138 free(packet.buf);
992 return n; 1139 return (int)recv_foo.received;
993 } 1140 }
994 1141
995 // FIXME: with ipv6 we don't have an ip header here 1142 if (recv_foo.recv_proto != AF_INET6) {
996 if (address_family != AF_INET6) { 1143 ip_header = (union ip_hdr *)buf;
997 ip = (union ip_hdr *)buf;
998 1144
999 if (debug > 1) { 1145 if (debug > 1) {
1000 char address[INET6_ADDRSTRLEN]; 1146 char address[INET6_ADDRSTRLEN];
1001 parse_address(&resp_addr, address, sizeof(address)); 1147 parse_address(&resp_addr, address, sizeof(address));
1002 printf("received %u bytes from %s\n", address_family == AF_INET6 ? ntohs(ip->ip6.ip6_plen) : ntohs(ip->ip.ip_len), address); 1148 printf("received %u bytes from %s\n",
1149 address_family == AF_INET6 ? ntohs(ip_header->ip6.ip6_plen)
1150 : ntohs(ip_header->ip.ip_len),
1151 address);
1003 } 1152 }
1004 } 1153 }
1005 1154
1006 /* obsolete. alpha on tru64 provides the necessary defines, but isn't broken */ 1155 int hlen = (recv_foo.recv_proto == AF_INET6) ? 0 : ip_header->ip.ip_hl << 2;
1007 /* #if defined( __alpha__ ) && __STDC__ && !defined( __GLIBC__ ) */ 1156
1008 /* alpha headers are decidedly broken. Using an ansi compiler, 1157 if (recv_foo.received < (hlen + ICMP_MINLEN)) {
1009 * they provide ip_vhl instead of ip_hl and ip_v, so we mask
1010 * off the bottom 4 bits */
1011 /* hlen = (ip->ip_vhl & 0x0f) << 2; */
1012 /* #else */
1013 hlen = (address_family == AF_INET6) ? 0 : ip->ip.ip_hl << 2;
1014 /* #endif */
1015
1016 if (n < (hlen + ICMP_MINLEN)) {
1017 char address[INET6_ADDRSTRLEN]; 1158 char address[INET6_ADDRSTRLEN];
1018 parse_address(&resp_addr, address, sizeof(address)); 1159 parse_address(&resp_addr, address, sizeof(address));
1019 crash("received packet too short for ICMP (%d bytes, expected %d) from %s\n", n, hlen + icmp_pkt_size, address); 1160 crash("received packet too short for ICMP (%ld bytes, expected %d) from %s\n",
1161 recv_foo.received, hlen + icmp_pkt_size, address);
1020 } 1162 }
1021 /* else if(debug) { */
1022 /* printf("ip header size: %u, packet size: %u (expected %u, %u)\n", */
1023 /* hlen, ntohs(ip->ip_len) - hlen, */
1024 /* sizeof(struct ip), icmp_pkt_size); */
1025 /* } */
1026
1027 /* check the response */ 1163 /* check the response */
1028
1029 memcpy(packet.buf, buf + hlen, icmp_pkt_size); 1164 memcpy(packet.buf, buf + hlen, icmp_pkt_size);
1030 /* address_family == AF_INET6 ? sizeof(struct icmp6_hdr)
1031 : sizeof(struct icmp));*/
1032 1165
1033 if ((address_family == PF_INET && (ntohs(packet.icp->icmp_id) != pid || packet.icp->icmp_type != ICMP_ECHOREPLY || 1166 if ((recv_foo.recv_proto == AF_INET &&
1034 ntohs(packet.icp->icmp_seq) >= targets * packets)) || 1167 (ntohs(packet.icp->icmp_id) != sender_id || packet.icp->icmp_type != ICMP_ECHOREPLY ||
1035 (address_family == PF_INET6 && (ntohs(packet.icp6->icmp6_id) != pid || packet.icp6->icmp6_type != ICMP6_ECHO_REPLY || 1168 ntohs(packet.icp->icmp_seq) >= number_of_targets * packets)) ||
1036 ntohs(packet.icp6->icmp6_seq) >= targets * packets))) { 1169 (recv_foo.recv_proto == AF_INET6 &&
1170 (ntohs(packet.icp6->icmp6_id) != sender_id ||
1171 packet.icp6->icmp6_type != ICMP6_ECHO_REPLY ||
1172 ntohs(packet.icp6->icmp6_seq) >= number_of_targets * packets))) {
1037 if (debug > 2) { 1173 if (debug > 2) {
1038 printf("not a proper ICMP_ECHOREPLY\n"); 1174 printf("not a proper ICMP_ECHOREPLY\n");
1039 } 1175 }
1040 handle_random_icmp(buf + hlen, &resp_addr); 1176
1177 handle_random_icmp(buf + hlen, &resp_addr, target_interval, sender_id, table, packets,
1178 number_of_targets, program_state);
1179
1041 continue; 1180 continue;
1042 } 1181 }
1043 1182
1044 /* this is indeed a valid response */ 1183 /* this is indeed a valid response */
1045 if (address_family == PF_INET) { 1184 ping_target *target;
1185 struct icmp_ping_data data;
1186 if (address_family == AF_INET) {
1046 memcpy(&data, packet.icp->icmp_data, sizeof(data)); 1187 memcpy(&data, packet.icp->icmp_data, sizeof(data));
1047 if (debug > 2) { 1188 if (debug > 2) {
1048 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", (unsigned long)sizeof(data), ntohs(packet.icp->icmp_id), 1189 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", sizeof(data),
1049 ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum); 1190 ntohs(packet.icp->icmp_id), ntohs(packet.icp->icmp_seq),
1191 packet.icp->icmp_cksum);
1050 } 1192 }
1051 host = table[ntohs(packet.icp->icmp_seq) / packets]; 1193 target = table[ntohs(packet.icp->icmp_seq) / packets];
1052 } else { 1194 } else {
1053 memcpy(&data, &packet.icp6->icmp6_dataun.icmp6_un_data8[4], sizeof(data)); 1195 memcpy(&data, &packet.icp6->icmp6_dataun.icmp6_un_data8[4], sizeof(data));
1054 if (debug > 2) { 1196 if (debug > 2) {
1055 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", (unsigned long)sizeof(data), ntohs(packet.icp6->icmp6_id), 1197 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", sizeof(data),
1056 ntohs(packet.icp6->icmp6_seq), packet.icp6->icmp6_cksum); 1198 ntohs(packet.icp6->icmp6_id), ntohs(packet.icp6->icmp6_seq),
1199 packet.icp6->icmp6_cksum);
1057 } 1200 }
1058 host = table[ntohs(packet.icp6->icmp6_seq) / packets]; 1201 target = table[ntohs(packet.icp6->icmp6_seq) / packets];
1059 } 1202 }
1060 1203
1061 tdiff = get_timevaldiff(&data.stime, &now); 1204 time_t tdiff = get_timevaldiff(data.stime, packet_received_timestamp);
1062 1205
1063 if (host->last_tdiff > 0) { 1206 if (target->last_tdiff > 0) {
1064 /* Calculate jitter */ 1207 /* Calculate jitter */
1065 if (host->last_tdiff > tdiff) { 1208 double jitter_tmp;
1066 jitter_tmp = host->last_tdiff - tdiff; 1209 if (target->last_tdiff > tdiff) {
1210 jitter_tmp = (double)(target->last_tdiff - tdiff);
1067 } else { 1211 } else {
1068 jitter_tmp = tdiff - host->last_tdiff; 1212 jitter_tmp = (double)(tdiff - target->last_tdiff);
1069 } 1213 }
1070 1214
1071 if (host->jitter == 0) { 1215 if (target->jitter == 0) {
1072 host->jitter = jitter_tmp; 1216 target->jitter = jitter_tmp;
1073 host->jitter_max = jitter_tmp; 1217 target->jitter_max = jitter_tmp;
1074 host->jitter_min = jitter_tmp; 1218 target->jitter_min = jitter_tmp;
1075 } else { 1219 } else {
1076 host->jitter += jitter_tmp; 1220 target->jitter += jitter_tmp;
1077 1221
1078 if (jitter_tmp < host->jitter_min) { 1222 if (jitter_tmp < target->jitter_min) {
1079 host->jitter_min = jitter_tmp; 1223 target->jitter_min = jitter_tmp;
1080 } 1224 }
1081 1225
1082 if (jitter_tmp > host->jitter_max) { 1226 if (jitter_tmp > target->jitter_max) {
1083 host->jitter_max = jitter_tmp; 1227 target->jitter_max = jitter_tmp;
1084 } 1228 }
1085 } 1229 }
1086 1230
1087 /* Check if packets in order */ 1231 /* Check if packets in order */
1088 if (host->last_icmp_seq >= packet.icp->icmp_seq) { 1232 if (target->last_icmp_seq >= packet.icp->icmp_seq) {
1089 host->order_status = STATE_CRITICAL; 1233 target->found_out_of_order_packets = true;
1090 } 1234 }
1091 } 1235 }
1092 host->last_tdiff = tdiff; 1236 target->last_tdiff = tdiff;
1093 1237
1094 host->last_icmp_seq = packet.icp->icmp_seq; 1238 target->last_icmp_seq = packet.icp->icmp_seq;
1095 1239
1096 host->time_waited += tdiff; 1240 target->time_waited += tdiff;
1097 host->icmp_recv++; 1241 target->icmp_recv++;
1098 icmp_recv++; 1242 program_state->icmp_recv++;
1099 1243
1100 if (tdiff > (unsigned int)host->rtmax) { 1244 if (tdiff > (unsigned int)target->rtmax) {
1101 host->rtmax = tdiff; 1245 target->rtmax = (double)tdiff;
1102 } 1246 }
1103 1247
1104 if ((host->rtmin == INFINITY) || (tdiff < (unsigned int)host->rtmin)) { 1248 if ((target->rtmin == INFINITY) || (tdiff < (unsigned int)target->rtmin)) {
1105 host->rtmin = tdiff; 1249 target->rtmin = (double)tdiff;
1106 } 1250 }
1107 1251
1108 if (debug) { 1252 if (debug) {
1109 char address[INET6_ADDRSTRLEN]; 1253 char address[INET6_ADDRSTRLEN];
1110 parse_address(&resp_addr, address, sizeof(address)); 1254 parse_address(&resp_addr, address, sizeof(address));
1111 1255
1112 switch (address_family) { 1256 switch (recv_foo.recv_proto) {
1113 case AF_INET: { 1257 case AF_INET: {
1114 printf("%0.3f ms rtt from %s, outgoing ttl: %u, incoming ttl: %u, max: %0.3f, min: %0.3f\n", (float)tdiff / 1000, address, 1258 printf("%0.3f ms rtt from %s, incoming ttl: %u, max: %0.3f, min: %0.3f\n",
1115 ttl, ip->ip.ip_ttl, (float)host->rtmax / 1000, (float)host->rtmin / 1000); 1259 (float)tdiff / 1000, address, ip_header->ip.ip_ttl,
1260 (float)target->rtmax / 1000, (float)target->rtmin / 1000);
1116 break; 1261 break;
1117 }; 1262 };
1118 case AF_INET6: { 1263 case AF_INET6: {
1119 printf("%0.3f ms rtt from %s, outgoing ttl: %u, max: %0.3f, min: %0.3f\n", (float)tdiff / 1000, address, ttl, 1264 printf("%0.3f ms rtt from %s, max: %0.3f, min: %0.3f\n", (float)tdiff / 1000,
1120 (float)host->rtmax / 1000, (float)host->rtmin / 1000); 1265 address, (float)target->rtmax / 1000, (float)target->rtmin / 1000);
1121 }; 1266 };
1122 } 1267 }
1123 } 1268 }
1124
1125 /* if we're in hostcheck mode, exit with limited printouts */
1126 if (mode == MODE_HOSTCHECK) {
1127 printf("OK - %s responds to ICMP. Packet %u, rta %0.3fms|"
1128 "pkt=%u;;;0;%u rta=%0.3f;%0.3f;%0.3f;;\n",
1129 host->name, icmp_recv, (float)tdiff / 1000, icmp_recv, packets, (float)tdiff / 1000, (float)warn.rta / 1000,
1130 (float)crit.rta / 1000);
1131 exit(STATE_OK);
1132 }
1133 } 1269 }
1134 1270
1135 free(packet.buf); 1271 free(packet.buf);
@@ -1137,38 +1273,28 @@ static int wait_for_reply(int sock, u_int t) {
1137} 1273}
1138 1274
1139/* the ping functions */ 1275/* the ping functions */
1140static int send_icmp_ping(int sock, struct rta_host *host) { 1276static int send_icmp_ping(const check_icmp_socket_set sockset, ping_target *host,
1141 long int len; 1277 const unsigned short icmp_pkt_size, const uint16_t sender_id,
1142 size_t addrlen; 1278 check_icmp_state *program_state) {
1143 struct icmp_ping_data data; 1279 void *buf = calloc(1, icmp_pkt_size);
1144 struct msghdr hdr;
1145 struct iovec iov;
1146 struct timeval tv;
1147 void *buf = NULL;
1148
1149 if (sock == -1) {
1150 errno = 0;
1151 crash("Attempt to send on bogus socket");
1152 return -1;
1153 }
1154
1155 if (!buf) { 1280 if (!buf) {
1156 if (!(buf = malloc(icmp_pkt_size))) { 1281 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", icmp_pkt_size);
1157 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", icmp_pkt_size); 1282 return -1; /* might be reached if we're in debug mode */
1158 return -1; /* might be reached if we're in debug mode */
1159 }
1160 } 1283 }
1161 memset(buf, 0, icmp_pkt_size);
1162 1284
1163 if ((gettimeofday(&tv, &tz)) == -1) { 1285 struct timeval current_time;
1286 if ((gettimeofday(&current_time, NULL)) == -1) {
1164 free(buf); 1287 free(buf);
1165 return -1; 1288 return -1;
1166 } 1289 }
1167 1290
1291 struct icmp_ping_data data;
1168 data.ping_id = 10; /* host->icmp.icmp_sent; */ 1292 data.ping_id = 10; /* host->icmp.icmp_sent; */
1169 memcpy(&data.stime, &tv, sizeof(tv)); 1293 memcpy(&data.stime, &current_time, sizeof(current_time));
1170 1294
1171 if (address_family == AF_INET) { 1295 socklen_t addrlen = 0;
1296
1297 if (host->address.ss_family == AF_INET) {
1172 struct icmp *icp = (struct icmp *)buf; 1298 struct icmp *icp = (struct icmp *)buf;
1173 addrlen = sizeof(struct sockaddr_in); 1299 addrlen = sizeof(struct sockaddr_in);
1174 1300
@@ -1177,15 +1303,19 @@ static int send_icmp_ping(int sock, struct rta_host *host) {
1177 icp->icmp_type = ICMP_ECHO; 1303 icp->icmp_type = ICMP_ECHO;
1178 icp->icmp_code = 0; 1304 icp->icmp_code = 0;
1179 icp->icmp_cksum = 0; 1305 icp->icmp_cksum = 0;
1180 icp->icmp_id = htons(pid); 1306 icp->icmp_id = htons((uint16_t)sender_id);
1181 icp->icmp_seq = htons(host->id++); 1307 icp->icmp_seq = htons(host->id++);
1182 icp->icmp_cksum = icmp_checksum((uint16_t *)buf, (size_t)icmp_pkt_size); 1308 icp->icmp_cksum = icmp_checksum((uint16_t *)buf, (size_t)icmp_pkt_size);
1183 1309
1184 if (debug > 2) { 1310 if (debug > 2) {
1185 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", (unsigned long)sizeof(data), 1311 char address[INET6_ADDRSTRLEN];
1186 ntohs(icp->icmp_id), ntohs(icp->icmp_seq), icp->icmp_cksum, host->name); 1312 parse_address((&host->address), address, sizeof(address));
1313
1314 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n",
1315 sizeof(data), ntohs(icp->icmp_id), ntohs(icp->icmp_seq), icp->icmp_cksum,
1316 address);
1187 } 1317 }
1188 } else { 1318 } else if (host->address.ss_family == AF_INET6) {
1189 struct icmp6_hdr *icp6 = (struct icmp6_hdr *)buf; 1319 struct icmp6_hdr *icp6 = (struct icmp6_hdr *)buf;
1190 addrlen = sizeof(struct sockaddr_in6); 1320 addrlen = sizeof(struct sockaddr_in6);
1191 1321
@@ -1194,659 +1324,431 @@ static int send_icmp_ping(int sock, struct rta_host *host) {
1194 icp6->icmp6_type = ICMP6_ECHO_REQUEST; 1324 icp6->icmp6_type = ICMP6_ECHO_REQUEST;
1195 icp6->icmp6_code = 0; 1325 icp6->icmp6_code = 0;
1196 icp6->icmp6_cksum = 0; 1326 icp6->icmp6_cksum = 0;
1197 icp6->icmp6_id = htons(pid); 1327 icp6->icmp6_id = htons((uint16_t)sender_id);
1198 icp6->icmp6_seq = htons(host->id++); 1328 icp6->icmp6_seq = htons(host->id++);
1199 // let checksum be calculated automatically 1329 // let checksum be calculated automatically
1200 1330
1201 if (debug > 2) { 1331 if (debug > 2) {
1202 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", (unsigned long)sizeof(data), 1332 char address[INET6_ADDRSTRLEN];
1203 ntohs(icp6->icmp6_id), ntohs(icp6->icmp6_seq), icp6->icmp6_cksum, host->name); 1333 parse_address((&host->address), address, sizeof(address));
1334
1335 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to target %s\n",
1336 sizeof(data), ntohs(icp6->icmp6_id), ntohs(icp6->icmp6_seq), icp6->icmp6_cksum,
1337 address);
1204 } 1338 }
1339 } else {
1340 // unknown address family
1341 crash("unknown address family in %s", __func__);
1205 } 1342 }
1206 1343
1344 struct iovec iov;
1207 memset(&iov, 0, sizeof(iov)); 1345 memset(&iov, 0, sizeof(iov));
1208 iov.iov_base = buf; 1346 iov.iov_base = buf;
1209 iov.iov_len = icmp_pkt_size; 1347 iov.iov_len = icmp_pkt_size;
1210 1348
1349 struct msghdr hdr;
1211 memset(&hdr, 0, sizeof(hdr)); 1350 memset(&hdr, 0, sizeof(hdr));
1212 hdr.msg_name = (struct sockaddr *)&host->saddr_in; 1351 hdr.msg_name = (struct sockaddr *)&host->address;
1213 hdr.msg_namelen = addrlen; 1352 hdr.msg_namelen = addrlen;
1214 hdr.msg_iov = &iov; 1353 hdr.msg_iov = &iov;
1215 hdr.msg_iovlen = 1; 1354 hdr.msg_iovlen = 1;
1216 1355
1217 errno = 0; 1356 errno = 0;
1218 1357
1219/* MSG_CONFIRM is a linux thing and only available on linux kernels >= 2.3.15, see send(2) */ 1358 long int len;
1359 /* MSG_CONFIRM is a linux thing and only available on linux kernels >= 2.3.15, see send(2) */
1360 if (host->address.ss_family == AF_INET) {
1361#ifdef MSG_CONFIRM
1362 len = sendmsg(sockset.socket4, &hdr, MSG_CONFIRM);
1363#else
1364 len = sendmsg(sockset.socket4, &hdr, 0);
1365#endif
1366 } else if (host->address.ss_family == AF_INET6) {
1220#ifdef MSG_CONFIRM 1367#ifdef MSG_CONFIRM
1221 len = sendmsg(sock, &hdr, MSG_CONFIRM); 1368 len = sendmsg(sockset.socket6, &hdr, MSG_CONFIRM);
1222#else 1369#else
1223 len = sendmsg(sock, &hdr, 0); 1370 len = sendmsg(sockset.socket6, &hdr, 0);
1224#endif 1371#endif
1372 } else {
1373 assert(false);
1374 }
1225 1375
1226 free(buf); 1376 free(buf);
1227 1377
1228 if (len < 0 || (unsigned int)len != icmp_pkt_size) { 1378 if (len < 0 || (unsigned int)len != icmp_pkt_size) {
1229 if (debug) { 1379 if (debug) {
1230 char address[INET6_ADDRSTRLEN]; 1380 char address[INET6_ADDRSTRLEN];
1231 parse_address((struct sockaddr_storage *)&host->saddr_in, address, sizeof(address)); 1381 parse_address((&host->address), address, sizeof(address));
1232 printf("Failed to send ping to %s: %s\n", address, strerror(errno)); 1382 printf("Failed to send ping to %s: %s\n", address, strerror(errno));
1233 } 1383 }
1234 errno = 0; 1384 errno = 0;
1235 return -1; 1385 return -1;
1236 } 1386 }
1237 1387
1238 icmp_sent++; 1388 program_state->icmp_sent++;
1239 host->icmp_sent++; 1389 host->icmp_sent++;
1240 1390
1241 return 0; 1391 return 0;
1242} 1392}
1243 1393
1244static int recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr, u_int *timo, struct timeval *tv) { 1394static recvfrom_wto_wrapper recvfrom_wto(const check_icmp_socket_set sockset, void *buf,
1245 u_int slen; 1395 const unsigned int len, struct sockaddr *saddr,
1246 int n, ret; 1396 time_t *timeout, struct timeval *received_timestamp) {
1247 struct timeval to, then, now;
1248 fd_set rd, wr;
1249#ifdef HAVE_MSGHDR_MSG_CONTROL 1397#ifdef HAVE_MSGHDR_MSG_CONTROL
1250 char ans_data[4096]; 1398 char ans_data[4096];
1251#endif // HAVE_MSGHDR_MSG_CONTROL 1399#endif // HAVE_MSGHDR_MSG_CONTROL
1252 struct msghdr hdr;
1253 struct iovec iov;
1254#ifdef SO_TIMESTAMP 1400#ifdef SO_TIMESTAMP
1255 struct cmsghdr *chdr; 1401 struct cmsghdr *chdr;
1256#endif 1402#endif
1257 1403
1258 if (!*timo) { 1404 recvfrom_wto_wrapper result = {
1405 .received = 0,
1406 .recv_proto = AF_UNSPEC,
1407 };
1408
1409 if (!*timeout) {
1259 if (debug) { 1410 if (debug) {
1260 printf("*timo is not\n"); 1411 printf("*timeout is not\n");
1261 } 1412 }
1262 return 0; 1413 return result;
1414 }
1415
1416 struct timeval real_timeout;
1417 real_timeout.tv_sec = *timeout / 1000000;
1418 real_timeout.tv_usec = (*timeout - (real_timeout.tv_sec * 1000000));
1419
1420 // Dummy fds for select
1421 fd_set dummy_write_fds;
1422 FD_ZERO(&dummy_write_fds);
1423
1424 // Read fds for select with the socket
1425 fd_set read_fds;
1426 FD_ZERO(&read_fds);
1427
1428 if (sockset.socket4 != -1) {
1429 FD_SET(sockset.socket4, &read_fds);
1430 }
1431 if (sockset.socket6 != -1) {
1432 FD_SET(sockset.socket6, &read_fds);
1263 } 1433 }
1264 1434
1265 to.tv_sec = *timo / 1000000; 1435 int nfds = (sockset.socket4 > sockset.socket6 ? sockset.socket4 : sockset.socket6) + 1;
1266 to.tv_usec = (*timo - (to.tv_sec * 1000000)); 1436
1437 struct timeval then;
1438 gettimeofday(&then, NULL);
1267 1439
1268 FD_ZERO(&rd);
1269 FD_ZERO(&wr);
1270 FD_SET(sock, &rd);
1271 errno = 0; 1440 errno = 0;
1272 gettimeofday(&then, &tz); 1441 int select_return = select(nfds, &read_fds, &dummy_write_fds, NULL, &real_timeout);
1273 n = select(sock + 1, &rd, &wr, NULL, &to); 1442 if (select_return < 0) {
1274 if (n < 0) {
1275 crash("select() in recvfrom_wto"); 1443 crash("select() in recvfrom_wto");
1276 } 1444 }
1277 gettimeofday(&now, &tz);
1278 *timo = get_timevaldiff(&then, &now);
1279 1445
1280 if (!n) { 1446 struct timeval now;
1281 return 0; /* timeout */ 1447 gettimeofday(&now, NULL);
1448 *timeout = get_timevaldiff(then, now);
1449
1450 if (!select_return) {
1451 return result; /* timeout */
1282 } 1452 }
1283 1453
1284 slen = sizeof(struct sockaddr_storage); 1454 unsigned int slen = sizeof(struct sockaddr_storage);
1285 1455
1286 memset(&iov, 0, sizeof(iov)); 1456 struct iovec iov = {
1287 iov.iov_base = buf; 1457 .iov_base = buf,
1288 iov.iov_len = len; 1458 .iov_len = len,
1459 };
1289 1460
1290 memset(&hdr, 0, sizeof(hdr)); 1461 struct msghdr hdr = {
1291 hdr.msg_name = saddr; 1462 .msg_name = saddr,
1292 hdr.msg_namelen = slen; 1463 .msg_namelen = slen,
1293 hdr.msg_iov = &iov; 1464 .msg_iov = &iov,
1294 hdr.msg_iovlen = 1; 1465 .msg_iovlen = 1,
1295#ifdef HAVE_MSGHDR_MSG_CONTROL 1466#ifdef HAVE_MSGHDR_MSG_CONTROL
1296 hdr.msg_control = ans_data; 1467 .msg_control = ans_data,
1297 hdr.msg_controllen = sizeof(ans_data); 1468 .msg_controllen = sizeof(ans_data),
1298#endif 1469#endif
1470 };
1471
1472 ssize_t ret;
1473 if (FD_ISSET(sockset.socket4, &read_fds)) {
1474 ret = recvmsg(sockset.socket4, &hdr, 0);
1475 result.recv_proto = AF_INET;
1476 } else if (FD_ISSET(sockset.socket6, &read_fds)) {
1477 ret = recvmsg(sockset.socket6, &hdr, 0);
1478 result.recv_proto = AF_INET6;
1479 } else {
1480 assert(false);
1481 }
1482
1483 result.received = ret;
1299 1484
1300 ret = recvmsg(sock, &hdr, 0);
1301#ifdef SO_TIMESTAMP 1485#ifdef SO_TIMESTAMP
1302 for (chdr = CMSG_FIRSTHDR(&hdr); chdr; chdr = CMSG_NXTHDR(&hdr, chdr)) { 1486 for (chdr = CMSG_FIRSTHDR(&hdr); chdr; chdr = CMSG_NXTHDR(&hdr, chdr)) {
1303 if (chdr->cmsg_level == SOL_SOCKET && chdr->cmsg_type == SO_TIMESTAMP && chdr->cmsg_len >= CMSG_LEN(sizeof(struct timeval))) { 1487 if (chdr->cmsg_level == SOL_SOCKET && chdr->cmsg_type == SO_TIMESTAMP &&
1304 memcpy(tv, CMSG_DATA(chdr), sizeof(*tv)); 1488 chdr->cmsg_len >= CMSG_LEN(sizeof(struct timeval))) {
1489 memcpy(received_timestamp, CMSG_DATA(chdr), sizeof(*received_timestamp));
1305 break; 1490 break;
1306 } 1491 }
1307 } 1492 }
1308 1493
1309 if (!chdr) 1494 if (!chdr) {
1495 gettimeofday(received_timestamp, NULL);
1496 }
1497#else
1498 gettimeofday(tv, NULL);
1310#endif // SO_TIMESTAMP 1499#endif // SO_TIMESTAMP
1311 gettimeofday(tv, &tz);
1312 return (ret);
1313}
1314 1500
1315static void finish(int sig) { 1501 return (result);
1316 u_int i = 0; 1502}
1317 unsigned char pl;
1318 double rta;
1319 struct rta_host *host;
1320 const char *status_string[] = {"OK", "WARNING", "CRITICAL", "UNKNOWN", "DEPENDENT"};
1321 int hosts_ok = 0;
1322 int hosts_warn = 0;
1323 int this_status;
1324 double R;
1325 1503
1504static void finish(int sig, check_icmp_mode_switches modes, int min_hosts_alive,
1505 check_icmp_threshold warn, check_icmp_threshold crit,
1506 const unsigned short number_of_targets, check_icmp_state *program_state,
1507 check_icmp_target_container host_list[], unsigned short number_of_hosts,
1508 mp_check overall[static 1]) {
1509 // Deactivate alarm
1326 alarm(0); 1510 alarm(0);
1511
1327 if (debug > 1) { 1512 if (debug > 1) {
1328 printf("finish(%d) called\n", sig); 1513 printf("finish(%d) called\n", sig);
1329 } 1514 }
1330 1515
1331 if (icmp_sock != -1) {
1332 close(icmp_sock);
1333 }
1334 if (udp_sock != -1) {
1335 close(udp_sock);
1336 }
1337 if (tcp_sock != -1) {
1338 close(tcp_sock);
1339 }
1340
1341 if (debug) { 1516 if (debug) {
1342 printf("icmp_sent: %u icmp_recv: %u icmp_lost: %u\n", icmp_sent, icmp_recv, icmp_lost); 1517 printf("icmp_sent: %u icmp_recv: %u icmp_lost: %u\n", program_state->icmp_sent,
1343 printf("targets: %u targets_alive: %u\n", targets, targets_alive); 1518 program_state->icmp_recv, program_state->icmp_lost);
1519 printf("targets: %u targets_alive: %u\n", number_of_targets,
1520 targets_alive(number_of_targets, program_state->targets_down));
1344 } 1521 }
1345 1522
1346 /* iterate thrice to calculate values, give output, and print perfparse */ 1523 // loop over targets to evaluate each one
1347 status = STATE_OK; 1524 int targets_ok = 0;
1348 host = list; 1525 int targets_warn = 0;
1349 1526 for (unsigned short i = 0; i < number_of_hosts; i++) {
1350 while (host) { 1527 evaluate_host_wrapper host_check = evaluate_host(host_list[i], modes, warn, crit);
1351 this_status = STATE_OK;
1352
1353 if (!host->icmp_recv) {
1354 /* rta 0 is ofcourse not entirely correct, but will still show up
1355 * conspicuously as missing entries in perfparse and cacti */
1356 pl = 100;
1357 rta = 0;
1358 status = STATE_CRITICAL;
1359 /* up the down counter if not already counted */
1360 if (!(host->flags & FLAG_LOST_CAUSE) && targets_alive) {
1361 targets_down++;
1362 }
1363 } else {
1364 pl = ((host->icmp_sent - host->icmp_recv) * 100) / host->icmp_sent;
1365 rta = (double)host->time_waited / host->icmp_recv;
1366 }
1367
1368 if (host->icmp_recv > 1) {
1369 /*
1370 * This algorithm is probably pretty much blindly copied from
1371 * locations like this one: https://www.slac.stanford.edu/comp/net/wan-mon/tutorial.html#mos
1372 * It calculates a MOS value (range of 1 to 5, where 1 is bad and 5 really good).
1373 * According to some quick research MOS originates from the Audio/Video transport network area.
1374 * Whether it can and should be computed from ICMP data, I can not say.
1375 *
1376 * Anyway the basic idea is to map a value "R" with a range of 0-100 to the MOS value
1377 *
1378 * MOS stands likely for Mean Opinion Score ( https://en.wikipedia.org/wiki/Mean_Opinion_Score )
1379 *
1380 * More links:
1381 * - https://confluence.slac.stanford.edu/display/IEPM/MOS
1382 */
1383 host->jitter = (host->jitter / (host->icmp_recv - 1) / 1000);
1384
1385 /*
1386 * Take the average round trip latency (in milliseconds), add
1387 * round trip jitter, but double the impact to latency
1388 * then add 10 for protocol latencies (in milliseconds).
1389 */
1390 host->EffectiveLatency = (rta / 1000) + host->jitter * 2 + 10;
1391
1392 if (host->EffectiveLatency < 160) {
1393 R = 93.2 - (host->EffectiveLatency / 40);
1394 } else {
1395 R = 93.2 - ((host->EffectiveLatency - 120) / 10);
1396 }
1397
1398 // Now, let us deduct 2.5 R values per percentage of packet loss (i.e. a
1399 // loss of 5% will be entered as 5).
1400 R = R - (pl * 2.5);
1401 1528
1402 if (R < 0) { 1529 targets_ok += host_check.targets_ok;
1403 R = 0; 1530 targets_warn += host_check.targets_warn;
1404 }
1405 1531
1406 host->score = R; 1532 mp_add_subcheck_to_check(overall, host_check.sc_host);
1407 host->mos = 1 + ((0.035) * R) + ((.000007) * R * (R - 60) * (100 - R));
1408 } else {
1409 host->jitter = 0;
1410 host->jitter_min = 0;
1411 host->jitter_max = 0;
1412 host->mos = 0;
1413 }
1414
1415 host->pl = pl;
1416 host->rta = rta;
1417
1418 /* if no new mode selected, use old schema */
1419 if (!rta_mode && !pl_mode && !jitter_mode && !score_mode && !mos_mode && !order_mode) {
1420 rta_mode = true;
1421 pl_mode = true;
1422 }
1423
1424 /* Check which mode is on and do the warn / Crit stuff */
1425 if (rta_mode) {
1426 if (rta >= crit.rta) {
1427 this_status = STATE_CRITICAL;
1428 status = STATE_CRITICAL;
1429 host->rta_status = STATE_CRITICAL;
1430 } else if (status != STATE_CRITICAL && (rta >= warn.rta)) {
1431 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
1432 status = STATE_WARNING;
1433 host->rta_status = STATE_WARNING;
1434 }
1435 }
1436
1437 if (pl_mode) {
1438 if (pl >= crit.pl) {
1439 this_status = STATE_CRITICAL;
1440 status = STATE_CRITICAL;
1441 host->pl_status = STATE_CRITICAL;
1442 } else if (status != STATE_CRITICAL && (pl >= warn.pl)) {
1443 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
1444 status = STATE_WARNING;
1445 host->pl_status = STATE_WARNING;
1446 }
1447 }
1448
1449 if (jitter_mode) {
1450 if (host->jitter >= crit.jitter) {
1451 this_status = STATE_CRITICAL;
1452 status = STATE_CRITICAL;
1453 host->jitter_status = STATE_CRITICAL;
1454 } else if (status != STATE_CRITICAL && (host->jitter >= warn.jitter)) {
1455 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
1456 status = STATE_WARNING;
1457 host->jitter_status = STATE_WARNING;
1458 }
1459 }
1460
1461 if (mos_mode) {
1462 if (host->mos <= crit.mos) {
1463 this_status = STATE_CRITICAL;
1464 status = STATE_CRITICAL;
1465 host->mos_status = STATE_CRITICAL;
1466 } else if (status != STATE_CRITICAL && (host->mos <= warn.mos)) {
1467 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
1468 status = STATE_WARNING;
1469 host->mos_status = STATE_WARNING;
1470 }
1471 }
1472
1473 if (score_mode) {
1474 if (host->score <= crit.score) {
1475 this_status = STATE_CRITICAL;
1476 status = STATE_CRITICAL;
1477 host->score_status = STATE_CRITICAL;
1478 } else if (status != STATE_CRITICAL && (host->score <= warn.score)) {
1479 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
1480 status = STATE_WARNING;
1481 host->score_status = STATE_WARNING;
1482 }
1483 }
1484
1485 if (this_status == STATE_WARNING) {
1486 hosts_warn++;
1487 } else if (this_status == STATE_OK) {
1488 hosts_ok++;
1489 }
1490
1491 host = host->next;
1492 } 1533 }
1493 1534
1494 /* this is inevitable */
1495 if (!targets_alive) {
1496 status = STATE_CRITICAL;
1497 }
1498 if (min_hosts_alive > -1) { 1535 if (min_hosts_alive > -1) {
1499 if (hosts_ok >= min_hosts_alive) { 1536 mp_subcheck sc_min_targets_alive = mp_subcheck_init();
1500 status = STATE_OK; 1537 sc_min_targets_alive = mp_set_subcheck_default_state(sc_min_targets_alive, STATE_OK);
1501 } else if ((hosts_ok + hosts_warn) >= min_hosts_alive) { 1538
1502 status = STATE_WARNING; 1539 if (targets_ok >= min_hosts_alive) {
1503 } 1540 sc_min_targets_alive = mp_set_subcheck_state(sc_min_targets_alive, STATE_OK);
1504 } 1541 xasprintf(&sc_min_targets_alive.output, "%u targets OK of a minimum of %u", targets_ok,
1505 printf("%s - ", status_string[status]); 1542 min_hosts_alive);
1506 1543
1507 host = list; 1544 // Overwrite main state here
1508 while (host) { 1545 overall->evaluation_function = &mp_eval_ok;
1509 if (debug) { 1546 } else if ((targets_ok + targets_warn) >= min_hosts_alive) {
1510 puts(""); 1547 sc_min_targets_alive = mp_set_subcheck_state(sc_min_targets_alive, STATE_WARNING);
1511 } 1548 xasprintf(&sc_min_targets_alive.output, "%u targets OK or Warning of a minimum of %u",
1512 1549 targets_ok + targets_warn, min_hosts_alive);
1513 if (i) { 1550 overall->evaluation_function = &mp_eval_warning;
1514 if (i < targets) { 1551 } else {
1515 printf(" :: "); 1552 sc_min_targets_alive = mp_set_subcheck_state(sc_min_targets_alive, STATE_CRITICAL);
1516 } else { 1553 xasprintf(&sc_min_targets_alive.output, "%u targets OK or Warning of a minimum of %u",
1517 printf("\n"); 1554 targets_ok + targets_warn, min_hosts_alive);
1518 } 1555 overall->evaluation_function = &mp_eval_critical;
1519 }
1520
1521 i++;
1522
1523 if (!host->icmp_recv) {
1524 status = STATE_CRITICAL;
1525 host->rtmin = 0;
1526 host->jitter_min = 0;
1527
1528 if (host->flags & FLAG_LOST_CAUSE) {
1529 char address[INET6_ADDRSTRLEN];
1530 parse_address(&host->error_addr, address, sizeof(address));
1531 printf("%s: %s @ %s. rta nan, lost %d%%", host->name, get_icmp_error_msg(host->icmp_type, host->icmp_code), address, 100);
1532 } else { /* not marked as lost cause, so we have no flags for it */
1533 printf("%s: rta nan, lost 100%%", host->name);
1534 }
1535 } else { /* !icmp_recv */
1536 printf("%s", host->name);
1537 /* rta text output */
1538 if (rta_mode) {
1539 if (status == STATE_OK) {
1540 printf(" rta %0.3fms", host->rta / 1000);
1541 } else if (status == STATE_WARNING && host->rta_status == status) {
1542 printf(" rta %0.3fms > %0.3fms", (float)host->rta / 1000, (float)warn.rta / 1000);
1543 } else if (status == STATE_CRITICAL && host->rta_status == status) {
1544 printf(" rta %0.3fms > %0.3fms", (float)host->rta / 1000, (float)crit.rta / 1000);
1545 }
1546 }
1547
1548 /* pl text output */
1549 if (pl_mode) {
1550 if (status == STATE_OK) {
1551 printf(" lost %u%%", host->pl);
1552 } else if (status == STATE_WARNING && host->pl_status == status) {
1553 printf(" lost %u%% > %u%%", host->pl, warn.pl);
1554 } else if (status == STATE_CRITICAL && host->pl_status == status) {
1555 printf(" lost %u%% > %u%%", host->pl, crit.pl);
1556 }
1557 }
1558
1559 /* jitter text output */
1560 if (jitter_mode) {
1561 if (status == STATE_OK) {
1562 printf(" jitter %0.3fms", (float)host->jitter);
1563 } else if (status == STATE_WARNING && host->jitter_status == status) {
1564 printf(" jitter %0.3fms > %0.3fms", (float)host->jitter, warn.jitter);
1565 } else if (status == STATE_CRITICAL && host->jitter_status == status) {
1566 printf(" jitter %0.3fms > %0.3fms", (float)host->jitter, crit.jitter);
1567 }
1568 }
1569
1570 /* mos text output */
1571 if (mos_mode) {
1572 if (status == STATE_OK) {
1573 printf(" MOS %0.1f", (float)host->mos);
1574 } else if (status == STATE_WARNING && host->mos_status == status) {
1575 printf(" MOS %0.1f < %0.1f", (float)host->mos, (float)warn.mos);
1576 } else if (status == STATE_CRITICAL && host->mos_status == status) {
1577 printf(" MOS %0.1f < %0.1f", (float)host->mos, (float)crit.mos);
1578 }
1579 }
1580
1581 /* score text output */
1582 if (score_mode) {
1583 if (status == STATE_OK) {
1584 printf(" Score %u", (int)host->score);
1585 } else if (status == STATE_WARNING && host->score_status == status) {
1586 printf(" Score %u < %u", (int)host->score, (int)warn.score);
1587 } else if (status == STATE_CRITICAL && host->score_status == status) {
1588 printf(" Score %u < %u", (int)host->score, (int)crit.score);
1589 }
1590 }
1591
1592 /* order statis text output */
1593 if (order_mode) {
1594 if (status == STATE_OK) {
1595 printf(" Packets in order");
1596 } else if (status == STATE_CRITICAL && host->order_status == status) {
1597 printf(" Packets out of order");
1598 }
1599 }
1600 }
1601 host = host->next;
1602 }
1603
1604 /* iterate once more for pretty perfparse output */
1605 if (!(!rta_mode && !pl_mode && !jitter_mode && !score_mode && !mos_mode && order_mode)) {
1606 printf("|");
1607 }
1608 i = 0;
1609 host = list;
1610 while (host) {
1611 if (debug) {
1612 puts("");
1613 }
1614
1615 if (rta_mode) {
1616 if (host->pl < 100) {
1617 printf("%srta=%0.3fms;%0.3f;%0.3f;0; %srtmax=%0.3fms;;;; %srtmin=%0.3fms;;;; ", (targets > 1) ? host->name : "",
1618 host->rta / 1000, (float)warn.rta / 1000, (float)crit.rta / 1000, (targets > 1) ? host->name : "",
1619 (float)host->rtmax / 1000, (targets > 1) ? host->name : "",
1620 (host->rtmin < INFINITY) ? (float)host->rtmin / 1000 : (float)0);
1621 } else {
1622 printf("%srta=U;;;; %srtmax=U;;;; %srtmin=U;;;; ", (targets > 1) ? host->name : "", (targets > 1) ? host->name : "",
1623 (targets > 1) ? host->name : "");
1624 }
1625 }
1626
1627 if (pl_mode) {
1628 printf("%spl=%u%%;%u;%u;0;100 ", (targets > 1) ? host->name : "", host->pl, warn.pl, crit.pl);
1629 }
1630
1631 if (jitter_mode) {
1632 if (host->pl < 100) {
1633 printf("%sjitter_avg=%0.3fms;%0.3f;%0.3f;0; %sjitter_max=%0.3fms;;;; %sjitter_min=%0.3fms;;;; ",
1634 (targets > 1) ? host->name : "", (float)host->jitter, (float)warn.jitter, (float)crit.jitter,
1635 (targets > 1) ? host->name : "", (float)host->jitter_max / 1000, (targets > 1) ? host->name : "",
1636 (float)host->jitter_min / 1000);
1637 } else {
1638 printf("%sjitter_avg=U;;;; %sjitter_max=U;;;; %sjitter_min=U;;;; ", (targets > 1) ? host->name : "",
1639 (targets > 1) ? host->name : "", (targets > 1) ? host->name : "");
1640 }
1641 }
1642
1643 if (mos_mode) {
1644 if (host->pl < 100) {
1645 printf("%smos=%0.1f;%0.1f;%0.1f;0;5 ", (targets > 1) ? host->name : "", (float)host->mos, (float)warn.mos, (float)crit.mos);
1646 } else {
1647 printf("%smos=U;;;; ", (targets > 1) ? host->name : "");
1648 }
1649 }
1650
1651 if (score_mode) {
1652 if (host->pl < 100) {
1653 printf("%sscore=%u;%u;%u;0;100 ", (targets > 1) ? host->name : "", (int)host->score, (int)warn.score, (int)crit.score);
1654 } else {
1655 printf("%sscore=U;;;; ", (targets > 1) ? host->name : "");
1656 }
1657 } 1556 }
1658 1557
1659 host = host->next; 1558 mp_add_subcheck_to_check(overall, sc_min_targets_alive);
1660 }
1661
1662 if (min_hosts_alive > -1) {
1663 if (hosts_ok >= min_hosts_alive) {
1664 status = STATE_OK;
1665 } else if ((hosts_ok + hosts_warn) >= min_hosts_alive) {
1666 status = STATE_WARNING;
1667 }
1668 } 1559 }
1669 1560
1670 /* finish with an empty line */ 1561 /* finish with an empty line */
1671 puts("");
1672 if (debug) { 1562 if (debug) {
1673 printf("targets: %u, targets_alive: %u, hosts_ok: %u, hosts_warn: %u, min_hosts_alive: %i\n", targets, targets_alive, hosts_ok, 1563 printf(
1674 hosts_warn, min_hosts_alive); 1564 "targets: %u, targets_alive: %u, hosts_ok: %u, hosts_warn: %u, min_hosts_alive: %i\n",
1565 number_of_targets, targets_alive(number_of_targets, program_state->targets_down),
1566 targets_ok, targets_warn, min_hosts_alive);
1675 } 1567 }
1676
1677 exit(status);
1678} 1568}
1679 1569
1680static u_int get_timevaldiff(struct timeval *early, struct timeval *later) { 1570static time_t get_timevaldiff(const struct timeval earlier, const struct timeval later) {
1681 u_int ret;
1682 struct timeval now;
1683
1684 if (!later) {
1685 gettimeofday(&now, &tz);
1686 later = &now;
1687 }
1688 if (!early) {
1689 early = &prog_start;
1690 }
1691
1692 /* if early > later we return 0 so as to indicate a timeout */ 1571 /* if early > later we return 0 so as to indicate a timeout */
1693 if (early->tv_sec > later->tv_sec || (early->tv_sec == later->tv_sec && early->tv_usec > later->tv_usec)) { 1572 if (earlier.tv_sec > later.tv_sec ||
1573 (earlier.tv_sec == later.tv_sec && earlier.tv_usec > later.tv_usec)) {
1694 return 0; 1574 return 0;
1695 } 1575 }
1696 ret = (later->tv_sec - early->tv_sec) * 1000000; 1576
1697 ret += later->tv_usec - early->tv_usec; 1577 time_t ret = (later.tv_sec - earlier.tv_sec) * 1000000;
1578 ret += later.tv_usec - earlier.tv_usec;
1698 1579
1699 return ret; 1580 return ret;
1700} 1581}
1701 1582
1702static int add_target_ip(char *arg, struct sockaddr_storage *in) { 1583static time_t get_timevaldiff_to_now(struct timeval earlier) {
1703 struct rta_host *host; 1584 struct timeval now;
1704 struct sockaddr_in *sin, *host_sin; 1585 gettimeofday(&now, NULL);
1705 struct sockaddr_in6 *sin6, *host_sin6; 1586
1587 return get_timevaldiff(earlier, now);
1588}
1589
1590static add_target_ip_wrapper add_target_ip(struct sockaddr_storage address) {
1591 assert((address.ss_family == AF_INET) || (address.ss_family == AF_INET6));
1706 1592
1707 if (address_family == AF_INET) { 1593 if (debug) {
1708 sin = (struct sockaddr_in *)in; 1594 char straddr[INET6_ADDRSTRLEN];
1595 parse_address((&address), straddr, sizeof(straddr));
1596 printf("add_target_ip called with: %s\n", straddr);
1597 }
1598 struct sockaddr_in *sin;
1599 struct sockaddr_in6 *sin6;
1600 if (address.ss_family == AF_INET) {
1601 sin = (struct sockaddr_in *)&address;
1602 } else if (address.ss_family == AF_INET6) {
1603 sin6 = (struct sockaddr_in6 *)&address;
1709 } else { 1604 } else {
1710 sin6 = (struct sockaddr_in6 *)in; 1605 assert(false);
1711 } 1606 }
1712 1607
1608 add_target_ip_wrapper result = {
1609 .error_code = OK,
1610 .target = NULL,
1611 };
1612
1713 /* disregard obviously stupid addresses 1613 /* disregard obviously stupid addresses
1714 * (I didn't find an ipv6 equivalent to INADDR_NONE) */ 1614 * (I didn't find an ipv6 equivalent to INADDR_NONE) */
1715 if (((address_family == AF_INET && (sin->sin_addr.s_addr == INADDR_NONE || sin->sin_addr.s_addr == INADDR_ANY))) || 1615 if (((address.ss_family == AF_INET &&
1716 (address_family == AF_INET6 && (sin6->sin6_addr.s6_addr == in6addr_any.s6_addr))) { 1616 (sin->sin_addr.s_addr == INADDR_NONE || sin->sin_addr.s_addr == INADDR_ANY))) ||
1717 return -1; 1617 (address.ss_family == AF_INET6 && (sin6->sin6_addr.s6_addr == in6addr_any.s6_addr))) {
1618 result.error_code = ERROR;
1619 return result;
1718 } 1620 }
1719 1621
1720 /* no point in adding two identical IP's, so don't. ;) */ 1622 // get string representation of address
1721 host = list; 1623 char straddr[INET6_ADDRSTRLEN];
1722 while (host) { 1624 parse_address((&address), straddr, sizeof(straddr));
1723 host_sin = (struct sockaddr_in *)&host->saddr_in;
1724 host_sin6 = (struct sockaddr_in6 *)&host->saddr_in;
1725
1726 if ((address_family == AF_INET && host_sin->sin_addr.s_addr == sin->sin_addr.s_addr) ||
1727 (address_family == AF_INET6 && host_sin6->sin6_addr.s6_addr == sin6->sin6_addr.s6_addr)) {
1728 if (debug) {
1729 printf("Identical IP already exists. Not adding %s\n", arg);
1730 }
1731 return -1;
1732 }
1733 host = host->next;
1734 }
1735 1625
1736 /* add the fresh ip */ 1626 /* add the fresh ip */
1737 host = (struct rta_host *)malloc(sizeof(struct rta_host)); 1627 ping_target *target = (ping_target *)calloc(1, sizeof(ping_target));
1738 if (!host) { 1628 if (!target) {
1739 char straddr[INET6_ADDRSTRLEN]; 1629 crash("add_target_ip(%s): malloc(%lu) failed", straddr, sizeof(ping_target));
1740 parse_address((struct sockaddr_storage *)&in, straddr, sizeof(straddr));
1741 crash("add_target_ip(%s, %s): malloc(%lu) failed", arg, straddr, sizeof(struct rta_host));
1742 } 1630 }
1743 memset(host, 0, sizeof(struct rta_host));
1744 1631
1745 /* set the values. use calling name for output */ 1632 ping_target_create_wrapper target_wrapper = ping_target_create(address);
1746 host->name = strdup(arg);
1747 1633
1748 /* fill out the sockaddr_storage struct */ 1634 if (target_wrapper.errorcode == OK) {
1749 if (address_family == AF_INET) { 1635 *target = target_wrapper.host;
1750 host_sin = (struct sockaddr_in *)&host->saddr_in; 1636 result.target = target;
1751 host_sin->sin_family = AF_INET;
1752 host_sin->sin_addr.s_addr = sin->sin_addr.s_addr;
1753 } else { 1637 } else {
1754 host_sin6 = (struct sockaddr_in6 *)&host->saddr_in; 1638 result.error_code = target_wrapper.errorcode;
1755 host_sin6->sin6_family = AF_INET6;
1756 memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr, sizeof host_sin6->sin6_addr.s6_addr);
1757 }
1758
1759 /* fill out the sockaddr_in struct */
1760 host->rtmin = INFINITY;
1761 host->rtmax = 0;
1762 host->jitter = 0;
1763 host->jitter_max = 0;
1764 host->jitter_min = INFINITY;
1765 host->last_tdiff = 0;
1766 host->order_status = STATE_OK;
1767 host->last_icmp_seq = 0;
1768 host->rta_status = 0;
1769 host->pl_status = 0;
1770 host->jitter_status = 0;
1771 host->mos_status = 0;
1772 host->score_status = 0;
1773 host->pl_status = 0;
1774
1775 if (!list) {
1776 list = cursor = host;
1777 } else {
1778 cursor->next = host;
1779 } 1639 }
1780 1640
1781 cursor = host; 1641 return result;
1782 targets++;
1783
1784 return 0;
1785} 1642}
1786 1643
1787/* wrapper for add_target_ip */ 1644/* wrapper for add_target_ip */
1788static int add_target(char *arg) { 1645static add_target_wrapper add_target(char *arg, const check_icmp_execution_mode mode,
1789 int error, result = -1; 1646 sa_family_t enforced_proto) {
1790 struct sockaddr_storage ip; 1647 if (debug > 0) {
1791 struct addrinfo hints, *res, *p; 1648 printf("add_target called with argument %s\n", arg);
1792 struct sockaddr_in *sin; 1649 }
1793 struct sockaddr_in6 *sin6; 1650
1794 1651 struct sockaddr_storage address_storage = {};
1795 switch (address_family) { 1652 struct sockaddr_in *sin = NULL;
1796 case -1: 1653 struct sockaddr_in6 *sin6 = NULL;
1797 /* -4 and -6 are not specified on cmdline */ 1654 int error_code = -1;
1798 address_family = AF_INET; 1655
1799 sin = (struct sockaddr_in *)&ip; 1656 switch (enforced_proto) {
1800 result = inet_pton(address_family, arg, &sin->sin_addr); 1657 case AF_UNSPEC:
1801#ifdef USE_IPV6 1658 /*
1802 if (result != 1) { 1659 * no enforced protocol family
1803 address_family = AF_INET6; 1660 * try to parse the address with each one
1804 sin6 = (struct sockaddr_in6 *)&ip; 1661 */
1805 result = inet_pton(address_family, arg, &sin6->sin6_addr); 1662 sin = (struct sockaddr_in *)&address_storage;
1806 } 1663 error_code = inet_pton(AF_INET, arg, &sin->sin_addr);
1807#endif 1664 address_storage.ss_family = AF_INET;
1808 /* If we don't find any valid addresses, we still don't know the address_family */ 1665
1809 if (result != 1) { 1666 if (error_code != 1) {
1810 address_family = -1; 1667 sin6 = (struct sockaddr_in6 *)&address_storage;
1668 error_code = inet_pton(AF_INET6, arg, &sin6->sin6_addr);
1669 address_storage.ss_family = AF_INET6;
1811 } 1670 }
1812 break; 1671 break;
1813 case AF_INET: 1672 case AF_INET:
1814 sin = (struct sockaddr_in *)&ip; 1673 sin = (struct sockaddr_in *)&address_storage;
1815 result = inet_pton(address_family, arg, &sin->sin_addr); 1674 error_code = inet_pton(AF_INET, arg, &sin->sin_addr);
1675 address_storage.ss_family = AF_INET;
1816 break; 1676 break;
1817 case AF_INET6: 1677 case AF_INET6:
1818 sin6 = (struct sockaddr_in6 *)&ip; 1678 sin6 = (struct sockaddr_in6 *)&address_storage;
1819 result = inet_pton(address_family, arg, &sin6->sin6_addr); 1679 error_code = inet_pton(AF_INET, arg, &sin6->sin6_addr);
1680 address_storage.ss_family = AF_INET6;
1820 break; 1681 break;
1821 default: 1682 default:
1822 crash("Address family not supported"); 1683 crash("Address family not supported");
1823 } 1684 }
1824 1685
1825 /* don't resolve if we don't have to */ 1686 add_target_wrapper result = {
1826 if (result == 1) { 1687 .error_code = OK,
1688 .targets = NULL,
1689 .has_v4 = false,
1690 .has_v6 = false,
1691 };
1692
1693 // if error_code == 1 the address was a valid address parsed above
1694 if (error_code == 1) {
1827 /* don't add all ip's if we were given a specific one */ 1695 /* don't add all ip's if we were given a specific one */
1828 return add_target_ip(arg, &ip); 1696 add_target_ip_wrapper targeted = add_target_ip(address_storage);
1829 } else { 1697
1830 errno = 0; 1698 if (targeted.error_code != OK) {
1831 memset(&hints, 0, sizeof(hints)); 1699 result.error_code = ERROR;
1832 if (address_family == -1) { 1700 return result;
1833 hints.ai_family = AF_UNSPEC;
1834 } else {
1835 hints.ai_family = address_family == AF_INET ? PF_INET : PF_INET6;
1836 } 1701 }
1837 hints.ai_socktype = SOCK_RAW; 1702
1838 if ((error = getaddrinfo(arg, NULL, &hints, &res)) != 0) { 1703 if (targeted.target->address.ss_family == AF_INET) {
1839 errno = 0; 1704 result.has_v4 = true;
1840 crash("Failed to resolve %s: %s", arg, gai_strerror(error)); 1705 } else if (targeted.target->address.ss_family == AF_INET6) {
1841 return -1; 1706 result.has_v6 = true;
1707 } else {
1708 assert(false);
1842 } 1709 }
1843 address_family = res->ai_family; 1710 result.targets = targeted.target;
1711 result.number_of_targets = 1;
1712 return result;
1713 }
1714
1715 struct addrinfo hints = {};
1716 errno = 0;
1717 hints.ai_family = enforced_proto;
1718 hints.ai_socktype = SOCK_RAW;
1719
1720 int error;
1721 struct addrinfo *res;
1722 if ((error = getaddrinfo(arg, NULL, &hints, &res)) != 0) {
1723 errno = 0;
1724 crash("Failed to resolve %s: %s", arg, gai_strerror(error));
1725 result.error_code = ERROR;
1726 return result;
1844 } 1727 }
1845 1728
1846 /* possibly add all the IP's as targets */ 1729 /* possibly add all the IP's as targets */
1847 for (p = res; p != NULL; p = p->ai_next) { 1730 for (struct addrinfo *address = res; address != NULL; address = address->ai_next) {
1848 memcpy(&ip, p->ai_addr, p->ai_addrlen); 1731 struct sockaddr_storage temporary_ip_address;
1849 add_target_ip(arg, &ip); 1732 memcpy(&temporary_ip_address, address->ai_addr, address->ai_addrlen);
1733
1734 add_target_ip_wrapper tmp = add_target_ip(temporary_ip_address);
1735
1736 if (tmp.error_code != OK) {
1737 // No proper error handling
1738 // What to do?
1739 } else {
1740 if (result.targets == NULL) {
1741 result.targets = tmp.target;
1742 result.number_of_targets = 1;
1743 } else {
1744 result.number_of_targets += ping_target_list_append(result.targets, tmp.target);
1745 }
1746 if (address->ai_family == AF_INET) {
1747 result.has_v4 = true;
1748 } else if (address->ai_family == AF_INET6) {
1749 result.has_v6 = true;
1750 }
1751 }
1850 1752
1851 /* this is silly, but it works */ 1753 /* this is silly, but it works */
1852 if (mode == MODE_HOSTCHECK || mode == MODE_ALL) { 1754 if (mode == MODE_HOSTCHECK || mode == MODE_ALL) {
@@ -1855,20 +1757,22 @@ static int add_target(char *arg) {
1855 } 1757 }
1856 continue; 1758 continue;
1857 } 1759 }
1760
1761 // Abort after first hit if not in of the modes above
1858 break; 1762 break;
1859 } 1763 }
1860 freeaddrinfo(res); 1764 freeaddrinfo(res);
1861 1765
1862 return 0; 1766 return result;
1863} 1767}
1864 1768
1865static void set_source_ip(char *arg) { 1769static void set_source_ip(char *arg, const int icmp_sock, sa_family_t addr_family) {
1866 struct sockaddr_in src; 1770 struct sockaddr_in src;
1867 1771
1868 memset(&src, 0, sizeof(src)); 1772 memset(&src, 0, sizeof(src));
1869 src.sin_family = address_family; 1773 src.sin_family = addr_family;
1870 if ((src.sin_addr.s_addr = inet_addr(arg)) == INADDR_NONE) { 1774 if ((src.sin_addr.s_addr = inet_addr(arg)) == INADDR_NONE) {
1871 src.sin_addr.s_addr = get_ip_address(arg); 1775 src.sin_addr.s_addr = get_ip_address(arg, icmp_sock);
1872 } 1776 }
1873 if (bind(icmp_sock, (struct sockaddr *)&src, sizeof(src)) == -1) { 1777 if (bind(icmp_sock, (struct sockaddr *)&src, sizeof(src)) == -1) {
1874 crash("Cannot bind to IP address %s", arg); 1778 crash("Cannot bind to IP address %s", arg);
@@ -1876,10 +1780,10 @@ static void set_source_ip(char *arg) {
1876} 1780}
1877 1781
1878/* TODO: Move this to netutils.c and also change check_dhcp to use that. */ 1782/* TODO: Move this to netutils.c and also change check_dhcp to use that. */
1879static in_addr_t get_ip_address(const char *ifname) { 1783static in_addr_t get_ip_address(const char *ifname, const int icmp_sock) {
1880 // TODO: Rewrite this so the function return an error and we exit somewhere else 1784 // TODO: Rewrite this so the function return an error and we exit somewhere else
1881 struct sockaddr_in ip; 1785 struct sockaddr_in ip_address;
1882 ip.sin_addr.s_addr = 0; // Fake initialization to make compiler happy 1786 ip_address.sin_addr.s_addr = 0; // Fake initialization to make compiler happy
1883#if defined(SIOCGIFADDR) 1787#if defined(SIOCGIFADDR)
1884 struct ifreq ifr; 1788 struct ifreq ifr;
1885 1789
@@ -1891,13 +1795,13 @@ static in_addr_t get_ip_address(const char *ifname) {
1891 crash("Cannot determine IP address of interface %s", ifname); 1795 crash("Cannot determine IP address of interface %s", ifname);
1892 } 1796 }
1893 1797
1894 memcpy(&ip, &ifr.ifr_addr, sizeof(ip)); 1798 memcpy(&ip_address, &ifr.ifr_addr, sizeof(ip_address));
1895#else 1799#else
1896 (void)ifname; 1800 (void)ifname;
1897 errno = 0; 1801 errno = 0;
1898 crash("Cannot get interface IP address on this platform."); 1802 crash("Cannot get interface IP address on this platform.");
1899#endif 1803#endif
1900 return ip.sin_addr.s_addr; 1804 return ip_address.sin_addr.s_addr;
1901} 1805}
1902 1806
1903/* 1807/*
@@ -1906,103 +1810,127 @@ static in_addr_t get_ip_address(const char *ifname) {
1906 * s = seconds 1810 * s = seconds
1907 * return value is in microseconds 1811 * return value is in microseconds
1908 */ 1812 */
1909static u_int get_timevar(const char *str) { 1813static get_timevar_wrapper get_timevar(const char *str) {
1910 char p, u, *ptr; 1814 get_timevar_wrapper result = {
1911 size_t len; 1815 .error_code = OK,
1912 u_int i, d; /* integer and decimal, respectively */ 1816 .time_range = 0,
1913 u_int factor = 1000; /* default to milliseconds */ 1817 };
1914 1818
1915 if (!str) { 1819 if (!str) {
1916 return 0; 1820 result.error_code = ERROR;
1821 return result;
1917 } 1822 }
1918 len = strlen(str); 1823
1824 size_t len = strlen(str);
1919 if (!len) { 1825 if (!len) {
1920 return 0; 1826 result.error_code = ERROR;
1827 return result;
1921 } 1828 }
1922 1829
1923 /* unit might be given as ms|m (millisec), 1830 /* unit might be given as ms|m (millisec),
1924 * us|u (microsec) or just plain s, for seconds */ 1831 * us|u (microsec) or just plain s, for seconds */
1925 p = '\0'; 1832 char tmp = '\0';
1926 u = str[len - 1]; 1833 char unit = str[len - 1];
1927 if (len >= 2 && !isdigit((int)str[len - 2])) { 1834 if (len >= 2 && !isdigit((int)str[len - 2])) {
1928 p = str[len - 2]; 1835 tmp = str[len - 2];
1929 } 1836 }
1930 if (p && u == 's') { 1837
1931 u = p; 1838 if (tmp && unit == 's') {
1932 } else if (!p) { 1839 unit = tmp;
1933 p = u; 1840 } else if (!tmp) {
1841 tmp = unit;
1934 } 1842 }
1843
1935 if (debug > 2) { 1844 if (debug > 2) {
1936 printf("evaluating %s, u: %c, p: %c\n", str, u, p); 1845 printf("evaluating %s, u: %c, p: %c\n", str, unit, tmp);
1937 } 1846 }
1938 1847
1939 if (u == 'u') { 1848 unsigned int factor = 1000; /* default to milliseconds */
1849 if (unit == 'u') {
1940 factor = 1; /* microseconds */ 1850 factor = 1; /* microseconds */
1941 } else if (u == 'm') { 1851 } else if (unit == 'm') {
1942 factor = 1000; /* milliseconds */ 1852 factor = 1000; /* milliseconds */
1943 } else if (u == 's') { 1853 } else if (unit == 's') {
1944 factor = 1000000; /* seconds */ 1854 factor = 1000000; /* seconds */
1945 } 1855 }
1856
1946 if (debug > 2) { 1857 if (debug > 2) {
1947 printf("factor is %u\n", factor); 1858 printf("factor is %u\n", factor);
1948 } 1859 }
1949 1860
1950 i = strtoul(str, &ptr, 0); 1861 char *ptr;
1862 unsigned long pre_radix;
1863 pre_radix = strtoul(str, &ptr, 0);
1951 if (!ptr || *ptr != '.' || strlen(ptr) < 2 || factor == 1) { 1864 if (!ptr || *ptr != '.' || strlen(ptr) < 2 || factor == 1) {
1952 return i * factor; 1865 result.time_range = (unsigned int)(pre_radix * factor);
1866 return result;
1953 } 1867 }
1954 1868
1955 /* time specified in usecs can't have decimal points, so ignore them */ 1869 /* time specified in usecs can't have decimal points, so ignore them */
1956 if (factor == 1) { 1870 if (factor == 1) {
1957 return i; 1871 result.time_range = (unsigned int)pre_radix;
1872 return result;
1958 } 1873 }
1959 1874
1960 d = strtoul(ptr + 1, NULL, 0); 1875 /* integer and decimal, respectively */
1876 unsigned int post_radix = (unsigned int)strtoul(ptr + 1, NULL, 0);
1961 1877
1962 /* d is decimal, so get rid of excess digits */ 1878 /* d is decimal, so get rid of excess digits */
1963 while (d >= factor) { 1879 while (post_radix >= factor) {
1964 d /= 10; 1880 post_radix /= 10;
1965 } 1881 }
1966 1882
1967 /* the last parenthesis avoids floating point exceptions. */ 1883 /* the last parenthesis avoids floating point exceptions. */
1968 return ((i * factor) + (d * (factor / 10))); 1884 result.time_range = (unsigned int)((pre_radix * factor) + (post_radix * (factor / 10)));
1885 return result;
1969} 1886}
1970 1887
1971/* not too good at checking errors, but it'll do (main() should barfe on -1) */ 1888static get_threshold_wrapper get_threshold(char *str, check_icmp_threshold threshold) {
1972static int get_threshold(char *str, threshold *th) { 1889 get_threshold_wrapper result = {
1973 char *p = NULL, i = 0; 1890 .errorcode = OK,
1891 .threshold = threshold,
1892 };
1974 1893
1975 if (!str || !strlen(str) || !th) { 1894 if (!str || !strlen(str)) {
1976 return -1; 1895 result.errorcode = ERROR;
1896 return result;
1977 } 1897 }
1978 1898
1979 /* pointer magic slims code by 10 lines. i is bof-stop on stupid libc's */ 1899 /* pointer magic slims code by 10 lines. i is bof-stop on stupid libc's */
1980 p = &str[strlen(str) - 1]; 1900 bool is_at_last_char = false;
1981 while (p != &str[1]) { 1901 char *tmp = &str[strlen(str) - 1];
1982 if (*p == '%') { 1902 while (tmp != &str[1]) {
1983 *p = '\0'; 1903 if (*tmp == '%') {
1984 } else if (*p == ',' && i) { 1904 *tmp = '\0';
1985 *p = '\0'; /* reset it so get_timevar(str) works nicely later */ 1905 } else if (*tmp == ',' && is_at_last_char) {
1986 th->pl = (unsigned char)strtoul(p + 1, NULL, 0); 1906 *tmp = '\0'; /* reset it so get_timevar(str) works nicely later */
1907 result.threshold.pl = (unsigned char)strtoul(tmp + 1, NULL, 0);
1987 break; 1908 break;
1988 } 1909 }
1989 i = 1; 1910 is_at_last_char = true;
1990 p--; 1911 tmp--;
1991 } 1912 }
1992 th->rta = get_timevar(str);
1993 1913
1994 if (!th->rta) { 1914 get_timevar_wrapper parsed_time = get_timevar(str);
1995 return -1; 1915
1916 if (parsed_time.error_code == OK) {
1917 result.threshold.rta = parsed_time.time_range;
1918 } else {
1919 if (debug > 1) {
1920 printf("%s: failed to parse rta threshold\n", __FUNCTION__);
1921 }
1922 result.errorcode = ERROR;
1923 return result;
1996 } 1924 }
1997 1925
1998 if (th->rta > MAXTTL * 1000000) { 1926 if (result.threshold.rta > MAXTTL * 1000000) {
1999 th->rta = MAXTTL * 1000000; 1927 result.threshold.rta = MAXTTL * 1000000;
2000 } 1928 }
2001 if (th->pl > 100) { 1929 if (result.threshold.pl > 100) {
2002 th->pl = 100; 1930 result.threshold.pl = 100;
2003 } 1931 }
2004 1932
2005 return 0; 1933 return result;
2006} 1934}
2007 1935
2008/* 1936/*
@@ -2013,184 +1941,537 @@ static int get_threshold(char *str, threshold *th) {
2013 * @param[in] length strlen(str) 1941 * @param[in] length strlen(str)
2014 * @param[out] warn Pointer to the warn threshold struct to which the values should be assigned 1942 * @param[out] warn Pointer to the warn threshold struct to which the values should be assigned
2015 * @param[out] crit Pointer to the crit threshold struct to which the values should be assigned 1943 * @param[out] crit Pointer to the crit threshold struct to which the values should be assigned
2016 * @param[in] mode Determines whether this a threshold for rta, packet_loss, jitter, mos or score (exclusively) 1944 * @param[in] mode Determines whether this a threshold for rta, packet_loss, jitter, mos or score
1945 * (exclusively)
2017 */ 1946 */
2018static bool get_threshold2(char *str, size_t length, threshold *warn, threshold *crit, threshold_mode mode) { 1947static get_threshold2_wrapper get_threshold2(char *str, size_t length, check_icmp_threshold warn,
2019 if (!str || !length || !warn || !crit) { 1948 check_icmp_threshold crit, threshold_mode mode) {
2020 return false; 1949 get_threshold2_wrapper result = {
1950 .errorcode = OK,
1951 .warn = warn,
1952 .crit = crit,
1953 };
1954
1955 if (!str || !length) {
1956 result.errorcode = ERROR;
1957 return result;
2021 } 1958 }
2022 1959
2023 // p points to the last char in str 1960 // p points to the last char in str
2024 char *p = &str[length - 1]; 1961 char *work_pointer = &str[length - 1];
2025 1962
2026 // first_iteration is bof-stop on stupid libc's 1963 // first_iteration is bof-stop on stupid libc's
2027 bool first_iteration = true; 1964 bool first_iteration = true;
2028 1965
2029 while (p != &str[0]) { 1966 while (work_pointer != &str[0]) {
2030 if ((*p == 'm') || (*p == '%')) { 1967 if ((*work_pointer == 'm') || (*work_pointer == '%')) {
2031 *p = '\0'; 1968 *work_pointer = '\0';
2032 } else if (*p == ',' && !first_iteration) { 1969 } else if (*work_pointer == ',' && !first_iteration) {
2033 *p = '\0'; /* reset it so get_timevar(str) works nicely later */ 1970 *work_pointer = '\0'; /* reset it so get_timevar(str) works nicely later */
2034 1971
2035 char *start_of_value = p + 1; 1972 char *start_of_value = work_pointer + 1;
2036 1973
2037 if (!parse_threshold2_helper(start_of_value, strlen(start_of_value), crit, mode)) { 1974 parse_threshold2_helper_wrapper tmp =
2038 return false; 1975 parse_threshold2_helper(start_of_value, strlen(start_of_value), result.crit, mode);
1976 if (tmp.errorcode != OK) {
1977 result.errorcode = ERROR;
1978 return result;
2039 } 1979 }
1980 result.crit = tmp.result;
2040 } 1981 }
2041 first_iteration = false; 1982 first_iteration = false;
2042 p--; 1983 work_pointer--;
2043 } 1984 }
2044 1985
2045 return parse_threshold2_helper(p, strlen(p), warn, mode); 1986 parse_threshold2_helper_wrapper tmp =
1987 parse_threshold2_helper(work_pointer, strlen(work_pointer), result.warn, mode);
1988 if (tmp.errorcode != OK) {
1989 result.errorcode = ERROR;
1990 } else {
1991 result.warn = tmp.result;
1992 }
1993 return result;
2046} 1994}
2047 1995
2048static bool parse_threshold2_helper(char *s, size_t length, threshold *thr, threshold_mode mode) { 1996static parse_threshold2_helper_wrapper parse_threshold2_helper(char *threshold_string,
1997 size_t length,
1998 check_icmp_threshold thr,
1999 threshold_mode mode) {
2049 char *resultChecker = {0}; 2000 char *resultChecker = {0};
2001 parse_threshold2_helper_wrapper result = {
2002 .result = thr,
2003 .errorcode = OK,
2004 };
2050 2005
2051 switch (mode) { 2006 switch (mode) {
2052 case const_rta_mode: 2007 case const_rta_mode:
2053 thr->rta = strtod(s, &resultChecker) * 1000; 2008 result.result.rta = (unsigned int)(strtod(threshold_string, &resultChecker) * 1000);
2054 break; 2009 break;
2055 case const_packet_loss_mode: 2010 case const_packet_loss_mode:
2056 thr->pl = (unsigned char)strtoul(s, &resultChecker, 0); 2011 result.result.pl = (unsigned char)strtoul(threshold_string, &resultChecker, 0);
2057 break; 2012 break;
2058 case const_jitter_mode: 2013 case const_jitter_mode:
2059 thr->jitter = strtod(s, &resultChecker); 2014 result.result.jitter = strtod(threshold_string, &resultChecker);
2060
2061 break; 2015 break;
2062 case const_mos_mode: 2016 case const_mos_mode:
2063 thr->mos = strtod(s, &resultChecker); 2017 result.result.mos = strtod(threshold_string, &resultChecker);
2064 break; 2018 break;
2065 case const_score_mode: 2019 case const_score_mode:
2066 thr->score = strtod(s, &resultChecker); 2020 result.result.score = strtod(threshold_string, &resultChecker);
2067 break; 2021 break;
2068 } 2022 }
2069 2023
2070 if (resultChecker == s) { 2024 if (resultChecker == threshold_string) {
2071 // Failed to parse 2025 // Failed to parse
2072 return false; 2026 result.errorcode = ERROR;
2027 return result;
2073 } 2028 }
2074 2029
2075 if (resultChecker != (s + length)) { 2030 if (resultChecker != (threshold_string + length)) {
2076 // Trailing symbols 2031 // Trailing symbols
2077 return false; 2032 result.errorcode = ERROR;
2078 } 2033 }
2079 2034
2080 return true; 2035 return result;
2081} 2036}
2082 2037
2083unsigned short icmp_checksum(uint16_t *p, size_t n) { 2038unsigned short icmp_checksum(uint16_t *packet, size_t packet_size) {
2084 unsigned short cksum;
2085 long sum = 0; 2039 long sum = 0;
2086 2040
2087 /* sizeof(uint16_t) == 2 */ 2041 /* sizeof(uint16_t) == 2 */
2088 while (n >= 2) { 2042 while (packet_size >= 2) {
2089 sum += *(p++); 2043 sum += *(packet++);
2090 n -= 2; 2044 packet_size -= 2;
2091 } 2045 }
2092 2046
2093 /* mop up the occasional odd byte */ 2047 /* mop up the occasional odd byte */
2094 if (n == 1) { 2048 if (packet_size == 1) {
2095 sum += *((uint8_t *)p - 1); 2049 sum += *((uint8_t *)packet - 1);
2096 } 2050 }
2097 2051
2098 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 2052 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
2099 sum += (sum >> 16); /* add carry */ 2053 sum += (sum >> 16); /* add carry */
2100 cksum = ~sum; /* ones-complement, trunc to 16 bits */ 2054 unsigned short cksum;
2055 cksum = (unsigned short)~sum; /* ones-complement, trunc to 16 bits */
2101 2056
2102 return cksum; 2057 return cksum;
2103} 2058}
2104 2059
2105void print_help(void) { 2060void print_help(void) {
2106 /*print_revision (progname);*/ /* FIXME: Why? */ 2061 // print_revision (progname); /* FIXME: Why? */
2107 printf("Copyright (c) 2005 Andreas Ericsson <ae@op5.se>\n"); 2062 printf("Copyright (c) 2005 Andreas Ericsson <ae@op5.se>\n");
2108 2063
2109 printf(COPYRIGHT, copyright, email); 2064 printf(COPYRIGHT, copyright, email);
2110 2065
2111 printf("\n\n");
2112
2113 print_usage(); 2066 print_usage();
2114 2067
2115 printf(UT_HELP_VRSN); 2068 printf(UT_HELP_VRSN);
2116 printf(UT_EXTRA_OPTS); 2069 printf(UT_EXTRA_OPTS);
2117 2070
2118 printf(" %s\n", "-H"); 2071 printf(" -H, --Host=HOST\n");
2119 printf(" %s\n", _("specify a target")); 2072 printf(" %s\n",
2120 printf(" %s\n", "[-4|-6]"); 2073 _("specify a target, might be one of: resolveable name | IPv6 address | IPv4 address\n"
2121 printf(" %s\n", _("Use IPv4 (default) or IPv6 to communicate with the targets")); 2074 " (required, can be given multiple times)"));
2122 printf(" %s\n", "-w"); 2075 printf(" %s\n", "[-4|-6], [--ipv4-only|--ipv6-only]");
2123 printf(" %s", _("warning threshold (currently ")); 2076 printf(" %s\n", _("Use IPv4 or IPv6 only to communicate with the targets"));
2124 printf("%0.3fms,%u%%)\n", (float)warn.rta / 1000, warn.pl); 2077 printf(" %s\n", "-w, --warning=WARN_VALUE");
2125 printf(" %s\n", "-c"); 2078 printf(" %s", _("warning threshold (default "));
2126 printf(" %s", _("critical threshold (currently ")); 2079 printf("%0.3fms,%u%%)\n", (float)DEFAULT_WARN_RTA / 1000, DEFAULT_WARN_PL);
2127 printf("%0.3fms,%u%%)\n", (float)crit.rta / 1000, crit.pl); 2080 printf(" %s\n", "-c, --critical=CRIT_VALUE");
2128 2081 printf(" %s", _("critical threshold (default "));
2129 printf(" %s\n", "-R"); 2082 printf("%0.3fms,%u%%)\n", (float)DEFAULT_CRIT_RTA / 1000, DEFAULT_CRIT_PL);
2130 printf(" %s\n", _("RTA, round trip average, mode warning,critical, ex. 100ms,200ms unit in ms")); 2083
2131 printf(" %s\n", "-P"); 2084 printf(" %s\n", "-R, --rta-mode-thresholds=RTA_THRESHOLDS");
2085 printf(" %s\n",
2086 _("RTA (round trip average) mode warning,critical, ex. 100ms,200ms unit in ms"));
2087 printf(" %s\n", "-P, --packet-loss-mode-thresholds=PACKET_LOSS_THRESHOLD");
2132 printf(" %s\n", _("packet loss mode, ex. 40%,50% , unit in %")); 2088 printf(" %s\n", _("packet loss mode, ex. 40%,50% , unit in %"));
2133 printf(" %s\n", "-J"); 2089 printf(" %s\n", "-J, --jitter-mode-thresholds=JITTER_MODE_THRESHOLD");
2134 printf(" %s\n", _("jitter mode warning,critical, ex. 40.000ms,50.000ms , unit in ms ")); 2090 printf(" %s\n", _("jitter mode warning,critical, ex. 40.000ms,50.000ms , unit in ms "));
2135 printf(" %s\n", "-M"); 2091 printf(" %s\n", "-M, --mos-mode-thresholds=MOS_MODE_THRESHOLD");
2136 printf(" %s\n", _("MOS mode, between 0 and 4.4 warning,critical, ex. 3.5,3.0")); 2092 printf(" %s\n", _("MOS mode, between 0 and 4.4 warning,critical, ex. 3.5,3.0"));
2137 printf(" %s\n", "-S"); 2093 printf(" %s\n", "-S, --score-mode-thresholds=SCORE_MODE_THRESHOLD");
2138 printf(" %s\n", _("score mode, max value 100 warning,critical, ex. 80,70 ")); 2094 printf(" %s\n", _("score mode, max value 100 warning,critical, ex. 80,70 "));
2139 printf(" %s\n", "-O"); 2095 printf(" %s\n", "-O, --out-of-order-packets");
2140 printf(" %s\n", _("detect out of order ICMP packts ")); 2096 printf(
2141 printf(" %s\n", "-H"); 2097 " %s\n",
2142 printf(" %s\n", _("specify a target")); 2098 _("detect out of order ICMP packets, if such packets are found, the result is CRITICAL"));
2143 printf(" %s\n", "-s"); 2099 printf(" %s\n", "[-n|-p], --number-of-packets=NUMBER_OF_PACKETS");
2144 printf(" %s\n", _("specify a source IP address or device name")); 2100 printf(" %s", _("number of packets to send (default "));
2145 printf(" %s\n", "-n"); 2101 printf("%u)\n", DEFAULT_NUMBER_OF_PACKETS);
2146 printf(" %s", _("number of packets to send (currently ")); 2102
2147 printf("%u)\n", packets);
2148 printf(" %s\n", "-p");
2149 printf(" %s", _("number of packets to send (currently "));
2150 printf("%u)\n", packets);
2151 printf(" %s\n", "-i"); 2103 printf(" %s\n", "-i");
2152 printf(" %s", _("max packet interval (currently ")); 2104 printf(" %s", _("[DEPRECATED] packet interval (default "));
2153 printf("%0.3fms)\n", (float)pkt_interval / 1000); 2105 printf("%0.3fms)\n", (float)DEFAULT_PKT_INTERVAL / 1000);
2154 printf(" %s\n", "-I"); 2106 printf(" %s", _("This option was never actually used and is just mentioned here for "
2155 printf(" %s", _("max target interval (currently ")); 2107 "historical purposes\n"));
2156 printf("%0.3fms)\n", (float)target_interval / 1000); 2108
2157 printf(" %s\n", "-m"); 2109 printf(" %s\n", "-I, --target-interval=TARGET_INTERVAL");
2158 printf(" %s", _("number of alive hosts required for success")); 2110 printf(" %s%0.3fms)\n The time interval to wait in between one target and the next\n",
2111 _("max target interval (default "), (float)DEFAULT_TARGET_INTERVAL / 1000);
2112 printf(" %s\n", "-m, --minimal-host-alive=MIN_ALIVE");
2113 printf(" %s", _("number of alive hosts required for success. If less than MIN_ALIVE hosts "
2114 "are OK, but MIN_ALIVE hosts are WARNING or OK, WARNING, else CRITICAL"));
2159 printf("\n"); 2115 printf("\n");
2160 printf(" %s\n", "-l"); 2116 printf(" %s\n", "-l, --outgoing-ttl=OUTGOING_TTL");
2161 printf(" %s", _("TTL on outgoing packets (currently ")); 2117 printf(" %s", _("TTL on outgoing packets (default "));
2162 printf("%u)\n", ttl); 2118 printf("%u)\n", DEFAULT_TTL);
2163 printf(" %s\n", "-t"); 2119 printf(" %s\n", "-b, --size=SIZE");
2164 printf(" %s", _("timeout value (seconds, currently ")); 2120 printf(" %s\n", _("Number of icmp ping data bytes to send"));
2165 printf("%u)\n", timeout); 2121 printf(" %s %lu + %d)\n", _("Packet size will be SIZE + icmp header (default"),
2166 printf(" %s\n", "-b"); 2122 DEFAULT_PING_DATA_SIZE, ICMP_MINLEN);
2167 printf(" %s\n", _("Number of icmp data bytes to send")); 2123 printf(" %s\n", "-v, --verbose");
2168 printf(" %s %u + %d)\n", _("Packet size will be data bytes + icmp header (currently"), icmp_data_size, ICMP_MINLEN); 2124 printf(" %s\n", _("Verbosity, can be given multiple times (for debugging)"));
2169 printf(" %s\n", "-v"); 2125
2170 printf(" %s\n", _("verbose")); 2126 printf(UT_OUTPUT_FORMAT);
2127
2171 printf("\n"); 2128 printf("\n");
2172 printf("%s\n", _("Notes:")); 2129 printf("%s\n", _("Notes:"));
2173 printf(" %s\n", _("If none of R,P,J,M,S or O is specified, default behavior is -R -P")); 2130 printf(" %s\n", _("If none of R,P,J,M,S or O is specified, default behavior is -R -P"));
2174 printf(" %s\n", _("The -H switch is optional. Naming a host (or several) to check is not.")); 2131 printf(" %s\n", _("Naming a host (or several) to check is not."));
2175 printf("\n"); 2132 printf("\n");
2176 printf(" %s\n", _("Threshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%")); 2133 printf(" %s\n", _("Threshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%"));
2177 printf(" %s\n", _("packet loss. The default values should work well for most users.")); 2134 printf(" %s\n", _("packet loss. The default values should work well for most users."));
2178 printf(" %s\n", _("You can specify different RTA factors using the standardized abbreviations")); 2135 printf(" %s\n",
2179 printf(" %s\n", _("us (microseconds), ms (milliseconds, default) or just plain s for seconds.")); 2136 _("You can specify different RTA factors using the standardized abbreviations"));
2180 /* -d not yet implemented */ 2137 printf(" %s\n",
2181 /* printf ("%s\n", _("Threshold format for -d is warn,crit. 12,14 means WARNING if >= 12 hops")); 2138 _("us (microseconds), ms (milliseconds, default) or just plain s for seconds."));
2182 printf ("%s\n", _("are spent and CRITICAL if >= 14 hops are spent."));
2183 printf ("%s\n\n", _("NOTE: Some systems decrease TTL when forming ICMP_ECHOREPLY, others do not."));*/
2184 printf("\n");
2185 printf(" %s\n", _("The -v switch can be specified several times for increased verbosity."));
2186 /* printf ("%s\n", _("Long options are currently unsupported."));
2187 printf ("%s\n", _("Options marked with * require an argument"));
2188 */
2189 2139
2190 printf(UT_SUPPORT); 2140 printf(UT_SUPPORT);
2191} 2141}
2192 2142
2193void print_usage(void) { 2143void print_usage(void) {
2194 printf("%s\n", _("Usage:")); 2144 printf("%s\n", _("Usage:"));
2195 printf(" %s [options] [-H] host1 host2 hostN\n", progname); 2145 printf(" %s [options] [-H host1 [-H host2 [-H hostN]]]\n", progname);
2146}
2147
2148static add_host_wrapper add_host(char *arg, check_icmp_execution_mode mode,
2149 sa_family_t enforced_proto) {
2150 if (debug) {
2151 printf("add_host called with argument %s\n", arg);
2152 }
2153
2154 add_host_wrapper result = {
2155 .error_code = OK,
2156 .host = check_icmp_target_container_init(),
2157 .has_v4 = false,
2158 .has_v6 = false,
2159 };
2160
2161 add_target_wrapper targets = add_target(arg, mode, enforced_proto);
2162
2163 if (targets.error_code != OK) {
2164 result.error_code = targets.error_code;
2165 return result;
2166 }
2167
2168 result.has_v4 = targets.has_v4;
2169 result.has_v6 = targets.has_v6;
2170
2171 result.host = check_icmp_target_container_init();
2172
2173 result.host.name = strdup(arg);
2174 result.host.target_list = targets.targets;
2175 result.host.number_of_targets = targets.number_of_targets;
2176
2177 return result;
2178}
2179
2180mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes,
2181 check_icmp_threshold warn, check_icmp_threshold crit) {
2182 /* if no new mode selected, use old schema */
2183 if (!modes.rta_mode && !modes.pl_mode && !modes.jitter_mode && !modes.score_mode &&
2184 !modes.mos_mode && !modes.order_mode) {
2185 modes.rta_mode = true;
2186 modes.pl_mode = true;
2187 }
2188
2189 mp_subcheck result = mp_subcheck_init();
2190 result = mp_set_subcheck_default_state(result, STATE_OK);
2191
2192 char address[INET6_ADDRSTRLEN];
2193 memset(address, 0, INET6_ADDRSTRLEN);
2194 parse_address(&target.address, address, sizeof(address));
2195
2196 xasprintf(&result.output, "%s", address);
2197
2198 double packet_loss;
2199 time_t rta;
2200 if (!target.icmp_recv) {
2201 /* rta 0 is of course not entirely correct, but will still show up
2202 * conspicuously as missing entries in perfparse and cacti */
2203 packet_loss = 100;
2204 rta = 0;
2205 result = mp_set_subcheck_state(result, STATE_CRITICAL);
2206 /* up the down counter if not already counted */
2207
2208 if (target.flags & FLAG_LOST_CAUSE) {
2209 xasprintf(&result.output, "%s: %s @ %s", result.output,
2210 get_icmp_error_msg(target.icmp_type, target.icmp_code), address);
2211 } else { /* not marked as lost cause, so we have no flags for it */
2212 xasprintf(&result.output, "%s", result.output);
2213 }
2214 } else {
2215 packet_loss =
2216 (unsigned char)((target.icmp_sent - target.icmp_recv) * 100) / target.icmp_sent;
2217 rta = target.time_waited / target.icmp_recv;
2218 }
2219
2220 double EffectiveLatency;
2221 double mos; /* Mean opinion score */
2222 double score; /* score */
2223
2224 if (target.icmp_recv > 1) {
2225 /*
2226 * This algorithm is probably pretty much blindly copied from
2227 * locations like this one:
2228 * https://www.slac.stanford.edu/comp/net/wan-mon/tutorial.html#mos It calculates a MOS
2229 * value (range of 1 to 5, where 1 is bad and 5 really good). According to some quick
2230 * research MOS originates from the Audio/Video transport network area. Whether it can
2231 * and should be computed from ICMP data, I can not say.
2232 *
2233 * Anyway the basic idea is to map a value "R" with a range of 0-100 to the MOS value
2234 *
2235 * MOS stands likely for Mean Opinion Score (
2236 * https://en.wikipedia.org/wiki/Mean_Opinion_Score )
2237 *
2238 * More links:
2239 * - https://confluence.slac.stanford.edu/display/IEPM/MOS
2240 */
2241 target.jitter = (target.jitter / (target.icmp_recv - 1) / 1000);
2242
2243 /*
2244 * Take the average round trip latency (in milliseconds), add
2245 * round trip jitter, but double the impact to latency
2246 * then add 10 for protocol latencies (in milliseconds).
2247 */
2248 EffectiveLatency = ((double)rta / 1000) + target.jitter * 2 + 10;
2249
2250 double R;
2251 if (EffectiveLatency < 160) {
2252 R = 93.2 - (EffectiveLatency / 40);
2253 } else {
2254 R = 93.2 - ((EffectiveLatency - 120) / 10);
2255 }
2256
2257 // Now, let us deduct 2.5 R values per percentage of packet loss (i.e. a
2258 // loss of 5% will be entered as 5).
2259 R = R - (packet_loss * 2.5);
2260
2261 if (R < 0) {
2262 R = 0;
2263 }
2264
2265 score = R;
2266 mos = 1 + ((0.035) * R) + ((.000007) * R * (R - 60) * (100 - R));
2267 } else {
2268 target.jitter = 0;
2269 target.jitter_min = 0;
2270 target.jitter_max = 0;
2271 mos = 0;
2272 }
2273
2274 /* Check which mode is on and do the warn / Crit stuff */
2275 if (modes.rta_mode) {
2276 mp_subcheck sc_rta = mp_subcheck_init();
2277 sc_rta = mp_set_subcheck_default_state(sc_rta, STATE_OK);
2278 xasprintf(&sc_rta.output, "rta %0.3fms", (double)rta / 1000);
2279
2280 if (rta >= crit.rta) {
2281 sc_rta = mp_set_subcheck_state(sc_rta, STATE_CRITICAL);
2282 xasprintf(&sc_rta.output, "%s >= %0.3fms", sc_rta.output, (double)crit.rta / 1000);
2283 } else if (rta >= warn.rta) {
2284 sc_rta = mp_set_subcheck_state(sc_rta, STATE_WARNING);
2285 xasprintf(&sc_rta.output, "%s >= %0.3fms", sc_rta.output, (double)warn.rta / 1000);
2286 }
2287
2288 if (packet_loss < 100) {
2289 mp_perfdata pd_rta = perfdata_init();
2290 xasprintf(&pd_rta.label, "%srta", address);
2291 pd_rta.uom = strdup("ms");
2292 pd_rta.value = mp_create_pd_value(rta / 1000);
2293 pd_rta.min = mp_create_pd_value(0);
2294
2295 pd_rta.warn = mp_range_set_end(pd_rta.warn, mp_create_pd_value(warn.rta));
2296 pd_rta.crit = mp_range_set_end(pd_rta.crit, mp_create_pd_value(crit.rta));
2297 mp_add_perfdata_to_subcheck(&sc_rta, pd_rta);
2298
2299 mp_perfdata pd_rt_min = perfdata_init();
2300 xasprintf(&pd_rt_min.label, "%srtmin", address);
2301 pd_rt_min.value = mp_create_pd_value(target.rtmin / 1000);
2302 pd_rt_min.uom = strdup("ms");
2303 mp_add_perfdata_to_subcheck(&sc_rta, pd_rt_min);
2304
2305 mp_perfdata pd_rt_max = perfdata_init();
2306 xasprintf(&pd_rt_max.label, "%srtmax", address);
2307 pd_rt_max.value = mp_create_pd_value(target.rtmax / 1000);
2308 pd_rt_max.uom = strdup("ms");
2309 mp_add_perfdata_to_subcheck(&sc_rta, pd_rt_max);
2310 }
2311
2312 mp_add_subcheck_to_subcheck(&result, sc_rta);
2313 }
2314
2315 if (modes.pl_mode) {
2316 mp_subcheck sc_pl = mp_subcheck_init();
2317 sc_pl = mp_set_subcheck_default_state(sc_pl, STATE_OK);
2318 xasprintf(&sc_pl.output, "packet loss %.1f%%", packet_loss);
2319
2320 if (packet_loss >= crit.pl) {
2321 sc_pl = mp_set_subcheck_state(sc_pl, STATE_CRITICAL);
2322 xasprintf(&sc_pl.output, "%s >= %u%%", sc_pl.output, crit.pl);
2323 } else if (packet_loss >= warn.pl) {
2324 sc_pl = mp_set_subcheck_state(sc_pl, STATE_WARNING);
2325 xasprintf(&sc_pl.output, "%s >= %u%%", sc_pl.output, warn.pl);
2326 }
2327
2328 mp_perfdata pd_pl = perfdata_init();
2329 xasprintf(&pd_pl.label, "%spl", address);
2330 pd_pl.uom = strdup("%");
2331
2332 pd_pl.warn = mp_range_set_end(pd_pl.warn, mp_create_pd_value(warn.pl));
2333 pd_pl.crit = mp_range_set_end(pd_pl.crit, mp_create_pd_value(crit.pl));
2334 pd_pl.value = mp_create_pd_value(packet_loss);
2335
2336 mp_add_perfdata_to_subcheck(&sc_pl, pd_pl);
2337
2338 mp_add_subcheck_to_subcheck(&result, sc_pl);
2339 }
2340
2341 if (modes.jitter_mode) {
2342 mp_subcheck sc_jitter = mp_subcheck_init();
2343 sc_jitter = mp_set_subcheck_default_state(sc_jitter, STATE_OK);
2344 xasprintf(&sc_jitter.output, "jitter %0.3fms", target.jitter);
2345
2346 if (target.jitter >= crit.jitter) {
2347 sc_jitter = mp_set_subcheck_state(sc_jitter, STATE_CRITICAL);
2348 xasprintf(&sc_jitter.output, "%s >= %0.3fms", sc_jitter.output, crit.jitter);
2349 } else if (target.jitter >= warn.jitter) {
2350 sc_jitter = mp_set_subcheck_state(sc_jitter, STATE_WARNING);
2351 xasprintf(&sc_jitter.output, "%s >= %0.3fms", sc_jitter.output, warn.jitter);
2352 }
2353
2354 if (packet_loss < 100) {
2355 mp_perfdata pd_jitter = perfdata_init();
2356 pd_jitter.uom = strdup("ms");
2357 xasprintf(&pd_jitter.label, "%sjitter_avg", address);
2358 pd_jitter.value = mp_create_pd_value(target.jitter);
2359 pd_jitter.warn = mp_range_set_end(pd_jitter.warn, mp_create_pd_value(warn.jitter));
2360 pd_jitter.crit = mp_range_set_end(pd_jitter.crit, mp_create_pd_value(crit.jitter));
2361 mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter);
2362
2363 mp_perfdata pd_jitter_min = perfdata_init();
2364 pd_jitter_min.uom = strdup("ms");
2365 xasprintf(&pd_jitter_min.label, "%sjitter_min", address);
2366 pd_jitter_min.value = mp_create_pd_value(target.jitter_min);
2367 mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter_min);
2368
2369 mp_perfdata pd_jitter_max = perfdata_init();
2370 pd_jitter_max.uom = strdup("ms");
2371 xasprintf(&pd_jitter_max.label, "%sjitter_max", address);
2372 pd_jitter_max.value = mp_create_pd_value(target.jitter_max);
2373 mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter_max);
2374 }
2375 mp_add_subcheck_to_subcheck(&result, sc_jitter);
2376 }
2377
2378 if (modes.mos_mode) {
2379 mp_subcheck sc_mos = mp_subcheck_init();
2380 sc_mos = mp_set_subcheck_default_state(sc_mos, STATE_OK);
2381 xasprintf(&sc_mos.output, "MOS %0.1f", mos);
2382
2383 if (mos <= crit.mos) {
2384 sc_mos = mp_set_subcheck_state(sc_mos, STATE_CRITICAL);
2385 xasprintf(&sc_mos.output, "%s <= %0.1f", sc_mos.output, crit.mos);
2386 } else if (mos <= warn.mos) {
2387 sc_mos = mp_set_subcheck_state(sc_mos, STATE_WARNING);
2388 xasprintf(&sc_mos.output, "%s <= %0.1f", sc_mos.output, warn.mos);
2389 }
2390
2391 if (packet_loss < 100) {
2392 mp_perfdata pd_mos = perfdata_init();
2393 xasprintf(&pd_mos.label, "%smos", address);
2394 pd_mos.value = mp_create_pd_value(mos);
2395 pd_mos.warn = mp_range_set_end(pd_mos.warn, mp_create_pd_value(warn.mos));
2396 pd_mos.crit = mp_range_set_end(pd_mos.crit, mp_create_pd_value(crit.mos));
2397 pd_mos.min = mp_create_pd_value(0); // MOS starts at 0
2398 pd_mos.max = mp_create_pd_value(5); // MOS max is 5, by definition
2399 mp_add_perfdata_to_subcheck(&sc_mos, pd_mos);
2400 }
2401 mp_add_subcheck_to_subcheck(&result, sc_mos);
2402 }
2403
2404 if (modes.score_mode) {
2405 mp_subcheck sc_score = mp_subcheck_init();
2406 sc_score = mp_set_subcheck_default_state(sc_score, STATE_OK);
2407 xasprintf(&sc_score.output, "Score %f", score);
2408
2409 if (score <= crit.score) {
2410 sc_score = mp_set_subcheck_state(sc_score, STATE_CRITICAL);
2411 xasprintf(&sc_score.output, "%s <= %f", sc_score.output, crit.score);
2412 } else if (score <= warn.score) {
2413 sc_score = mp_set_subcheck_state(sc_score, STATE_WARNING);
2414 xasprintf(&sc_score.output, "%s <= %f", sc_score.output, warn.score);
2415 }
2416
2417 if (packet_loss < 100) {
2418 mp_perfdata pd_score = perfdata_init();
2419 xasprintf(&pd_score.label, "%sscore", address);
2420 pd_score.value = mp_create_pd_value(score);
2421 pd_score.warn = mp_range_set_end(pd_score.warn, mp_create_pd_value(warn.score));
2422 pd_score.crit = mp_range_set_end(pd_score.crit, mp_create_pd_value(crit.score));
2423 pd_score.min = mp_create_pd_value(0);
2424 pd_score.max = mp_create_pd_value(100);
2425 mp_add_perfdata_to_subcheck(&sc_score, pd_score);
2426 }
2427
2428 mp_add_subcheck_to_subcheck(&result, sc_score);
2429 }
2430
2431 if (modes.order_mode) {
2432 mp_subcheck sc_order = mp_subcheck_init();
2433 sc_order = mp_set_subcheck_default_state(sc_order, STATE_OK);
2434
2435 if (target.found_out_of_order_packets) {
2436 mp_set_subcheck_state(sc_order, STATE_CRITICAL);
2437 xasprintf(&sc_order.output, "Packets out of order");
2438 } else {
2439 xasprintf(&sc_order.output, "Packets in order");
2440 }
2441
2442 mp_add_subcheck_to_subcheck(&result, sc_order);
2443 }
2444
2445 return result;
2446}
2447
2448evaluate_host_wrapper evaluate_host(check_icmp_target_container host,
2449 check_icmp_mode_switches modes, check_icmp_threshold warn,
2450 check_icmp_threshold crit) {
2451 evaluate_host_wrapper result = {
2452 .targets_warn = 0,
2453 .targets_ok = 0,
2454 .sc_host = mp_subcheck_init(),
2455 };
2456 result.sc_host = mp_set_subcheck_default_state(result.sc_host, STATE_OK);
2457
2458 result.sc_host.output = strdup(host.name);
2459
2460 ping_target *target = host.target_list;
2461 for (unsigned int i = 0; i < host.number_of_targets; i++) {
2462 mp_subcheck sc_target = evaluate_target(*target, modes, warn, crit);
2463
2464 mp_state_enum target_state = mp_compute_subcheck_state(sc_target);
2465
2466 if (target_state == STATE_WARNING) {
2467 result.targets_warn++;
2468 } else if (target_state == STATE_OK) {
2469 result.targets_ok++;
2470 }
2471 mp_add_subcheck_to_subcheck(&result.sc_host, sc_target);
2472
2473 target = target->next;
2474 }
2475
2476 return result;
2196} 2477}
diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.c b/plugins-root/check_icmp.d/check_icmp_helpers.c
new file mode 100644
index 00000000..1b96a392
--- /dev/null
+++ b/plugins-root/check_icmp.d/check_icmp_helpers.c
@@ -0,0 +1,134 @@
1#include "./config.h"
2#include <math.h>
3#include <netinet/in.h>
4#include <sys/socket.h>
5#include "./check_icmp_helpers.h"
6#include "../../plugins/netutils.h"
7
8// timeout as a global variable to make it available to the timeout handler
9unsigned int timeout = DEFAULT_TIMEOUT;
10
11check_icmp_config check_icmp_config_init() {
12 check_icmp_config tmp = {
13 .modes =
14 {
15 .order_mode = false,
16 .mos_mode = false,
17 .rta_mode = false,
18 .pl_mode = false,
19 .jitter_mode = false,
20 .score_mode = false,
21 },
22
23 .min_hosts_alive = -1,
24 .crit = {.pl = DEFAULT_CRIT_PL,
25 .rta = DEFAULT_CRIT_RTA,
26 .jitter = 50.0,
27 .mos = 3.0,
28 .score = 70.0},
29 .warn = {.pl = DEFAULT_WARN_PL,
30 .rta = DEFAULT_WARN_RTA,
31 .jitter = 40.0,
32 .mos = 3.5,
33 .score = 80.0},
34
35 .ttl = DEFAULT_TTL,
36 .icmp_data_size = DEFAULT_PING_DATA_SIZE,
37 .target_interval = 0,
38 .number_of_packets = DEFAULT_NUMBER_OF_PACKETS,
39
40 .source_ip = NULL,
41 .need_v4 = false,
42 .need_v6 = false,
43
44 .sender_id = 0,
45
46 .mode = MODE_RTA,
47
48 .number_of_targets = 0,
49 .targets = NULL,
50
51 .number_of_hosts = 0,
52 .hosts = NULL,
53
54 .output_format_is_set = false,
55 };
56 return tmp;
57}
58
59ping_target ping_target_init() {
60 ping_target tmp = {
61 .rtmin = INFINITY,
62
63 .jitter_min = INFINITY,
64
65 .found_out_of_order_packets = false,
66 };
67
68 return tmp;
69}
70
71check_icmp_state check_icmp_state_init() {
72 check_icmp_state tmp = {.icmp_sent = 0, .icmp_lost = 0, .icmp_recv = 0, .targets_down = 0};
73
74 return tmp;
75}
76
77ping_target_create_wrapper ping_target_create(struct sockaddr_storage address) {
78 ping_target_create_wrapper result = {
79 .errorcode = 0,
80 };
81
82 struct sockaddr_storage *tmp_addr = &address;
83
84 /* disregard obviously stupid addresses
85 * (I didn't find an ipv6 equivalent to INADDR_NONE) */
86 if (((tmp_addr->ss_family == AF_INET &&
87 (((struct sockaddr_in *)tmp_addr)->sin_addr.s_addr == INADDR_NONE ||
88 ((struct sockaddr_in *)tmp_addr)->sin_addr.s_addr == INADDR_ANY))) ||
89 (tmp_addr->ss_family == AF_INET6 &&
90 (((struct sockaddr_in6 *)tmp_addr)->sin6_addr.s6_addr == in6addr_any.s6_addr))) {
91 result.errorcode = 1;
92 return result;
93 }
94
95 /* add the fresh ip */
96 ping_target target = ping_target_init();
97
98 /* fill out the sockaddr_storage struct */
99 target.address = address;
100
101 result.host = target;
102
103 return result;
104}
105
106check_icmp_target_container check_icmp_target_container_init() {
107 check_icmp_target_container tmp = {
108 .name = NULL,
109 .number_of_targets = 0,
110 .target_list = NULL,
111 };
112 return tmp;
113}
114
115unsigned int ping_target_list_append(ping_target *list, ping_target *elem) {
116 if (elem == NULL || list == NULL) {
117 return 0;
118 }
119
120 while (list->next != NULL) {
121 list = list->next;
122 }
123
124 list->next = elem;
125
126 unsigned int result = 1;
127
128 while (elem->next != NULL) {
129 result++;
130 elem = elem->next;
131 }
132
133 return result;
134}
diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.h b/plugins-root/check_icmp.d/check_icmp_helpers.h
new file mode 100644
index 00000000..dc6ea40b
--- /dev/null
+++ b/plugins-root/check_icmp.d/check_icmp_helpers.h
@@ -0,0 +1,68 @@
1#pragma once
2
3#include "../../lib/states.h"
4#include <netinet/in_systm.h>
5#include <netinet/in.h>
6#include <netinet/ip.h>
7#include <netinet/ip6.h>
8#include <netinet/ip_icmp.h>
9#include <netinet/icmp6.h>
10#include <arpa/inet.h>
11
12typedef struct ping_target {
13 unsigned short id; /* id in **table, and icmp pkts */
14 char *msg; /* icmp error message, if any */
15
16 struct sockaddr_storage address; /* the address of this host */
17 struct sockaddr_storage error_addr; /* stores address of error replies */
18 time_t time_waited; /* total time waited, in usecs */
19 unsigned int icmp_sent, icmp_recv, icmp_lost; /* counters */
20 unsigned char icmp_type, icmp_code; /* type and code from errors */
21 unsigned short flags; /* control/status flags */
22
23 double rtmax; /* max rtt */
24 double rtmin; /* min rtt */
25
26 double jitter; /* measured jitter */
27 double jitter_max; /* jitter rtt maximum */
28 double jitter_min; /* jitter rtt minimum */
29
30 time_t last_tdiff;
31 unsigned int last_icmp_seq; /* Last ICMP_SEQ to check out of order pkts */
32
33 bool found_out_of_order_packets;
34
35 struct ping_target *next;
36} ping_target;
37
38ping_target ping_target_init();
39
40typedef struct {
41 char *name;
42 ping_target *target_list;
43 unsigned int number_of_targets;
44} check_icmp_target_container;
45
46check_icmp_target_container check_icmp_target_container_init();
47
48typedef struct {
49 unsigned int icmp_sent;
50 unsigned int icmp_recv;
51 unsigned int icmp_lost;
52 unsigned short targets_down;
53} check_icmp_state;
54
55check_icmp_state check_icmp_state_init();
56
57typedef struct {
58 int errorcode;
59 ping_target host;
60} ping_target_create_wrapper;
61
62typedef struct {
63 int socket4;
64 int socket6;
65} check_icmp_socket_set;
66
67ping_target_create_wrapper ping_target_create(struct sockaddr_storage address);
68unsigned int ping_target_list_append(ping_target *list, ping_target *elem);
diff --git a/plugins-root/check_icmp.d/config.h b/plugins-root/check_icmp.d/config.h
new file mode 100644
index 00000000..be388d0a
--- /dev/null
+++ b/plugins-root/check_icmp.d/config.h
@@ -0,0 +1,115 @@
1#pragma once
2
3#include "../../config.h"
4#include "../../lib/states.h"
5#include <stddef.h>
6#include <netinet/in_systm.h>
7#include <netinet/in.h>
8#include <netinet/ip.h>
9#include <netinet/ip6.h>
10#include <netinet/ip_icmp.h>
11#include <netinet/icmp6.h>
12#include <arpa/inet.h>
13#include <stdint.h>
14#include "./check_icmp_helpers.h"
15#include "output.h"
16
17/* threshold structure. all values are maximum allowed, exclusive */
18typedef struct {
19 unsigned char pl; /* max allowed packet loss in percent */
20 time_t rta; /* roundtrip time average, microseconds */
21 double jitter; /* jitter time average, microseconds */
22 double mos; /* MOS */
23 double score; /* Score */
24} check_icmp_threshold;
25
26/* the different modes of this program are as follows:
27 * MODE_RTA: send all packets no matter what (mimic check_icmp and check_ping)
28 * MODE_HOSTCHECK: Return immediately upon any sign of life
29 * In addition, sends packets to ALL addresses assigned
30 * to this host (as returned by gethostbyname() or
31 * gethostbyaddr() and expects one host only to be checked at
32 * a time. Therefore, any packet response what so ever will
33 * count as a sign of life, even when received outside
34 * crit.rta limit. Do not misspell any additional IP's.
35 * MODE_ALL: Requires packets from ALL requested IP to return OK (default).
36 * MODE_ICMP: Default Mode
37 */
38typedef enum {
39 MODE_RTA,
40 MODE_HOSTCHECK,
41 MODE_ALL,
42 MODE_ICMP,
43} check_icmp_execution_mode;
44
45typedef struct {
46 bool order_mode;
47 bool mos_mode;
48 bool rta_mode;
49 bool pl_mode;
50 bool jitter_mode;
51 bool score_mode;
52} check_icmp_mode_switches;
53
54typedef struct {
55 check_icmp_mode_switches modes;
56
57 int min_hosts_alive;
58 check_icmp_threshold crit;
59 check_icmp_threshold warn;
60
61 unsigned long ttl;
62 unsigned short icmp_data_size;
63 time_t target_interval;
64 unsigned short number_of_packets;
65
66 char *source_ip;
67 bool need_v4;
68 bool need_v6;
69
70 uint16_t sender_id; // PID of the main process, which is used as an ID in packets
71
72 check_icmp_execution_mode mode;
73
74 unsigned short number_of_targets;
75 ping_target *targets;
76
77 unsigned short number_of_hosts;
78 check_icmp_target_container *hosts;
79
80 mp_output_format output_format;
81 bool output_format_is_set;
82} check_icmp_config;
83
84check_icmp_config check_icmp_config_init();
85
86/* the data structure */
87typedef struct icmp_ping_data {
88 struct timeval stime; /* timestamp (saved in protocol struct as well) */
89 unsigned short ping_id;
90} icmp_ping_data;
91
92#define MAX_IP_PKT_SIZE 65536 /* (theoretical) max IP packet size */
93#define IP_HDR_SIZE 20
94#define MAX_PING_DATA (MAX_IP_PKT_SIZE - IP_HDR_SIZE - ICMP_MINLEN)
95#define MIN_PING_DATA_SIZE sizeof(struct icmp_ping_data)
96#define DEFAULT_PING_DATA_SIZE (MIN_PING_DATA_SIZE + 44)
97
98/* 80 msec packet interval by default */
99// DEPRECATED, remove when removing the option
100#define DEFAULT_PKT_INTERVAL 80000
101
102#define DEFAULT_TARGET_INTERVAL 0
103
104#define DEFAULT_WARN_RTA 200000
105#define DEFAULT_CRIT_RTA 500000
106#define DEFAULT_WARN_PL 40
107#define DEFAULT_CRIT_PL 80
108
109#define DEFAULT_TIMEOUT 10
110#define DEFAULT_TTL 64
111
112#define DEFAULT_NUMBER_OF_PACKETS 5
113
114#define PACKET_BACKOFF_FACTOR 1.5
115#define TARGET_BACKOFF_FACTOR 1.5
diff --git a/plugins-root/pst3.c b/plugins-root/pst3.c
index 1f69f3a6..1bfe3d35 100644
--- a/plugins-root/pst3.c
+++ b/plugins-root/pst3.c
@@ -1,45 +1,45 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* pst3 3 * pst3
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2008 Monitoring Plugins Development Team 6 * Copyright (c) 2008 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the pst3 executable. This is a replacement ps command 10 * This file contains the pst3 executable. This is a replacement ps command
11* for Solaris to get output which provides a long argument listing, which 11 * for Solaris to get output which provides a long argument listing, which
12* is not possible with the standard ps command (due to truncation). /usr/ucb/ps 12 * is not possible with the standard ps command (due to truncation). /usr/ucb/ps
13* also has issues where some fields run into each other. 13 * also has issues where some fields run into each other.
14* 14 *
15* This executable works by reading process address structures, so needs 15 * This executable works by reading process address structures, so needs
16* to be executed as root 16 * to be executed as root
17* 17 *
18* Originally written by R.W.Ingraham 18 * Originally written by R.W.Ingraham
19* Rewritten by Duncan Ferguson (Altinity Ltd, June 2008) 19 * Rewritten by Duncan Ferguson (Altinity Ltd, June 2008)
20* The rewrite was necessary as /dev/kmem is not available within 20 * The rewrite was necessary as /dev/kmem is not available within
21* non-global zones on Solaris 10 21 * non-global zones on Solaris 10
22* 22 *
23* Details for rewrite came from 23 * Details for rewrite came from
24* source of /usr/ucb/ps on Solaris: 24 * source of /usr/ucb/ps on Solaris:
25* http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/ucbcmd/ps/ps.c#argvoff 25 * http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/ucbcmd/ps/ps.c#argvoff
26* usenet group posting 26 * usenet group posting
27* http://groups.google.com/group/comp.unix.solaris/tree/browse_frm/month/2001-09/bfa40c08bac819a2?rnum=141&_done=%2Fgroup%2Fcomp.unix.solaris%2Fbrowse_frm%2Fmonth%2F2001-09%3F 27 * http://groups.google.com/group/comp.unix.solaris/tree/browse_frm/month/2001-09/bfa40c08bac819a2?rnum=141&_done=%2Fgroup%2Fcomp.unix.solaris%2Fbrowse_frm%2Fmonth%2F2001-09%3F
28* 28 *
29* This program is free software: you can redistribute it and/or modify 29 * This program is free software: you can redistribute it and/or modify
30* it under the terms of the GNU General Public License as published by 30 * it under the terms of the GNU General Public License as published by
31* the Free Software Foundation, either version 3 of the License, or 31 * the Free Software Foundation, either version 3 of the License, or
32* (at your option) any later version. 32 * (at your option) any later version.
33* 33 *
34* This program is distributed in the hope that it will be useful, 34 * This program is distributed in the hope that it will be useful,
35* but WITHOUT ANY WARRANTY; without even the implied warranty of 35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37* GNU General Public License for more details. 37 * GNU General Public License for more details.
38* 38 *
39* You should have received a copy of the GNU General Public License 39 * You should have received a copy of the GNU General Public License
40* along with this program. If not, see <http://www.gnu.org/licenses/>. 40 * along with this program. If not, see <http://www.gnu.org/licenses/>.
41* 41 *
42*****************************************************************************/ 42 *****************************************************************************/
43 43
44#include <stdio.h> 44#include <stdio.h>
45#include <stdlib.h> 45#include <stdlib.h>
@@ -55,14 +55,14 @@
55 * Constants 55 * Constants
56 */ 56 */
57 57
58#define PROC_DIR "/proc" 58#define PROC_DIR "/proc"
59#define ARGS 30 59#define ARGS 30
60 60
61/* 61/*
62 * Globals 62 * Globals
63 */ 63 */
64 64
65static char * szProg; 65static char *szProg;
66 66
67/* 67/*
68 * Prototypes 68 * Prototypes
@@ -71,192 +71,179 @@ void usage();
71 71
72/*----------------------------------------------------------------------------*/ 72/*----------------------------------------------------------------------------*/
73 73
74int main (int argc, char **argv) 74int main(int argc, char **argv) {
75{ 75 DIR *procdir;
76 DIR *procdir; 76 struct dirent *proc;
77 struct dirent *proc; 77 char ps_name[ARGS];
78 char ps_name[ARGS]; 78 char as_name[ARGS];
79 char as_name[ARGS]; 79 psinfo_t psinfo;
80 psinfo_t psinfo; 80
81 81 /* Set our program name global */
82 /* Set our program name global */ 82 if ((szProg = strrchr(argv[0], '/')) != NULL) {
83 if ((szProg = strrchr(argv[0], '/')) != NULL) 83 szProg++;
84 szProg++; 84 } else {
85 else 85 szProg = argv[0];
86 szProg = argv[0]; 86 }
87 87
88 /* if given any parameters, print out help */ 88 /* if given any parameters, print out help */
89 if(argc > 1) { 89 if (argc > 1) {
90 (void)usage(); 90 (void)usage();
91 exit(1); 91 exit(1);
92 } 92 }
93 93
94 /* Make sure that our euid is root */ 94 /* Make sure that our euid is root */
95 if (geteuid() != 0) 95 if (geteuid() != 0) {
96 { 96 fprintf(stderr, "%s: This program can only be run by the root user!\n", szProg);
97 fprintf(stderr, "%s: This program can only be run by the root user!\n", szProg); 97 exit(1);
98 exit(1); 98 }
99 } 99
100 100 if ((procdir = opendir(PROC_DIR)) == NULL) {
101 if ((procdir = opendir(PROC_DIR)) == NULL) { 101 fprintf(stderr, "%s: cannot open PROC directory %s\n", szProg, PROC_DIR);
102 fprintf(stderr, "%s: cannot open PROC directory %s\n", szProg, PROC_DIR); 102 exit(1);
103 exit(1); 103 }
104 } 104
105 105 /* Display column headings */
106 /* Display column headings */ 106 printf("%c %5s %5s %5s %6s %6s %4s %s %s\n", 'S', "UID", "PID", "PPID", "VSZ", "RSS", "%CPU",
107 printf("%c %5s %5s %5s %6s %6s %4s %s %s\n", 107 "COMMAND", "ARGS");
108 'S', 108
109 "UID", 109 /* Zip through all of the process entries */
110 "PID", 110 while ((proc = readdir(procdir))) {
111 "PPID", 111 int ps_fd;
112 "VSZ", 112 int as_fd;
113 "RSS", 113 off_t argoff;
114 "%CPU", 114 int i;
115 "COMMAND", 115 char *args;
116 "ARGS" 116 char *procname;
117 ); 117 char *ptr;
118 118 int argslen;
119 /* Zip through all of the process entries */ 119 uintptr_t args_addr;
120 while((proc = readdir(procdir))) { 120 ;
121 int ps_fd; 121 uintptr_t *args_vecs;
122 int as_fd; 122 ;
123 off_t argoff; 123 int args_count;
124 int i; 124
125 char *args; 125 if (proc->d_name[0] == '.') {
126 char *procname; 126 continue;
127 char *ptr; 127 }
128 int argslen; 128
129 uintptr_t args_addr;; 129 sprintf(ps_name, "%s/%s/%s", PROC_DIR, proc->d_name, "psinfo");
130 uintptr_t *args_vecs;; 130 sprintf(as_name, "%s/%s/%s", PROC_DIR, proc->d_name, "as");
131 int args_count; 131 try_again:
132 132 if ((ps_fd = open(ps_name, O_RDONLY)) == -1) {
133 if(proc->d_name[0] == '.') 133 continue;
134 continue; 134 }
135 135
136 sprintf(ps_name,"%s/%s/%s",PROC_DIR,proc->d_name,"psinfo"); 136 if ((as_fd = open(as_name, O_RDONLY)) == -1) {
137 sprintf(as_name,"%s/%s/%s",PROC_DIR,proc->d_name,"as"); 137 close(ps_fd);
138try_again: 138 continue;
139 if((ps_fd = open(ps_name, O_RDONLY)) == -1) 139 }
140 continue; 140
141 141 if (read(ps_fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) {
142 if((as_fd = open(as_name, O_RDONLY)) == -1) { 142 int err = errno;
143 close(ps_fd); 143 close(ps_fd);
144 continue; 144 close(as_fd);
145 } 145 if (err == EAGAIN) {
146 146 goto try_again;
147 if(read(ps_fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) { 147 }
148 int err = errno; 148 if (err != ENOENT) {
149 close(ps_fd); 149 fprintf(stderr, "%s: read() on %s: %s\n", szProg, ps_name, strerror(err));
150 close(as_fd); 150 }
151 if(err == EAGAIN) goto try_again; 151 continue;
152 if(err != ENOENT) 152 }
153 fprintf(stderr, "%s: read() on %s: %s\n", szProg, 153 close(ps_fd);
154 ps_name, strerror(err)); 154
155 continue; 155 /* system process, ignore since the previous version did */
156 } 156 if (psinfo.pr_nlwp == 0 || strcmp(psinfo.pr_lwp.pr_clname, "SYS") == 0) {
157 close(ps_fd); 157 continue;
158 158 }
159 /* system process, ignore since the previous version did */ 159
160 if( 160 /* get the procname to match previous versions */
161 psinfo.pr_nlwp == 0 || 161 procname = strdup(psinfo.pr_psargs);
162 strcmp(psinfo.pr_lwp.pr_clname, "SYS") == 0 162 if ((ptr = strchr(procname, ' ')) != NULL) {
163 ) { 163 *ptr = '\0';
164 continue; 164 }
165 } 165 if ((ptr = strrchr(procname, '/')) != NULL) {
166 166 ptr++;
167 /* get the procname to match previous versions */ 167 } else {
168 procname = strdup(psinfo.pr_psargs); 168 ptr = procname;
169 if((ptr = strchr(procname, ' ')) != NULL) 169 }
170 *ptr = '\0'; 170
171 if((ptr = strrchr(procname, '/')) != NULL) 171 /*
172 ptr++; 172 * print out what we currently know
173 else 173 */
174 ptr = procname; 174 printf("%c %5d %5d %5d %6lu %6lu %4.1f %s ", psinfo.pr_lwp.pr_sname, psinfo.pr_euid,
175 175 psinfo.pr_pid, psinfo.pr_ppid, psinfo.pr_size, psinfo.pr_rssize,
176 /* 176 ((float)(psinfo.pr_pctcpu) / 0x8000 * 100.0), ptr);
177 * print out what we currently know 177 free(procname);
178 */ 178
179 printf("%c %5d %5d %5d %6lu %6lu %4.1f %s ", 179 /*
180 psinfo.pr_lwp.pr_sname, 180 * and now for the command line stuff
181 psinfo.pr_euid, 181 */
182 psinfo.pr_pid, 182
183 psinfo.pr_ppid, 183 args_addr = psinfo.pr_argv;
184 psinfo.pr_size, 184 args_count = psinfo.pr_argc;
185 psinfo.pr_rssize, 185 args_vecs = malloc(args_count * sizeof(uintptr_t));
186 ((float)(psinfo.pr_pctcpu) / 0x8000 * 100.0), 186
187 ptr 187 if (psinfo.pr_dmodel == PR_MODEL_NATIVE) {
188 ); 188 /* this process matches target process */
189 free(procname); 189 pread(as_fd, args_vecs, args_count * sizeof(uintptr_t), args_addr);
190 190 } else {
191 /* 191 /* this process is 64bit, target process is 32 bit*/
192 * and now for the command line stuff 192 caddr32_t *args_vecs32 = (caddr32_t *)args_vecs;
193 */ 193 pread(as_fd, args_vecs32, args_count * sizeof(caddr32_t), args_addr);
194 194 for (i = args_count - 1; i >= 0; --i) {
195 args_addr = psinfo.pr_argv; 195 args_vecs[i] = args_vecs32[i];
196 args_count = psinfo.pr_argc; 196 }
197 args_vecs = malloc(args_count * sizeof(uintptr_t)); 197 }
198 198
199 if(psinfo.pr_dmodel == PR_MODEL_NATIVE) { 199 /*
200 /* this process matches target process */ 200 * now read in the args - if what we read in fills buffer
201 pread(as_fd,args_vecs, args_count * sizeof(uintptr_t), 201 * resize buffer and reread that bit again
202 args_addr); 202 */
203 } else { 203 argslen = ARGS;
204 /* this process is 64bit, target process is 32 bit*/ 204 args = malloc(argslen + 1);
205 caddr32_t *args_vecs32 = (caddr32_t *)args_vecs; 205 for (i = 0; i < args_count; i++) {
206 pread(as_fd,args_vecs32,args_count * sizeof(caddr32_t), 206 memset(args, '\0', argslen + 1);
207 args_addr); 207 if (pread(as_fd, args, argslen, args_vecs[i]) <= 0) {
208 for (i=args_count-1;i>=0;--i) 208 break;
209 args_vecs[i]=args_vecs32[i]; 209 }
210 } 210 args[argslen] = '\0';
211 211 if (strlen(args) == argslen) {
212 /* 212 argslen += ARGS;
213 * now read in the args - if what we read in fills buffer 213 args = realloc(args, argslen + 1);
214 * resize buffer and reread that bit again 214 i--;
215 */ 215 continue;
216 argslen=ARGS; 216 }
217 args=malloc(argslen+1); 217 printf(" %s", args);
218 for(i=0;i<args_count;i++) { 218 }
219 memset(args,'\0',argslen+1); 219 free(args_vecs);
220 if(pread(as_fd, args, argslen, args_vecs[i]) <= 0) { 220 free(args);
221 break; 221 close(as_fd);
222 } 222 printf("\n");
223 args[argslen]='\0'; 223 }
224 if(strlen(args) == argslen){ 224
225 argslen += ARGS; 225 (void)closedir(procdir);
226 args = realloc(args, argslen + 1); 226
227 i--; 227 return (0);
228 continue;
229 }
230 printf(" %s", args);
231 }
232 free(args_vecs);
233 free(args);
234 close(as_fd);
235 printf("\n");
236 }
237
238 (void) closedir(procdir);
239
240 return (0);
241} 228}
242 229
243/*----------------------------------------------------------------------------*/ 230/*----------------------------------------------------------------------------*/
244 231
245void usage() { 232void usage() {
246 printf("%s: Help output\n\n", szProg); 233 printf("%s: Help output\n\n", szProg);
247 printf("If this program is given any arguments, this help is displayed.\n"); 234 printf("If this program is given any arguments, this help is displayed.\n");
248 printf("This command is used to print out the full command line for all\n"); 235 printf("This command is used to print out the full command line for all\n");
249 printf("running processes because /usr/bin/ps is limited to 80 chars and\n"); 236 printf("running processes because /usr/bin/ps is limited to 80 chars and\n");
250 printf("/usr/ucb/ps can merge columns together.\n\n"); 237 printf("/usr/ucb/ps can merge columns together.\n\n");
251 printf("Columns are:\n"); 238 printf("Columns are:\n");
252 printf("\tS - State of process - see 'ps' man page\n"); 239 printf("\tS - State of process - see 'ps' man page\n");
253 printf("\tUID - UID of the process owner\n"); 240 printf("\tUID - UID of the process owner\n");
254 printf("\tPID - PID of the process\n"); 241 printf("\tPID - PID of the process\n");
255 printf("\tPPID - PID of the parent process\n"); 242 printf("\tPPID - PID of the parent process\n");
256 printf("\tVSZ - Virtual memory usage (kilobytes)\n"); 243 printf("\tVSZ - Virtual memory usage (kilobytes)\n");
257 printf("\tRSS - Real memory usage (kilobytes)\n"); 244 printf("\tRSS - Real memory usage (kilobytes)\n");
258 printf("\t%%CPU - CPU usage\n"); 245 printf("\t%%CPU - CPU usage\n");
259 printf("\tCOMMAND - Command being run\n"); 246 printf("\tCOMMAND - Command being run\n");
260 printf("\tARGS - Full command line with arguments\n"); 247 printf("\tARGS - Full command line with arguments\n");
261 return; 248 return;
262} 249}
diff --git a/plugins-root/t/check_dhcp.t b/plugins-root/t/check_dhcp.t
index ce627736..70392154 100644
--- a/plugins-root/t/check_dhcp.t
+++ b/plugins-root/t/check_dhcp.t
@@ -12,14 +12,14 @@ my $allow_sudo = getTestParameter( "NP_ALLOW_SUDO",
12 "no" ); 12 "no" );
13 13
14if ($allow_sudo eq "yes" or $> == 0) { 14if ($allow_sudo eq "yes" or $> == 0) {
15 plan tests => 6; 15 plan tests => 7;
16} else { 16} else {
17 plan skip_all => "Need sudo to test check_dhcp"; 17 plan skip_all => "Need sudo to test check_dhcp";
18} 18}
19my $sudo = $> == 0 ? '' : 'sudo'; 19my $sudo = $> == 0 ? '' : 'sudo';
20 20
21my $successOutput = '/OK: Received \d+ DHCPOFFER\(s\), \d+ of 1 requested servers responded, max lease time = \d+ sec\./'; 21my $successOutput = '/Received \d+ DHCPOFFER(s)*, max lease time = \d+ seconds/';
22my $failureOutput = '/CRITICAL: (No DHCPOFFERs were received|Received \d+ DHCPOFFER\(s\), 0 of 1 requested servers responded, max lease time = \d+ sec\.)/'; 22my $failureOutput = '/(No DHCPOFFERs were received|Received \d+ DHCPOFFER\(s\), 0 of 1 requested servers responded, max lease time = \d+ sec\.)/';
23my $invalidOutput = '/Invalid hostname/'; 23my $invalidOutput = '/Invalid hostname/';
24 24
25my $host_responsive = getTestParameter( "NP_HOST_DHCP_RESPONSIVE", 25my $host_responsive = getTestParameter( "NP_HOST_DHCP_RESPONSIVE",
@@ -34,6 +34,8 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
34 "An invalid (not known to DNS) hostname", 34 "An invalid (not known to DNS) hostname",
35 "nosuchhost" ); 35 "nosuchhost" );
36 36
37my $output_format = "--output-format mp-test-json";
38
37# try to determince interface 39# try to determince interface
38my $interface = ''; 40my $interface = '';
39 41
@@ -49,19 +51,21 @@ my $res;
49SKIP: { 51SKIP: {
50 skip('need responsive test host', 2) unless $host_responsive; 52 skip('need responsive test host', 2) unless $host_responsive;
51 $res = NPTest->testCmd( 53 $res = NPTest->testCmd(
52 "$sudo ./check_dhcp $interface -u -s $host_responsive" 54 "$sudo ./check_dhcp $interface -u -s $host_responsive $output_format"
53 ); 55 );
54 is( $res->return_code, 0, "Syntax ok" ); 56 is( $res->return_code, 0, "with JSON test format result should always be OK" );
55 like( $res->output, $successOutput, "Output OK" ); 57 like( $res->{'mp_test_result'}->{'state'}, "/OK/", "Output OK" );
58 like( $res->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $successOutput, "Output OK" );
56}; 59};
57 60
58SKIP: { 61SKIP: {
59 skip('need nonresponsive test host', 2) unless $host_nonresponsive; 62 skip('need nonresponsive test host', 2) unless $host_nonresponsive;
60 $res = NPTest->testCmd( 63 $res = NPTest->testCmd(
61 "$sudo ./check_dhcp $interface -u -s $host_nonresponsive" 64 "$sudo ./check_dhcp $interface -u -s $host_nonresponsive $output_format"
62 ); 65 );
63 is( $res->return_code, 2, "Exit code - host nonresponsive" ); 66 is( $res->return_code, 0, "with JSON test format result should always be OK" );
64 like( $res->output, $failureOutput, "Output OK" ); 67 like( $res->{'mp_test_result'}->{'state'}, "/CRITICAL/", "Exit code - host nonresponsive" );
68 like( $res->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $failureOutput, "Output OK" );
65}; 69};
66 70
67SKIP: { 71SKIP: {
@@ -69,6 +73,6 @@ SKIP: {
69 $res = NPTest->testCmd( 73 $res = NPTest->testCmd(
70 "$sudo ./check_dhcp $interface -u -s $hostname_invalid" 74 "$sudo ./check_dhcp $interface -u -s $hostname_invalid"
71 ); 75 );
72 is( $res->return_code, 3, "Exit code - host invalid" ); 76 is( $res->return_code, 3, "invalid hostname/address should return UNKNOWN" );
73 like( $res->output, $invalidOutput, "Output OK" ); 77 like( $res->output, $invalidOutput, "Output OK" );
74}; 78};
diff --git a/plugins-root/t/check_icmp.t b/plugins-root/t/check_icmp.t
index de1d88d2..d414c3c7 100644
--- a/plugins-root/t/check_icmp.t
+++ b/plugins-root/t/check_icmp.t
@@ -12,15 +12,12 @@ my $allow_sudo = getTestParameter( "NP_ALLOW_SUDO",
12 "no" ); 12 "no" );
13 13
14if ($allow_sudo eq "yes" or $> == 0) { 14if ($allow_sudo eq "yes" or $> == 0) {
15 plan tests => 40; 15 plan tests => 17;
16} else { 16} else {
17 plan skip_all => "Need sudo to test check_icmp"; 17 plan skip_all => "Need sudo to test check_icmp";
18} 18}
19my $sudo = $> == 0 ? '' : 'sudo'; 19my $sudo = $> == 0 ? '' : 'sudo';
20 20
21my $successOutput = '/OK - .*? rta (?:[\d\.]+ms)|(?:nan), lost \d+%/';
22my $failureOutput = '/(WARNING|CRITICAL) - .*? rta (?:[\d\.]+ms > [\d\.]+ms|nan)/';
23
24my $host_responsive = getTestParameter( "NP_HOST_RESPONSIVE", 21my $host_responsive = getTestParameter( "NP_HOST_RESPONSIVE",
25 "The hostname of system responsive to network requests", 22 "The hostname of system responsive to network requests",
26 "localhost" ); 23 "localhost" );
@@ -36,108 +33,85 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
36my $res; 33my $res;
37 34
38$res = NPTest->testCmd( 35$res = NPTest->testCmd(
39 "$sudo ./check_icmp -H $host_responsive -w 10000ms,100% -c 10000ms,100%" 36 "$sudo ./check_icmp -H $host_responsive -w 100ms,100% -c 100ms,100%"
40 ); 37 );
41is( $res->return_code, 0, "Syntax ok" ); 38is( $res->return_code, 0, "Syntax ok" );
42like( $res->output, $successOutput, "Output OK" );
43 39
44$res = NPTest->testCmd( 40$res = NPTest->testCmd(
45 "$sudo ./check_icmp -H $host_responsive -w 0ms,0% -c 10000ms,100%" 41 "$sudo ./check_icmp -H $host_responsive -w 0ms,0% -c 100ms,100%"
46 ); 42 );
47is( $res->return_code, 1, "Syntax ok, with forced warning" ); 43is( $res->return_code, 1, "Syntax ok, with forced warning" );
48like( $res->output, $failureOutput, "Output OK" );
49 44
50$res = NPTest->testCmd( 45$res = NPTest->testCmd(
51 "$sudo ./check_icmp -H $host_responsive -w 0,0% -c 0,0%" 46 "$sudo ./check_icmp -H $host_responsive -w 0,0% -c 0,0%"
52 ); 47 );
53is( $res->return_code, 2, "Syntax ok, with forced critical" ); 48is( $res->return_code, 2, "Syntax ok, with forced critical" );
54like( $res->output, $failureOutput, "Output OK" );
55 49
56$res = NPTest->testCmd( 50$res = NPTest->testCmd(
57 "$sudo ./check_icmp -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -t 2" 51 "$sudo ./check_icmp -H $host_nonresponsive -w 100ms,100% -c 100ms,100%"
58 ); 52 );
59is( $res->return_code, 2, "Timeout - host nonresponsive" ); 53is( $res->return_code, 2, "Timeout - host nonresponsive" );
60like( $res->output, '/pl=100%/', "Error contains 'pl=100%' string (for 100% packet loss)" );
61like( $res->output, '/rta=U/', "Error contains 'rta=U' string" );
62 54
63$res = NPTest->testCmd( 55$res = NPTest->testCmd(
64 "$sudo ./check_icmp -w 10000ms,100% -c 10000ms,100%" 56 "$sudo ./check_icmp -w 100ms,100% -c 100ms,100%"
65 ); 57 );
66is( $res->return_code, 3, "No hostname" ); 58is( $res->return_code, 3, "No hostname" );
67like( $res->output, '/No hosts to check/', "Output with appropriate error message");
68 59
69$res = NPTest->testCmd( 60$res = NPTest->testCmd(
70 "$sudo ./check_icmp -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -n 1 -m 0 -t 2" 61 "$sudo ./check_icmp -H $host_nonresponsive -w 100ms,100% -c 100ms,100% -n 1 -m 0"
71 ); 62 );
72is( $res->return_code, 0, "One host nonresponsive - zero required" ); 63is( $res->return_code, 0, "One host nonresponsive - zero required" );
73like( $res->output, $successOutput, "Output OK" );
74 64
75$res = NPTest->testCmd( 65$res = NPTest->testCmd(
76 "$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -n 1 -m 1 -t 2" 66 "$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 100ms,100% -c 100ms,100% -n 1 -m 1"
77 ); 67 );
78is( $res->return_code, 0, "One of two host nonresponsive - one required" ); 68is( $res->return_code, 0, "One of two host nonresponsive - one required" );
79like( $res->output, $successOutput, "Output OK" );
80 69
81$res = NPTest->testCmd( 70$res = NPTest->testCmd(
82 "$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -n 1 -m 2" 71 "$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 100ms,100% -c 100ms,100% -n 1 -m 2"
83 ); 72 );
84is( $res->return_code, 2, "One of two host nonresponsive - two required" ); 73is( $res->return_code, 2, "One of two host nonresponsive - two required" );
85like( $res->output, $failureOutput, "Output OK" );
86 74
87$res = NPTest->testCmd( 75$res = NPTest->testCmd(
88 "$sudo ./check_icmp -H $host_responsive -s 127.0.15.15 -w 10000ms,100% -c 10000ms,100% -n 1 -m 2" 76 "$sudo ./check_icmp -H $host_responsive -s 127.0.15.15 -w 100ms,100% -c 100ms,100% -n 1"
89 ); 77 );
90is( $res->return_code, 0, "IPv4 source_ip accepted" ); 78is( $res->return_code, 0, "IPv4 source_ip accepted" );
91like( $res->output, $successOutput, "Output OK" );
92 79
93$res = NPTest->testCmd( 80$res = NPTest->testCmd(
94 "$sudo ./check_icmp -H $host_responsive -b 65507" 81 "$sudo ./check_icmp -H $host_responsive -b 65507"
95 ); 82 );
96is( $res->return_code, 0, "Try max packet size" ); 83is( $res->return_code, 0, "Try max packet size" );
97like( $res->output, $successOutput, "Output OK - Didn't overflow" );
98 84
99$res = NPTest->testCmd( 85$res = NPTest->testCmd(
100 "$sudo ./check_icmp -H $host_responsive -R 100,100 -n 1 -t 2" 86 "$sudo ./check_icmp -H $host_responsive -R 100,100 -n 1"
101 ); 87 );
102is( $res->return_code, 0, "rta works" ); 88is( $res->return_code, 0, "rta works" );
103like( $res->output, $successOutput, "Output OK" );
104$res = NPTest->testCmd( 89$res = NPTest->testCmd(
105 "$sudo ./check_icmp -H $host_responsive -P 80,90 -n 1 -t 2" 90 "$sudo ./check_icmp -H $host_responsive -P 80,90 -n 1"
106 ); 91 );
107is( $res->return_code, 0, "pl works" ); 92is( $res->return_code, 0, "pl works" );
108like( $res->output, '/lost 0%/', "Output OK" );
109 93
110$res = NPTest->testCmd( 94$res = NPTest->testCmd(
111 "$sudo ./check_icmp -H $host_responsive -J 80,90 -t 2" 95 "$sudo ./check_icmp -H $host_responsive -J 80,90"
112 ); 96 );
113is( $res->return_code, 0, "jitter works" ); 97is( $res->return_code, 0, "jitter works" );
114like( $res->output, '/jitter \d/', "Output OK" );
115 98
116$res = NPTest->testCmd( 99$res = NPTest->testCmd(
117 "$sudo ./check_icmp -H $host_responsive -M 4,3 -t 2" 100 "$sudo ./check_icmp -H $host_responsive -M 4,3"
118 ); 101 );
119is( $res->return_code, 0, "mos works" ); 102is( $res->return_code, 0, "mos works" );
120like( $res->output, '/MOS \d/', "Output OK" );
121 103
122$res = NPTest->testCmd( 104$res = NPTest->testCmd(
123 "$sudo ./check_icmp -H $host_responsive -S 80,70 -t 2" 105 "$sudo ./check_icmp -H $host_responsive -S 80,70"
124 ); 106 );
125is( $res->return_code, 0, "score works" ); 107is( $res->return_code, 0, "score works" );
126like( $res->output, '/Score \d/', "Output OK" );
127 108
128$res = NPTest->testCmd( 109$res = NPTest->testCmd(
129 "$sudo ./check_icmp -H $host_responsive -O -t 2" 110 "$sudo ./check_icmp -H $host_responsive -O"
130 ); 111 );
131is( $res->return_code, 0, "order works" ); 112is( $res->return_code, 0, "order works" );
132like( $res->output, '/Packets in order/', "Output OK" );
133 113
134$res = NPTest->testCmd( 114$res = NPTest->testCmd(
135 "$sudo ./check_icmp -H $host_responsive -O -S 80,70 -M 4,3 -J 80,90 -P 80,90 -R 100,100 -t 2" 115 "$sudo ./check_icmp -H $host_responsive -O -S 80,70 -M 4,3 -J 80,90 -P 80,90 -R 100,100"
136 ); 116 );
137is( $res->return_code, 0, "order works" ); 117is( $res->return_code, 0, "order works" );
138like( $res->output, '/Packets in order/', "Output OK" );
139like( $res->output, '/Score \d/', "Output OK" );
140like( $res->output, '/MOS \d/', "Output OK" );
141like( $res->output, '/jitter \d/', "Output OK" );
142like( $res->output, '/lost 0%/', "Output OK" );
143like( $res->output, $successOutput, "Output OK" );
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 6c582a15..d098fa8a 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -13,8 +13,14 @@ AM_CFLAGS = -DNP_VERSION='"$(NP_VERSION)"'
13 13
14VPATH = $(top_srcdir) $(top_srcdir)/lib $(top_srcdir)/plugins $(top_srcdir)/plugins/t 14VPATH = $(top_srcdir) $(top_srcdir)/lib $(top_srcdir)/plugins $(top_srcdir)/plugins/t
15 15
16AM_CPPFLAGS = -I.. -I$(top_srcdir)/lib -I$(top_srcdir)/gl -I$(top_srcdir)/intl \ 16AM_CPPFLAGS = -I.. \
17 @LDAPINCLUDE@ @PGINCLUDE@ @SSLINCLUDE@ 17 -I$(top_srcdir)/lib \
18 -I$(top_srcdir)/gl \
19 -I$(top_srcdir)/intl \
20 -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \
21 @LDAPINCLUDE@ \
22 @PGINCLUDE@ \
23 @SSLINCLUDE@
18 24
19localedir = $(datadir)/locale 25localedir = $(datadir)/locale
20# gettext docs say to use AM_CPPFLAGS, but per module_CPPFLAGS override this 26# gettext docs say to use AM_CPPFLAGS, but per module_CPPFLAGS override this
@@ -27,48 +33,68 @@ MATHLIBS = @MATHLIBS@
27#AM_CFLAGS = -Wall 33#AM_CFLAGS = -Wall
28 34
29libexec_PROGRAMS = check_apt check_cluster check_disk check_dummy check_http check_load \ 35libexec_PROGRAMS = check_apt check_cluster check_disk check_dummy check_http check_load \
30 check_mrtg check_mrtgtraf check_ntp check_ntp_peer check_nwstat check_ping \ 36 check_mrtg check_mrtgtraf check_ntp_peer check_ping \
31 check_real check_smtp check_ssh check_tcp check_time check_ntp_time \ 37 check_real check_smtp check_ssh check_tcp check_time check_ntp_time \
32 check_ups check_users negate \ 38 check_ups check_users negate \
33 urlize @EXTRAS@ 39 urlize @EXTRAS@ \
40 check_snmp
34 41
35check_tcp_programs = check_ftp check_imap check_nntp check_pop \ 42check_tcp_programs = check_ftp check_imap check_nntp check_pop \
36 check_udp check_clamd @check_tcp_ssl@ 43 check_udp check_clamd @check_tcp_ssl@
37 44
38EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \ 45EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_hpjd \
39 check_swap check_fping check_ldap check_game check_dig \ 46 check_swap check_fping check_ldap check_game check_dig \
40 check_nagios check_by_ssh check_dns check_nt check_ide_smart \ 47 check_nagios check_by_ssh check_dns check_ide_smart \
41 check_procs check_mysql_query check_apt check_dbi check_curl \ 48 check_procs check_mysql_query check_apt check_dbi check_curl \
42 \ 49 \
43 tests/test_check_swap 50 tests/test_check_swap \
51 tests/test_check_snmp \
52 tests/test_check_disk
44 53
45SUBDIRS = picohttpparser 54SUBDIRS = picohttpparser
46 55
47np_test_scripts = tests/test_check_swap.t 56np_test_scripts = tests/test_check_swap.t \
57 tests/test_check_snmp.t \
58 tests/test_check_disk.t
48 59
49EXTRA_DIST = t \ 60EXTRA_DIST = t \
50 tests \ 61 tests \
51 $(np_test_scripts) \ 62 $(np_test_scripts) \
63 negate.d \
52 check_swap.d \ 64 check_swap.d \
53 check_ldap.d \ 65 check_ldap.d \
54 check_hpjd.d \ 66 check_hpjd.d \
55 check_game.d \ 67 check_game.d \
68 check_radius.d \
69 check_curl.d \
70 check_disk.d \
71 check_time.d \
72 check_users.d \
73 check_load.d \
56 check_nagios.d \ 74 check_nagios.d \
57 check_dbi.d \ 75 check_dbi.d \
76 check_tcp.d \
77 check_real.d \
58 check_ssh.d \ 78 check_ssh.d \
59 check_nt.d \
60 check_dns.d \ 79 check_dns.d \
61 check_mrtgtraf.d \ 80 check_mrtgtraf.d \
62 check_mysql_query.d \ 81 check_mysql_query.d \
63 check_mrtg.d \ 82 check_mrtg.d \
83 check_ntp_peer.d \
64 check_apt.d \ 84 check_apt.d \
65 check_pgsql.d \ 85 check_pgsql.d \
86 check_procs.d \
87 check_ping.d \
66 check_by_ssh.d \ 88 check_by_ssh.d \
67 check_smtp.d \ 89 check_smtp.d \
90 check_snmp.d \
68 check_mysql.d \ 91 check_mysql.d \
69 check_ntp_time.d \ 92 check_ntp_time.d \
70 check_dig.d \ 93 check_dig.d \
71 check_cluster.d \ 94 check_cluster.d \
95 check_curl.d \
96 check_cluster.d \
97 check_ups.d \
72 check_fping.d 98 check_fping.d
73 99
74PLUGINHDRS = common.h 100PLUGINHDRS = common.h
@@ -108,9 +134,11 @@ check_cluster_LDADD = $(BASEOBJS)
108check_curl_CFLAGS = $(AM_CFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser 134check_curl_CFLAGS = $(AM_CFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser
109check_curl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser 135check_curl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser
110check_curl_LDADD = $(NETLIBS) $(LIBCURLLIBS) $(SSLOBJS) $(URIPARSERLIBS) picohttpparser/libpicohttpparser.a 136check_curl_LDADD = $(NETLIBS) $(LIBCURLLIBS) $(SSLOBJS) $(URIPARSERLIBS) picohttpparser/libpicohttpparser.a
137check_curl_SOURCES = check_curl.c check_curl.d/check_curl_helpers.c
111check_dbi_LDADD = $(NETLIBS) $(DBILIBS) 138check_dbi_LDADD = $(NETLIBS) $(DBILIBS)
112check_dig_LDADD = $(NETLIBS) 139check_dig_LDADD = $(NETLIBS)
113check_disk_LDADD = $(BASEOBJS) 140check_disk_LDADD = $(BASEOBJS)
141check_disk_SOURCES = check_disk.c check_disk.d/utils_disk.c
114check_dns_LDADD = $(NETLIBS) 142check_dns_LDADD = $(NETLIBS)
115check_dummy_LDADD = $(BASEOBJS) 143check_dummy_LDADD = $(BASEOBJS)
116check_fping_LDADD = $(NETLIBS) 144check_fping_LDADD = $(NETLIBS)
@@ -128,16 +156,16 @@ check_mysql_query_CFLAGS = $(AM_CFLAGS) $(MYSQLCFLAGS)
128check_mysql_query_CPPFLAGS = $(AM_CPPFLAGS) $(MYSQLINCLUDE) 156check_mysql_query_CPPFLAGS = $(AM_CPPFLAGS) $(MYSQLINCLUDE)
129check_mysql_query_LDADD = $(NETLIBS) $(MYSQLLIBS) 157check_mysql_query_LDADD = $(NETLIBS) $(MYSQLLIBS)
130check_nagios_LDADD = $(BASEOBJS) 158check_nagios_LDADD = $(BASEOBJS)
131check_nt_LDADD = $(NETLIBS)
132check_ntp_LDADD = $(NETLIBS) $(MATHLIBS)
133check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS) 159check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS)
134check_nwstat_LDADD = $(NETLIBS)
135check_pgsql_LDADD = $(NETLIBS) $(PGLIBS) 160check_pgsql_LDADD = $(NETLIBS) $(PGLIBS)
136check_ping_LDADD = $(NETLIBS) 161check_ping_LDADD = $(NETLIBS)
137check_procs_LDADD = $(BASEOBJS) 162check_procs_LDADD = $(BASEOBJS)
138check_radius_LDADD = $(NETLIBS) $(RADIUSLIBS) 163check_radius_LDADD = $(NETLIBS) $(RADIUSLIBS)
139check_real_LDADD = $(NETLIBS) 164check_real_LDADD = $(NETLIBS)
165check_snmp_SOURCES = check_snmp.c check_snmp.d/check_snmp_helpers.c
140check_snmp_LDADD = $(BASEOBJS) 166check_snmp_LDADD = $(BASEOBJS)
167check_snmp_LDFLAGS = $(AM_LDFLAGS) `net-snmp-config --libs`
168check_snmp_CFLAGS = $(AM_CFLAGS) `net-snmp-config --cflags`
141check_smtp_LDADD = $(SSLOBJS) 169check_smtp_LDADD = $(SSLOBJS)
142check_ssh_LDADD = $(NETLIBS) 170check_ssh_LDADD = $(NETLIBS)
143check_swap_SOURCES = check_swap.c check_swap.d/swap.c 171check_swap_SOURCES = check_swap.c check_swap.d/swap.c
@@ -146,6 +174,7 @@ check_tcp_LDADD = $(SSLOBJS)
146check_time_LDADD = $(NETLIBS) 174check_time_LDADD = $(NETLIBS)
147check_ntp_time_LDADD = $(NETLIBS) $(MATHLIBS) 175check_ntp_time_LDADD = $(NETLIBS) $(MATHLIBS)
148check_ups_LDADD = $(NETLIBS) 176check_ups_LDADD = $(NETLIBS)
177check_users_SOURCES = check_users.c check_users.d/users.c
149check_users_LDADD = $(BASEOBJS) $(WTSAPI32LIBS) $(SYSTEMDLIBS) 178check_users_LDADD = $(BASEOBJS) $(WTSAPI32LIBS) $(SYSTEMDLIBS)
150check_by_ssh_LDADD = $(NETLIBS) 179check_by_ssh_LDADD = $(NETLIBS)
151check_ide_smart_LDADD = $(BASEOBJS) 180check_ide_smart_LDADD = $(BASEOBJS)
@@ -158,6 +187,10 @@ endif
158 187
159tests_test_check_swap_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap 188tests_test_check_swap_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap
160tests_test_check_swap_SOURCES = tests/test_check_swap.c check_swap.d/swap.c 189tests_test_check_swap_SOURCES = tests/test_check_swap.c check_swap.d/swap.c
190tests_test_check_snmp_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap
191tests_test_check_snmp_SOURCES = tests/test_check_snmp.c check_snmp.d/check_snmp_helpers.c
192tests_test_check_disk_LDADD = $(BASEOBJS) $(tap_ldflags) check_disk.d/utils_disk.c -ltap
193tests_test_check_disk_SOURCES = tests/test_check_disk.c
161 194
162############################################################################## 195##############################################################################
163# secondary dependencies 196# secondary dependencies
diff --git a/plugins/check_apt.c b/plugins/check_apt.c
index e840184b..9ed5b6cf 100644
--- a/plugins/check_apt.c
+++ b/plugins/check_apt.c
@@ -29,31 +29,33 @@
29 * 29 *
30 *****************************************************************************/ 30 *****************************************************************************/
31 31
32#include "states.h" 32#include "perfdata.h"
33const char *progname = "check_apt"; 33const char *progname = "check_apt";
34const char *copyright = "2006-2024"; 34const char *copyright = "2006-2024";
35const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
36 36
37#include "states.h"
38#include "output.h"
37#include "common.h" 39#include "common.h"
38#include "runcmd.h" 40#include "runcmd.h"
39#include "utils.h" 41#include "utils.h"
40#include "regex.h" 42#include "regex.h"
41#include "check_apt.d/config.h" 43#include "check_apt.d/config.h"
42 44
43/* Character for hidden input file option (for testing). */
44#define INPUT_FILE_OPT CHAR_MAX + 1
45/* the default opts can be overridden via the cmdline */ 45/* the default opts can be overridden via the cmdline */
46#define UPGRADE_DEFAULT_OPTS "-o 'Debug::NoLocking=true' -s -qq" 46const char *UPGRADE_DEFAULT_OPTS = "-o 'Debug::NoLocking=true' -s -qq";
47#define UPDATE_DEFAULT_OPTS "-q" 47const char *UPDATE_DEFAULT_OPTS = "-q";
48
48/* until i commit the configure.in patch which gets this, i'll define 49/* until i commit the configure.in patch which gets this, i'll define
49 * it here as well */ 50 * it here as well */
50#ifndef PATH_TO_APTGET 51#ifndef PATH_TO_APTGET
51# define PATH_TO_APTGET "/usr/bin/apt-get" 52# define PATH_TO_APTGET "/usr/bin/apt-get"
52#endif /* PATH_TO_APTGET */ 53#endif /* PATH_TO_APTGET */
54
53/* String found at the beginning of the apt output lines we're interested in */ 55/* String found at the beginning of the apt output lines we're interested in */
54#define PKGINST_PREFIX "Inst " 56const char *PKGINST_PREFIX = "Inst ";
55/* the RE that catches security updates */ 57/* the RE that catches security updates */
56#define SECURITY_RE "^[^\\(]*\\(.* (Debian-Security:|Ubuntu:[^/]*/[^-]*-security)" 58const char *SECURITY_RE = "^[^\\(]*\\(.* (Debian-Security:|Ubuntu:[^/]*/[^-]*-security)";
57 59
58/* some standard functions */ 60/* some standard functions */
59typedef struct { 61typedef struct {
@@ -66,20 +68,28 @@ void print_usage(void);
66 68
67/* construct the appropriate apt-get cmdline */ 69/* construct the appropriate apt-get cmdline */
68static char *construct_cmdline(upgrade_type /*u*/, const char * /*opts*/); 70static char *construct_cmdline(upgrade_type /*u*/, const char * /*opts*/);
71
69/* run an apt-get update */ 72/* run an apt-get update */
70static int run_update(char * /*update_opts*/); 73typedef struct {
74 mp_subcheck sc;
75 bool stderr_warning;
76 bool exec_warning;
77} run_update_result;
78static run_update_result run_update(char *update_opts);
71 79
72typedef struct { 80typedef struct {
73 int errorcode; 81 int errorcode;
74 int package_count; 82 size_t package_count;
75 int security_package_count; 83 size_t security_package_count;
76 char **packages_list; 84 char **packages_list;
77 char **secpackages_list; 85 char **secpackages_list;
86 bool exec_warning;
78} run_upgrade_result; 87} run_upgrade_result;
79 88
80/* run an apt-get upgrade */ 89/* run an apt-get upgrade */
81run_upgrade_result run_upgrade(upgrade_type upgrade, const char *do_include, const char *do_exclude, const char *do_critical, 90run_upgrade_result run_upgrade(upgrade_type upgrade, const char *do_include, const char *do_exclude,
82 const char *upgrade_opts, const char *input_filename); 91 const char *do_critical, const char *upgrade_opts,
92 const char *input_filename);
83 93
84/* add another clause to a regexp */ 94/* add another clause to a regexp */
85static char *add_to_regexp(char * /*expr*/, const char * /*next*/); 95static char *add_to_regexp(char * /*expr*/, const char * /*next*/);
@@ -107,6 +117,10 @@ int main(int argc, char **argv) {
107 117
108 const check_apt_config config = tmp_config.config; 118 const check_apt_config config = tmp_config.config;
109 119
120 if (config.output_format_is_set) {
121 mp_set_format(config.output_format);
122 }
123
110 /* Set signal handling and alarm timeout */ 124 /* Set signal handling and alarm timeout */
111 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) { 125 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
112 usage_va(_("Cannot catch SIGALRM")); 126 usage_va(_("Cannot catch SIGALRM"));
@@ -115,55 +129,91 @@ int main(int argc, char **argv) {
115 /* handle timeouts gracefully... */ 129 /* handle timeouts gracefully... */
116 alarm(timeout_interval); 130 alarm(timeout_interval);
117 131
118 mp_state_enum result = STATE_UNKNOWN; 132 mp_check overall = mp_check_init();
119 /* if they want to run apt-get update first... */ 133 /* if they want to run apt-get update first... */
120 if (config.do_update) { 134 if (config.do_update) {
121 result = run_update(config.update_opts); 135 run_update_result update_result = run_update(config.update_opts);
136
137 mp_add_subcheck_to_check(&overall, update_result.sc);
122 } 138 }
123 139
124 /* apt-get upgrade */ 140 /* apt-get upgrade */
125 run_upgrade_result upgrad_res = 141 run_upgrade_result upgrad_res =
126 run_upgrade(config.upgrade, config.do_include, config.do_exclude, config.do_critical, config.upgrade_opts, config.input_filename); 142 run_upgrade(config.upgrade, config.do_include, config.do_exclude, config.do_critical,
143 config.upgrade_opts, config.input_filename);
144
145 mp_subcheck sc_run_upgrade = mp_subcheck_init();
146 if (upgrad_res.errorcode == OK) {
147 sc_run_upgrade = mp_set_subcheck_state(sc_run_upgrade, STATE_OK);
148 }
149 xasprintf(&sc_run_upgrade.output, "Executed apt upgrade (dry run)");
127 150
128 result = max_state(result, upgrad_res.errorcode); 151 mp_add_subcheck_to_check(&overall, sc_run_upgrade);
129 int packages_available = upgrad_res.package_count; 152
130 int sec_count = upgrad_res.security_package_count; 153 size_t packages_available = upgrad_res.package_count;
154 size_t number_of_security_updates = upgrad_res.security_package_count;
131 char **packages_list = upgrad_res.packages_list; 155 char **packages_list = upgrad_res.packages_list;
132 char **secpackages_list = upgrad_res.secpackages_list; 156 char **secpackages_list = upgrad_res.secpackages_list;
133 157
134 if (sec_count > 0) { 158 mp_perfdata pd_security_updates = perfdata_init();
135 result = max_state(result, STATE_CRITICAL); 159 pd_security_updates.value = mp_create_pd_value(number_of_security_updates);
136 } else if (packages_available >= config.packages_warning && !config.only_critical) { 160 pd_security_updates.label = "critical_updates";
137 result = max_state(result, STATE_WARNING); 161
138 } else if (result > STATE_UNKNOWN) { 162 mp_subcheck sc_security_updates = mp_subcheck_init();
139 result = STATE_UNKNOWN; 163 xasprintf(&sc_security_updates.output, "Security updates available: %zu",
164 number_of_security_updates);
165 mp_add_perfdata_to_subcheck(&sc_security_updates, pd_security_updates);
166
167 if (number_of_security_updates > 0) {
168 sc_security_updates = mp_set_subcheck_state(sc_security_updates, STATE_CRITICAL);
169 } else {
170 sc_security_updates = mp_set_subcheck_state(sc_security_updates, STATE_OK);
140 } 171 }
141 172
142 printf(_("APT %s: %d packages available for %s (%d critical updates). %s%s%s%s|available_upgrades=%d;;;0 critical_updates=%d;;;0\n"), 173 mp_perfdata pd_other_updates = perfdata_init();
143 state_text(result), packages_available, (config.upgrade == DIST_UPGRADE) ? "dist-upgrade" : "upgrade", sec_count, 174 pd_other_updates.value = mp_create_pd_value(packages_available);
144 (stderr_warning) ? " warnings detected" : "", (stderr_warning && exec_warning) ? "," : "", 175 pd_other_updates.label = "available_upgrades";
145 (exec_warning) ? " errors detected" : "", (stderr_warning || exec_warning) ? "." : "", packages_available, sec_count); 176
177 mp_subcheck sc_other_updates = mp_subcheck_init();
178
179 xasprintf(&sc_other_updates.output, "Updates available: %zu", packages_available);
180 sc_other_updates = mp_set_subcheck_default_state(sc_other_updates, STATE_OK);
181 mp_add_perfdata_to_subcheck(&sc_other_updates, pd_other_updates);
182
183 if (packages_available >= config.packages_warning && !config.only_critical) {
184 sc_other_updates = mp_set_subcheck_state(sc_other_updates, STATE_WARNING);
185 }
146 186
147 if (config.list) { 187 if (config.list) {
148 qsort(secpackages_list, sec_count, sizeof(char *), cmpstringp); 188 qsort(secpackages_list, number_of_security_updates, sizeof(char *), cmpstringp);
149 qsort(packages_list, packages_available - sec_count, sizeof(char *), cmpstringp); 189 qsort(packages_list, packages_available - number_of_security_updates, sizeof(char *),
190 cmpstringp);
150 191
151 for (int i = 0; i < sec_count; i++) { 192 for (size_t i = 0; i < number_of_security_updates; i++) {
152 printf("%s (security)\n", secpackages_list[i]); 193 xasprintf(&sc_security_updates.output, "%s\n%s (security)", sc_security_updates.output,
194 secpackages_list[i]);
153 } 195 }
154 196
155 if (!config.only_critical) { 197 if (!config.only_critical) {
156 for (int i = 0; i < packages_available - sec_count; i++) { 198 for (size_t i = 0; i < packages_available - number_of_security_updates; i++) {
157 printf("%s\n", packages_list[i]); 199 xasprintf(&sc_other_updates.output, "%s\n%s", sc_other_updates.output,
200 packages_list[i]);
158 } 201 }
159 } 202 }
160 } 203 }
204 mp_add_subcheck_to_check(&overall, sc_security_updates);
205 mp_add_subcheck_to_check(&overall, sc_other_updates);
161 206
162 return result; 207 mp_exit(overall);
163} 208}
164 209
165/* process command-line arguments */ 210/* process command-line arguments */
166check_apt_config_wrapper process_arguments(int argc, char **argv) { 211check_apt_config_wrapper process_arguments(int argc, char **argv) {
212 enum {
213 /* Character for hidden input file option (for testing). */
214 INPUT_FILE_OPT = CHAR_MAX + 1,
215 output_format_index,
216 };
167 static struct option longopts[] = {{"version", no_argument, 0, 'V'}, 217 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
168 {"help", no_argument, 0, 'h'}, 218 {"help", no_argument, 0, 'h'},
169 {"verbose", no_argument, 0, 'v'}, 219 {"verbose", no_argument, 0, 'v'},
@@ -179,6 +229,7 @@ check_apt_config_wrapper process_arguments(int argc, char **argv) {
179 {"only-critical", no_argument, 0, 'o'}, 229 {"only-critical", no_argument, 0, 'o'},
180 {"input-file", required_argument, 0, INPUT_FILE_OPT}, 230 {"input-file", required_argument, 0, INPUT_FILE_OPT},
181 {"packages-warning", required_argument, 0, 'w'}, 231 {"packages-warning", required_argument, 0, 'w'},
232 {"output-format", required_argument, 0, output_format_index},
182 {0, 0, 0, 0}}; 233 {0, 0, 0, 0}};
183 234
184 check_apt_config_wrapper result = { 235 check_apt_config_wrapper result = {
@@ -257,6 +308,18 @@ check_apt_config_wrapper process_arguments(int argc, char **argv) {
257 case 'w': 308 case 'w':
258 result.config.packages_warning = atoi(optarg); 309 result.config.packages_warning = atoi(optarg);
259 break; 310 break;
311 case output_format_index: {
312 parsed_output_format parser = mp_parse_output_format(optarg);
313 if (!parser.parsing_success) {
314 // TODO List all available formats here, maybe add anothoer usage function
315 printf("Invalid output format: %s\n", optarg);
316 exit(STATE_UNKNOWN);
317 }
318
319 result.config.output_format_is_set = true;
320 result.config.output_format = parser.output_format;
321 break;
322 }
260 default: 323 default:
261 /* print short usage statement if args not parsable */ 324 /* print short usage statement if args not parsable */
262 usage5(); 325 usage5();
@@ -267,37 +330,38 @@ check_apt_config_wrapper process_arguments(int argc, char **argv) {
267} 330}
268 331
269/* run an apt-get upgrade */ 332/* run an apt-get upgrade */
270run_upgrade_result run_upgrade(const upgrade_type upgrade, const char *do_include, const char *do_exclude, const char *do_critical, 333run_upgrade_result run_upgrade(const upgrade_type upgrade, const char *do_include,
334 const char *do_exclude, const char *do_critical,
271 const char *upgrade_opts, const char *input_filename) { 335 const char *upgrade_opts, const char *input_filename) {
272 regex_t ereg; 336 regex_t exclude_regex;
273 /* initialize ereg as it is possible it is printed while uninitialized */ 337 /* initialize ereg as it is possible it is printed while uninitialized */
274 memset(&ereg, '\0', sizeof(ereg.buffer)); 338 memset(&exclude_regex, '\0', sizeof(exclude_regex.buffer));
275 339
276 run_upgrade_result result = { 340 run_upgrade_result result = {
277 .errorcode = STATE_UNKNOWN, 341 .errorcode = OK,
278 }; 342 };
279 343
280 if (upgrade == NO_UPGRADE) { 344 if (upgrade == NO_UPGRADE) {
281 result.errorcode = STATE_OK; 345 result.errorcode = OK;
282 return result; 346 return result;
283 } 347 }
284 348
285 int regres = 0; 349 int regres = 0;
286 regex_t ireg; 350 regex_t include_regex;
287 char rerrbuf[64]; 351 char rerrbuf[64];
288 /* compile the regexps */ 352 /* compile the regexps */
289 if (do_include != NULL) { 353 if (do_include != NULL) {
290 regres = regcomp(&ireg, do_include, REG_EXTENDED); 354 regres = regcomp(&include_regex, do_include, REG_EXTENDED);
291 if (regres != 0) { 355 if (regres != 0) {
292 regerror(regres, &ireg, rerrbuf, 64); 356 regerror(regres, &include_regex, rerrbuf, 64);
293 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf); 357 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf);
294 } 358 }
295 } 359 }
296 360
297 if (do_exclude != NULL) { 361 if (do_exclude != NULL) {
298 regres = regcomp(&ereg, do_exclude, REG_EXTENDED); 362 regres = regcomp(&exclude_regex, do_exclude, REG_EXTENDED);
299 if (regres != 0) { 363 if (regres != 0) {
300 regerror(regres, &ereg, rerrbuf, 64); 364 regerror(regres, &exclude_regex, rerrbuf, 64);
301 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf); 365 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf);
302 } 366 }
303 } 367 }
@@ -306,12 +370,12 @@ run_upgrade_result run_upgrade(const upgrade_type upgrade, const char *do_includ
306 const char *crit_ptr = (do_critical != NULL) ? do_critical : SECURITY_RE; 370 const char *crit_ptr = (do_critical != NULL) ? do_critical : SECURITY_RE;
307 regres = regcomp(&sreg, crit_ptr, REG_EXTENDED); 371 regres = regcomp(&sreg, crit_ptr, REG_EXTENDED);
308 if (regres != 0) { 372 if (regres != 0) {
309 regerror(regres, &ereg, rerrbuf, 64); 373 regerror(regres, &exclude_regex, rerrbuf, 64);
310 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf); 374 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf);
311 } 375 }
312 376
313 struct output chld_out; 377 output chld_out;
314 struct output chld_err; 378 output chld_err;
315 char *cmdline = NULL; 379 char *cmdline = NULL;
316 cmdline = construct_cmdline(upgrade, upgrade_opts); 380 cmdline = construct_cmdline(upgrade, upgrade_opts);
317 if (input_filename != NULL) { 381 if (input_filename != NULL) {
@@ -322,13 +386,12 @@ run_upgrade_result run_upgrade(const upgrade_type upgrade, const char *do_includ
322 result.errorcode = np_runcmd(cmdline, &chld_out, &chld_err, 0); 386 result.errorcode = np_runcmd(cmdline, &chld_out, &chld_err, 0);
323 } 387 }
324 388
325 /* apt-get upgrade only changes exit status if there is an 389 // apt-get upgrade only changes exit status if there is an
326 * internal error when run in dry-run mode. therefore we will 390 // internal error when run in dry-run mode.
327 * treat such an error as UNKNOWN */ 391 if (result.errorcode != 0) {
328 if (result.errorcode != STATE_OK) { 392 result.exec_warning = true;
329 exec_warning = 1; 393 result.errorcode = ERROR;
330 result.errorcode = STATE_UNKNOWN; 394 // fprintf(stderr, _("'%s' exited with non-zero status.\n"), cmdline);
331 fprintf(stderr, _("'%s' exited with non-zero status.\n"), cmdline);
332 } 395 }
333 396
334 char **pkglist = malloc(sizeof(char *) * chld_out.lines); 397 char **pkglist = malloc(sizeof(char *) * chld_out.lines);
@@ -349,27 +412,31 @@ run_upgrade_result run_upgrade(const upgrade_type upgrade, const char *do_includ
349 * we may need to switch to the --print-uris output format, 412 * we may need to switch to the --print-uris output format,
350 * in which case the logic here will slightly change. 413 * in which case the logic here will slightly change.
351 */ 414 */
352 int package_counter = 0; 415 size_t package_counter = 0;
353 int security_package_counter = 0; 416 size_t security_package_counter = 0;
354 for (size_t i = 0; i < chld_out.lines; i++) { 417 for (size_t i = 0; i < chld_out.lines; i++) {
355 if (verbose) { 418 if (verbose) {
356 printf("%s\n", chld_out.line[i]); 419 printf("%s\n", chld_out.line[i]);
357 } 420 }
421
358 /* if it is a package we care about */ 422 /* if it is a package we care about */
359 if (strncmp(PKGINST_PREFIX, chld_out.line[i], strlen(PKGINST_PREFIX)) == 0 && 423 if (strncmp(PKGINST_PREFIX, chld_out.line[i], strlen(PKGINST_PREFIX)) == 0 &&
360 (do_include == NULL || regexec(&ireg, chld_out.line[i], 0, NULL, 0) == 0)) { 424 (do_include == NULL || regexec(&include_regex, chld_out.line[i], 0, NULL, 0) == 0)) {
361 /* if we're not excluding, or it's not in the 425 /* if we're not excluding, or it's not in the
362 * list of stuff to exclude */ 426 * list of stuff to exclude */
363 if (do_exclude == NULL || regexec(&ereg, chld_out.line[i], 0, NULL, 0) != 0) { 427 if (do_exclude == NULL || regexec(&exclude_regex, chld_out.line[i], 0, NULL, 0) != 0) {
364 package_counter++; 428 package_counter++;
365 if (regexec(&sreg, chld_out.line[i], 0, NULL, 0) == 0) { 429 if (regexec(&sreg, chld_out.line[i], 0, NULL, 0) == 0) {
366 security_package_counter++; 430 security_package_counter++;
431
367 if (verbose) { 432 if (verbose) {
368 printf("*"); 433 printf("*");
369 } 434 }
435
370 (secpkglist)[security_package_counter - 1] = pkg_name(chld_out.line[i]); 436 (secpkglist)[security_package_counter - 1] = pkg_name(chld_out.line[i]);
371 } else { 437 } else {
372 (pkglist)[package_counter - security_package_counter - 1] = pkg_name(chld_out.line[i]); 438 (pkglist)[package_counter - security_package_counter - 1] =
439 pkg_name(chld_out.line[i]);
373 } 440 }
374 if (verbose) { 441 if (verbose) {
375 printf("*%s\n", chld_out.line[i]); 442 printf("*%s\n", chld_out.line[i]);
@@ -377,6 +444,7 @@ run_upgrade_result run_upgrade(const upgrade_type upgrade, const char *do_includ
377 } 444 }
378 } 445 }
379 } 446 }
447
380 result.package_count = package_counter; 448 result.package_count = package_counter;
381 result.security_package_count = security_package_counter; 449 result.security_package_count = security_package_counter;
382 result.packages_list = pkglist; 450 result.packages_list = pkglist;
@@ -385,41 +453,55 @@ run_upgrade_result run_upgrade(const upgrade_type upgrade, const char *do_includ
385 /* If we get anything on stderr, at least set warning */ 453 /* If we get anything on stderr, at least set warning */
386 if (input_filename == NULL && chld_err.buflen) { 454 if (input_filename == NULL && chld_err.buflen) {
387 stderr_warning = true; 455 stderr_warning = true;
388 result.errorcode = max_state(result.errorcode, STATE_WARNING); 456 result.errorcode = ERROR;
457
389 if (verbose) { 458 if (verbose) {
390 for (size_t i = 0; i < chld_err.lines; i++) { 459 for (size_t i = 0; i < chld_err.lines; i++) {
391 fprintf(stderr, "%s\n", chld_err.line[i]); 460 fprintf(stderr, "%s\n", chld_err.line[i]);
392 } 461 }
393 } 462 }
394 } 463 }
464
395 if (do_include != NULL) { 465 if (do_include != NULL) {
396 regfree(&ireg); 466 regfree(&include_regex);
397 } 467 }
468
398 regfree(&sreg); 469 regfree(&sreg);
470
399 if (do_exclude != NULL) { 471 if (do_exclude != NULL) {
400 regfree(&ereg); 472 regfree(&exclude_regex);
401 } 473 }
474
402 free(cmdline); 475 free(cmdline);
476
403 return result; 477 return result;
404} 478}
405 479
406/* run an apt-get update (needs root) */ 480/* run an apt-get update (needs root) */
407int run_update(char *update_opts) { 481run_update_result run_update(char *update_opts) {
408 int result = STATE_UNKNOWN;
409 char *cmdline; 482 char *cmdline;
410 /* run the update */ 483 /* run the update */
411 cmdline = construct_cmdline(NO_UPGRADE, update_opts); 484 cmdline = construct_cmdline(NO_UPGRADE, update_opts);
412 485
413 struct output chld_out; 486 run_update_result result = {
414 struct output chld_err; 487 .exec_warning = false,
415 result = np_runcmd(cmdline, &chld_out, &chld_err, 0); 488 .stderr_warning = false,
489 .sc = mp_subcheck_init(),
490 };
491
492 result.sc = mp_set_subcheck_default_state(result.sc, STATE_OK);
493 xasprintf(&result.sc.output, "executing '%s' first", cmdline);
494
495 output chld_out;
496 output chld_err;
497 int cmd_error = np_runcmd(cmdline, &chld_out, &chld_err, 0);
416 /* apt-get update changes exit status if it can't fetch packages. 498 /* apt-get update changes exit status if it can't fetch packages.
417 * since we were explicitly asked to do so, this is treated as 499 * since we were explicitly asked to do so, this is treated as
418 * a critical error. */ 500 * a critical error. */
419 if (result != 0) { 501 if (cmd_error != 0) {
420 exec_warning = true; 502 exec_warning = true;
421 result = STATE_CRITICAL; 503 result.sc = mp_set_subcheck_state(result.sc, STATE_CRITICAL);
422 fprintf(stderr, _("'%s' exited with non-zero status.\n"), cmdline); 504 xasprintf(&result.sc.output, _("'%s' exited with non-zero status.\n"), cmdline);
423 } 505 }
424 506
425 if (verbose) { 507 if (verbose) {
@@ -430,15 +512,18 @@ int run_update(char *update_opts) {
430 512
431 /* If we get anything on stderr, at least set warning */ 513 /* If we get anything on stderr, at least set warning */
432 if (chld_err.buflen) { 514 if (chld_err.buflen) {
433 stderr_warning = 1; 515 stderr_warning = true;
434 result = max_state(result, STATE_WARNING); 516 result.sc = mp_set_subcheck_state(
517 result.sc, max_state(mp_compute_subcheck_state(result.sc), STATE_WARNING));
435 if (verbose) { 518 if (verbose) {
436 for (size_t i = 0; i < chld_err.lines; i++) { 519 for (size_t i = 0; i < chld_err.lines; i++) {
437 fprintf(stderr, "%s\n", chld_err.line[i]); 520 fprintf(stderr, "%s\n", chld_err.line[i]);
438 } 521 }
439 } 522 }
440 } 523 }
524
441 free(cmdline); 525 free(cmdline);
526
442 return result; 527 return result;
443} 528}
444 529
@@ -520,7 +605,7 @@ char *construct_cmdline(upgrade_type upgrade, const char *opts) {
520 break; 605 break;
521 } 606 }
522 607
523 int len = 0; 608 size_t len = 0;
524 len += strlen(PATH_TO_APTGET) + 1; /* "/usr/bin/apt-get " */ 609 len += strlen(PATH_TO_APTGET) + 1; /* "/usr/bin/apt-get " */
525 len += strlen(opts_ptr) + 1; /* "opts " */ 610 len += strlen(opts_ptr) + 1; /* "opts " */
526 len += strlen(aptcmd) + 1; /* "upgrade\0" */ 611 len += strlen(aptcmd) + 1; /* "upgrade\0" */
@@ -558,7 +643,8 @@ void print_help(void) {
558 printf(" %s\n", _("List packages available for upgrade. Packages are printed sorted by")); 643 printf(" %s\n", _("List packages available for upgrade. Packages are printed sorted by"));
559 printf(" %s\n", _("name with security packages listed first.")); 644 printf(" %s\n", _("name with security packages listed first."));
560 printf(" %s\n", "-i, --include=REGEXP"); 645 printf(" %s\n", "-i, --include=REGEXP");
561 printf(" %s\n", _("Include only packages matching REGEXP. Can be specified multiple times")); 646 printf(" %s\n",
647 _("Include only packages matching REGEXP. Can be specified multiple times"));
562 printf(" %s\n", _("the values will be combined together. Any packages matching this list")); 648 printf(" %s\n", _("the values will be combined together. Any packages matching this list"));
563 printf(" %s\n", _("cause the plugin to return WARNING status. Others will be ignored.")); 649 printf(" %s\n", _("cause the plugin to return WARNING status. Others will be ignored."));
564 printf(" %s\n", _("Default is to include all packages.")); 650 printf(" %s\n", _("Default is to include all packages."));
@@ -567,7 +653,8 @@ void print_help(void) {
567 printf(" %s\n", _("otherwise be included. Can be specified multiple times; the values")); 653 printf(" %s\n", _("otherwise be included. Can be specified multiple times; the values"));
568 printf(" %s\n", _("will be combined together. Default is to exclude no packages.")); 654 printf(" %s\n", _("will be combined together. Default is to exclude no packages."));
569 printf(" %s\n", "-c, --critical=REGEXP"); 655 printf(" %s\n", "-c, --critical=REGEXP");
570 printf(" %s\n", _("If the full package information of any of the upgradable packages match")); 656 printf(" %s\n",
657 _("If the full package information of any of the upgradable packages match"));
571 printf(" %s\n", _("this REGEXP, the plugin will return CRITICAL status. Can be specified")); 658 printf(" %s\n", _("this REGEXP, the plugin will return CRITICAL status. Can be specified"));
572 printf(" %s\n", _("multiple times like above. Default is a regexp matching security")); 659 printf(" %s\n", _("multiple times like above. Default is a regexp matching security"));
573 printf(" %s\n", _("upgrades for Debian and Ubuntu:")); 660 printf(" %s\n", _("upgrades for Debian and Ubuntu:"));
@@ -576,15 +663,21 @@ void print_help(void) {
576 printf(" %s\n", _("information is compared against the critical list.")); 663 printf(" %s\n", _("information is compared against the critical list."));
577 printf(" %s\n", "-o, --only-critical"); 664 printf(" %s\n", "-o, --only-critical");
578 printf(" %s\n", _("Only warn about upgrades matching the critical list. The total number")); 665 printf(" %s\n", _("Only warn about upgrades matching the critical list. The total number"));
579 printf(" %s\n", _("of upgrades will be printed, but any non-critical upgrades will not cause")); 666 printf(" %s\n",
667 _("of upgrades will be printed, but any non-critical upgrades will not cause"));
580 printf(" %s\n", _("the plugin to return WARNING status.")); 668 printf(" %s\n", _("the plugin to return WARNING status."));
581 printf(" %s\n", "-w, --packages-warning"); 669 printf(" %s\n", "-w, --packages-warning");
582 printf(" %s\n", _("Minimum number of packages available for upgrade to return WARNING status.")); 670 printf(" %s\n",
671 _("Minimum number of packages available for upgrade to return WARNING status."));
583 printf(" %s\n\n", _("Default is 1 package.")); 672 printf(" %s\n\n", _("Default is 1 package."));
584 673
585 printf("%s\n\n", _("The following options require root privileges and should be used with care:")); 674 printf(UT_OUTPUT_FORMAT);
675
676 printf("%s\n\n",
677 _("The following options require root privileges and should be used with care:"));
586 printf(" %s\n", "-u, --update=OPTS"); 678 printf(" %s\n", "-u, --update=OPTS");
587 printf(" %s\n", _("First perform an 'apt-get update'. An optional OPTS parameter overrides")); 679 printf(" %s\n",
680 _("First perform an 'apt-get update'. An optional OPTS parameter overrides"));
588 printf(" %s\n", _("the default options. Note: you may also need to adjust the global")); 681 printf(" %s\n", _("the default options. Note: you may also need to adjust the global"));
589 printf(" %s\n", _("timeout (with -t) to prevent the plugin from timing out if apt-get")); 682 printf(" %s\n", _("timeout (with -t) to prevent the plugin from timing out if apt-get"));
590 printf(" %s\n", _("upgrade is expected to take longer than the default timeout.")); 683 printf(" %s\n", _("upgrade is expected to take longer than the default timeout."));
@@ -593,8 +686,10 @@ void print_help(void) {
593 printf(" %s\n", _("apt-get will be run with these command line options instead of the")); 686 printf(" %s\n", _("apt-get will be run with these command line options instead of the"));
594 printf(" %s", _("default ")); 687 printf(" %s", _("default "));
595 printf("(%s).\n", UPGRADE_DEFAULT_OPTS); 688 printf("(%s).\n", UPGRADE_DEFAULT_OPTS);
596 printf(" %s\n", _("Note that you may be required to have root privileges if you do not use")); 689 printf(" %s\n",
597 printf(" %s\n", _("the default options, which will only run a simulation and NOT perform the upgrade")); 690 _("Note that you may be required to have root privileges if you do not use"));
691 printf(" %s\n",
692 _("the default options, which will only run a simulation and NOT perform the upgrade"));
598 printf(" %s\n", "-d, --dist-upgrade=OPTS"); 693 printf(" %s\n", "-d, --dist-upgrade=OPTS");
599 printf(" %s\n", _("Perform a dist-upgrade instead of normal upgrade. Like with -U OPTS")); 694 printf(" %s\n", _("Perform a dist-upgrade instead of normal upgrade. Like with -U OPTS"));
600 printf(" %s\n", _("can be provided to override the default options.")); 695 printf(" %s\n", _("can be provided to override the default options."));
diff --git a/plugins/check_apt.d/config.h b/plugins/check_apt.d/config.h
index 981f4f42..e4d622f1 100644
--- a/plugins/check_apt.d/config.h
+++ b/plugins/check_apt.d/config.h
@@ -2,6 +2,7 @@
2 2
3#include "../../config.h" 3#include "../../config.h"
4#include <stddef.h> 4#include <stddef.h>
5#include "../lib/output.h"
5 6
6/* some constants */ 7/* some constants */
7typedef enum { 8typedef enum {
@@ -16,7 +17,7 @@ typedef struct {
16 bool only_critical; /* whether to warn about non-critical updates */ 17 bool only_critical; /* whether to warn about non-critical updates */
17 bool list; /* list packages available for upgrade */ 18 bool list; /* list packages available for upgrade */
18 /* number of packages available for upgrade to return WARNING status */ 19 /* number of packages available for upgrade to return WARNING status */
19 int packages_warning; 20 size_t packages_warning;
20 21
21 char *upgrade_opts; /* options to override defaults for upgrade */ 22 char *upgrade_opts; /* options to override defaults for upgrade */
22 char *update_opts; /* options to override defaults for update */ 23 char *update_opts; /* options to override defaults for update */
@@ -24,6 +25,9 @@ typedef struct {
24 char *do_exclude; /* regexp to only exclude certain packages */ 25 char *do_exclude; /* regexp to only exclude certain packages */
25 char *do_critical; /* regexp specifying critical packages */ 26 char *do_critical; /* regexp specifying critical packages */
26 char *input_filename; /* input filename for testing */ 27 char *input_filename; /* input filename for testing */
28
29 bool output_format_is_set;
30 mp_output_format output_format;
27} check_apt_config; 31} check_apt_config;
28 32
29check_apt_config check_apt_config_init() { 33check_apt_config check_apt_config_init() {
@@ -36,6 +40,7 @@ check_apt_config check_apt_config_init() {
36 .do_include = NULL, 40 .do_include = NULL,
37 .do_exclude = NULL, 41 .do_exclude = NULL,
38 .do_critical = NULL, 42 .do_critical = NULL,
39 .input_filename = NULL}; 43 .input_filename = NULL,
44 .output_format_is_set = false};
40 return tmp; 45 return tmp;
41} 46}
diff --git a/plugins/check_by_ssh.c b/plugins/check_by_ssh.c
index 2bc38d49..7ffa0ded 100644
--- a/plugins/check_by_ssh.c
+++ b/plugins/check_by_ssh.c
@@ -26,16 +26,17 @@
26 * 26 *
27 *****************************************************************************/ 27 *****************************************************************************/
28 28
29const char *progname = "check_by_ssh";
30const char *copyright = "2000-2024";
31const char *email = "devel@monitoring-plugins.org";
32
33#include "common.h" 29#include "common.h"
30#include "output.h"
34#include "utils.h" 31#include "utils.h"
35#include "utils_cmd.h" 32#include "utils_cmd.h"
36#include "check_by_ssh.d/config.h" 33#include "check_by_ssh.d/config.h"
37#include "states.h" 34#include "states.h"
38 35
36const char *progname = "check_by_ssh";
37const char *copyright = "2000-2024";
38const char *email = "devel@monitoring-plugins.org";
39
39#ifndef NP_MAXARGS 40#ifndef NP_MAXARGS
40# define NP_MAXARGS 1024 41# define NP_MAXARGS 1024
41#endif 42#endif
@@ -45,7 +46,8 @@ typedef struct {
45 check_by_ssh_config config; 46 check_by_ssh_config config;
46} check_by_ssh_config_wrapper; 47} check_by_ssh_config_wrapper;
47static check_by_ssh_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); 48static check_by_ssh_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
48static check_by_ssh_config_wrapper validate_arguments(check_by_ssh_config_wrapper /*config_wrapper*/); 49static check_by_ssh_config_wrapper
50 validate_arguments(check_by_ssh_config_wrapper /*config_wrapper*/);
49 51
50static command_construct comm_append(command_construct /*cmd*/, const char * /*str*/); 52static command_construct comm_append(command_construct /*cmd*/, const char * /*str*/);
51static void print_help(void); 53static void print_help(void);
@@ -70,6 +72,10 @@ int main(int argc, char **argv) {
70 72
71 const check_by_ssh_config config = tmp_config.config; 73 const check_by_ssh_config config = tmp_config.config;
72 74
75 if (config.output_format_is_set) {
76 mp_set_format(config.output_format);
77 }
78
73 /* Set signal handling and alarm timeout */ 79 /* Set signal handling and alarm timeout */
74 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) { 80 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
75 usage_va(_("Cannot catch SIGALRM")); 81 usage_va(_("Cannot catch SIGALRM"));
@@ -84,59 +90,99 @@ int main(int argc, char **argv) {
84 } 90 }
85 } 91 }
86 92
87 output chld_out; 93 cmd_run_result child_result = cmd_run_array2(config.cmd.commargv, 0);
88 output chld_err; 94 mp_check overall = mp_check_init();
89 mp_state_enum result = cmd_run_array(config.cmd.commargv, &chld_out, &chld_err, 0);
90 95
91 /* SSH returns 255 if connection attempt fails; include the first line of error output */ 96 /* SSH returns 255 if connection attempt fails; include the first line of error output */
92 if (result == 255 && config.unknown_timeout) { 97 // we can sadly not detect other SSH errors
93 printf(_("SSH connection failed: %s\n"), chld_err.lines > 0 ? chld_err.line[0] : "(no error output)"); 98 if (child_result.cmd_error_code == 255 && config.unknown_timeout) {
94 return STATE_UNKNOWN; 99 mp_subcheck sc_ssh_execution = mp_subcheck_init();
100 xasprintf(&sc_ssh_execution.output, "SSH connection failed: %s",
101 child_result.err.lines > 0 ? child_result.err.line[0]
102 : "(no error output)");
103
104 sc_ssh_execution = mp_set_subcheck_state(sc_ssh_execution, STATE_UNKNOWN);
105 mp_add_subcheck_to_check(&overall, sc_ssh_execution);
106 mp_exit(overall);
95 } 107 }
96 108
97 if (verbose) { 109 if (verbose) {
98 for (size_t i = 0; i < chld_out.lines; i++) { 110 for (size_t i = 0; i < child_result.out.lines; i++) {
99 printf("stdout: %s\n", chld_out.line[i]); 111 printf("stdout: %s\n", child_result.out.line[i]);
100 } 112 }
101 for (size_t i = 0; i < chld_err.lines; i++) { 113 for (size_t i = 0; i < child_result.err.lines; i++) {
102 printf("stderr: %s\n", chld_err.line[i]); 114 printf("stderr: %s\n", child_result.err.line[i]);
103 } 115 }
104 } 116 }
105 117
106 size_t skip_stdout = 0; 118 size_t skip_stdout = 0;
107 if (config.skip_stdout == -1) { /* --skip-stdout specified without argument */ 119 if (config.skip_stdout) { /* --skip-stdout specified without argument */
108 skip_stdout = chld_out.lines; 120 skip_stdout = child_result.out.lines;
109 } else { 121 } else {
110 skip_stdout = config.skip_stdout; 122 skip_stdout = config.stdout_lines_to_ignore;
111 } 123 }
112 124
113 size_t skip_stderr = 0; 125 size_t skip_stderr = 0;
114 if (config.skip_stderr == -1) { /* --skip-stderr specified without argument */ 126 if (config.skip_stderr) { /* --skip-stderr specified without argument */
115 skip_stderr = chld_err.lines; 127 skip_stderr = child_result.err.lines;
116 } else { 128 } else {
117 skip_stderr = config.skip_stderr; 129 skip_stderr = config.sterr_lines_to_ignore;
118 } 130 }
119 131
120 /* UNKNOWN or worse if (non-skipped) output found on stderr */ 132 /* Allow UNKNOWN or WARNING state for (non-skipped) output found on stderr */
121 if (chld_err.lines > (size_t)skip_stderr) { 133 if (child_result.err.lines > skip_stderr &&
122 printf(_("Remote command execution failed: %s\n"), chld_err.line[skip_stderr]); 134 (config.unknown_on_stderr || config.warn_on_stderr)) {
135 mp_subcheck sc_stderr = mp_subcheck_init();
136 xasprintf(&sc_stderr.output, "remote command execution failed: %s",
137 child_result.err.line[skip_stderr]);
138
139 if (config.unknown_on_stderr) {
140 sc_stderr = mp_set_subcheck_state(sc_stderr, STATE_UNKNOWN);
141 }
142
123 if (config.warn_on_stderr) { 143 if (config.warn_on_stderr) {
124 return max_state_alt(result, STATE_WARNING); 144 sc_stderr = mp_set_subcheck_state(sc_stderr, STATE_WARNING);
125 } 145 }
126 return max_state_alt(result, STATE_UNKNOWN); 146
147 mp_add_subcheck_to_check(&overall, sc_stderr);
148 // TODO still exit here?
127 } 149 }
128 150
129 /* this is simple if we're not supposed to be passive. 151 /* this is simple if we're not supposed to be passive.
130 * Wrap up quickly and keep the tricks below */ 152 * Wrap up quickly and keep the tricks below */
131 if (!config.passive) { 153 if (!config.passive) {
132 if (chld_out.lines > (size_t)skip_stdout) { 154 mp_subcheck sc_active_check = mp_subcheck_init();
133 for (size_t i = skip_stdout; i < chld_out.lines; i++) { 155 xasprintf(&sc_active_check.output, "command stdout:");
134 puts(chld_out.line[i]); 156
157 if (child_result.out.lines > skip_stdout) {
158 for (size_t i = skip_stdout; i < child_result.out.lines; i++) {
159 xasprintf(&sc_active_check.output, "%s\n%s", sc_active_check.output,
160 child_result.out.line[i]);
135 } 161 }
136 } else { 162 } else {
137 printf(_("%s - check_by_ssh: Remote command '%s' returned status %d\n"), state_text(result), config.remotecmd, result); 163 xasprintf(&sc_active_check.output, "remote command '%s' returned status %d",
164 config.remotecmd, child_result.cmd_error_code);
138 } 165 }
139 return result; /* return error status from remote command */ 166
167 /* return error status from remote command */
168
169 switch (child_result.cmd_error_code) {
170 case 0:
171 sc_active_check = mp_set_subcheck_state(sc_active_check, STATE_OK);
172 break;
173 case 1:
174 sc_active_check = mp_set_subcheck_state(sc_active_check, STATE_WARNING);
175 break;
176 case 2:
177 sc_active_check = mp_set_subcheck_state(sc_active_check, STATE_CRITICAL);
178 break;
179 default:
180 sc_active_check = mp_set_subcheck_state(sc_active_check, STATE_UNKNOWN);
181 break;
182 }
183
184 mp_add_subcheck_to_check(&overall, sc_active_check);
185 mp_exit(overall);
140 } 186 }
141 187
142 /* 188 /*
@@ -144,62 +190,88 @@ int main(int argc, char **argv) {
144 */ 190 */
145 191
146 /* process output */ 192 /* process output */
147 FILE *file_pointer = NULL; 193 mp_subcheck sc_passive_file = mp_subcheck_init();
148 if (!(file_pointer = fopen(config.outputfile, "a"))) { 194 FILE *output_file = NULL;
149 printf(_("SSH WARNING: could not open %s\n"), config.outputfile); 195 if (!(output_file = fopen(config.outputfile, "a"))) {
150 exit(STATE_UNKNOWN); 196 xasprintf(&sc_passive_file.output, "could not open %s", config.outputfile);
197 sc_passive_file = mp_set_subcheck_state(sc_passive_file, STATE_UNKNOWN);
198
199 mp_add_subcheck_to_check(&overall, sc_passive_file);
200 mp_exit(overall);
151 } 201 }
152 202
203 xasprintf(&sc_passive_file.output, "opened output file %s", config.outputfile);
204 sc_passive_file = mp_set_subcheck_state(sc_passive_file, STATE_OK);
205 mp_add_subcheck_to_check(&overall, sc_passive_file);
206
153 time_t local_time = time(NULL); 207 time_t local_time = time(NULL);
154 unsigned int commands = 0; 208 unsigned int commands = 0;
155 char *status_text; 209 char *status_text;
156 int cresult; 210 int cresult;
157 for (size_t i = skip_stdout; i < chld_out.lines; i++) { 211 mp_subcheck sc_parse_passive = mp_subcheck_init();
158 status_text = chld_out.line[i++]; 212 for (size_t i = skip_stdout; i < child_result.out.lines; i++) {
159 if (i == chld_out.lines || strstr(chld_out.line[i], "STATUS CODE: ") == NULL) { 213 status_text = child_result.out.line[i++];
160 die(STATE_UNKNOWN, _("%s: Error parsing output\n"), progname); 214 if (i == child_result.out.lines ||
215 strstr(child_result.out.line[i], "STATUS CODE: ") == NULL) {
216
217 sc_parse_passive = mp_set_subcheck_state(sc_parse_passive, STATE_UNKNOWN);
218 xasprintf(&sc_parse_passive.output, "failed to parse output");
219 mp_add_subcheck_to_check(&overall, sc_parse_passive);
220 mp_exit(overall);
161 } 221 }
162 222
163 if (config.service[commands] && status_text && sscanf(chld_out.line[i], "STATUS CODE: %d", &cresult) == 1) { 223 if (config.service[commands] && status_text &&
164 fprintf(file_pointer, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", (int)local_time, config.host_shortname, 224 sscanf(child_result.out.line[i], "STATUS CODE: %d", &cresult) == 1) {
165 config.service[commands++], cresult, status_text); 225 fprintf(output_file, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", (int)local_time,
226 config.host_shortname, config.service[commands++], cresult, status_text);
166 } 227 }
167 } 228 }
168 229
230 sc_parse_passive = mp_set_subcheck_state(sc_parse_passive, STATE_OK);
231 xasprintf(&sc_parse_passive.output, "parsed and wrote output");
232 mp_add_subcheck_to_check(&overall, sc_parse_passive);
233
169 /* Multiple commands and passive checking should always return OK */ 234 /* Multiple commands and passive checking should always return OK */
170 exit(result); 235 mp_exit(overall);
171} 236}
172 237
173/* process command-line arguments */ 238/* process command-line arguments */
174check_by_ssh_config_wrapper process_arguments(int argc, char **argv) { 239check_by_ssh_config_wrapper process_arguments(int argc, char **argv) {
175 static struct option longopts[] = {{"version", no_argument, 0, 'V'}, 240 enum {
176 {"help", no_argument, 0, 'h'}, 241 output_format_index = CHAR_MAX + 1,
177 {"verbose", no_argument, 0, 'v'}, 242 };
178 {"fork", no_argument, 0, 'f'}, 243
179 {"timeout", required_argument, 0, 't'}, 244 static struct option longopts[] = {
180 {"unknown-timeout", no_argument, 0, 'U'}, 245 {"version", no_argument, 0, 'V'},
181 {"host", required_argument, 0, 'H'}, /* backward compatibility */ 246 {"help", no_argument, 0, 'h'},
182 {"hostname", required_argument, 0, 'H'}, 247 {"verbose", no_argument, 0, 'v'},
183 {"port", required_argument, 0, 'p'}, 248 {"fork", no_argument, 0, 'f'},
184 {"output", required_argument, 0, 'O'}, 249 {"timeout", required_argument, 0, 't'},
185 {"name", required_argument, 0, 'n'}, 250 {"unknown-timeout", no_argument, 0, 'U'},
186 {"services", required_argument, 0, 's'}, 251 {"host", required_argument, 0, 'H'}, /* backward compatibility */
187 {"identity", required_argument, 0, 'i'}, 252 {"hostname", required_argument, 0, 'H'},
188 {"user", required_argument, 0, 'u'}, 253 {"port", required_argument, 0, 'p'},
189 {"logname", required_argument, 0, 'l'}, 254 {"output", required_argument, 0, 'O'},
190 {"command", required_argument, 0, 'C'}, 255 {"name", required_argument, 0, 'n'},
191 {"skip", optional_argument, 0, 'S'}, /* backwards compatibility */ 256 {"services", required_argument, 0, 's'},
192 {"skip-stdout", optional_argument, 0, 'S'}, 257 {"identity", required_argument, 0, 'i'},
193 {"skip-stderr", optional_argument, 0, 'E'}, 258 {"user", required_argument, 0, 'u'}, /* backwards compatibility */
194 {"warn-on-stderr", no_argument, 0, 'W'}, 259 {"logname", required_argument, 0, 'l'},
195 {"proto1", no_argument, 0, '1'}, 260 {"command", required_argument, 0, 'C'},
196 {"proto2", no_argument, 0, '2'}, 261 {"skip", optional_argument, 0, 'S'}, /* backwards compatibility */
197 {"use-ipv4", no_argument, 0, '4'}, 262 {"skip-stdout", optional_argument, 0, 'S'},
198 {"use-ipv6", no_argument, 0, '6'}, 263 {"skip-stderr", optional_argument, 0, 'E'},
199 {"ssh-option", required_argument, 0, 'o'}, 264 {"unknown-on-stderr", no_argument, 0, 'e'},
200 {"quiet", no_argument, 0, 'q'}, 265 {"warn-on-stderr", no_argument, 0, 'W'},
201 {"configfile", optional_argument, 0, 'F'}, 266 {"proto1", no_argument, 0, '1'},
202 {0, 0, 0, 0}}; 267 {"proto2", no_argument, 0, '2'},
268 {"use-ipv4", no_argument, 0, '4'},
269 {"use-ipv6", no_argument, 0, '6'},
270 {"ssh-option", required_argument, 0, 'o'},
271 {"quiet", no_argument, 0, 'q'},
272 {"configfile", optional_argument, 0, 'F'},
273 {"output-format", required_argument, 0, output_format_index},
274 {0, 0, 0, 0}};
203 275
204 check_by_ssh_config_wrapper result = { 276 check_by_ssh_config_wrapper result = {
205 .errorcode = OK, 277 .errorcode = OK,
@@ -221,7 +293,8 @@ check_by_ssh_config_wrapper process_arguments(int argc, char **argv) {
221 293
222 int option = 0; 294 int option = 0;
223 while (true) { 295 while (true) {
224 int opt_index = getopt_long(argc, argv, "Vvh1246fqt:UH:O:p:i:u:l:C:S::E::n:s:o:F:", longopts, &option); 296 int opt_index =
297 getopt_long(argc, argv, "Vvh1246fqt:UH:O:p:i:u:l:C:S::E::n:s:o:F:", longopts, &option);
225 298
226 if (opt_index == -1 || opt_index == EOF) { 299 if (opt_index == -1 || opt_index == EOF) {
227 break; 300 break;
@@ -266,11 +339,13 @@ check_by_ssh_config_wrapper process_arguments(int argc, char **argv) {
266 char *p2; 339 char *p2;
267 340
268 p1 = optarg; 341 p1 = optarg;
269 result.config.service = realloc(result.config.service, (++result.config.number_of_services) * sizeof(char *)); 342 result.config.service = realloc(result.config.service,
343 (++result.config.number_of_services) * sizeof(char *));
270 while ((p2 = index(p1, ':'))) { 344 while ((p2 = index(p1, ':'))) {
271 *p2 = '\0'; 345 *p2 = '\0';
272 result.config.service[result.config.number_of_services - 1] = p1; 346 result.config.service[result.config.number_of_services - 1] = p1;
273 result.config.service = realloc(result.config.service, (++result.config.number_of_services) * sizeof(char *)); 347 result.config.service = realloc(
348 result.config.service, (++result.config.number_of_services) * sizeof(char *));
274 p1 = p2 + 1; 349 p1 = p2 + 1;
275 } 350 }
276 result.config.service[result.config.number_of_services - 1] = p1; 351 result.config.service[result.config.number_of_services - 1] = p1;
@@ -309,28 +384,39 @@ check_by_ssh_config_wrapper process_arguments(int argc, char **argv) {
309 case 'C': /* Command for remote machine */ 384 case 'C': /* Command for remote machine */
310 result.config.commands++; 385 result.config.commands++;
311 if (result.config.commands > 1) { 386 if (result.config.commands > 1) {
312 xasprintf(&result.config.remotecmd, "%s;echo STATUS CODE: $?;", result.config.remotecmd); 387 xasprintf(&result.config.remotecmd, "%s;echo STATUS CODE: $?;",
388 result.config.remotecmd);
313 } 389 }
314 xasprintf(&result.config.remotecmd, "%s%s", result.config.remotecmd, optarg); 390 xasprintf(&result.config.remotecmd, "%s%s", result.config.remotecmd, optarg);
315 break; 391 break;
316 case 'S': /* skip n (or all) lines on stdout */ 392 case 'S': /* skip n (or all) lines on stdout */
317 if (optarg == NULL) { 393 if (optarg == NULL) {
318 result.config.skip_stdout = -1; /* skip all output on stdout */ 394 result.config.skip_stdout = true; /* skip all output on stdout */
395
396 if (verbose) {
397 printf("Setting the skip_stdout flag\n");
398 }
319 } else if (!is_integer(optarg)) { 399 } else if (!is_integer(optarg)) {
320 usage_va(_("skip-stdout argument must be an integer")); 400 usage_va(_("skip-stdout argument must be an integer"));
321 } else { 401 } else {
322 result.config.skip_stdout = atoi(optarg); 402 result.config.stdout_lines_to_ignore = atoi(optarg);
323 } 403 }
324 break; 404 break;
325 case 'E': /* skip n (or all) lines on stderr */ 405 case 'E': /* skip n (or all) lines on stderr */
326 if (optarg == NULL) { 406 if (optarg == NULL) {
327 result.config.skip_stderr = -1; /* skip all output on stderr */ 407 result.config.skip_stderr = true; /* skip all output on stderr */
408 if (verbose) {
409 printf("Setting the skip_stderr flag\n");
410 }
328 } else if (!is_integer(optarg)) { 411 } else if (!is_integer(optarg)) {
329 usage_va(_("skip-stderr argument must be an integer")); 412 usage_va(_("skip-stderr argument must be an integer"));
330 } else { 413 } else {
331 result.config.skip_stderr = atoi(optarg); 414 result.config.sterr_lines_to_ignore = atoi(optarg);
332 } 415 }
333 break; 416 break;
417 case 'e': /* exit with unknown if there is an output on stderr */
418 result.config.unknown_on_stderr = true;
419 break;
334 case 'W': /* exit with warning if there is an output on stderr */ 420 case 'W': /* exit with warning if there is an output on stderr */
335 result.config.warn_on_stderr = true; 421 result.config.warn_on_stderr = true;
336 break; 422 break;
@@ -345,6 +431,18 @@ check_by_ssh_config_wrapper process_arguments(int argc, char **argv) {
345 result.config.cmd = comm_append(result.config.cmd, "-F"); 431 result.config.cmd = comm_append(result.config.cmd, "-F");
346 result.config.cmd = comm_append(result.config.cmd, optarg); 432 result.config.cmd = comm_append(result.config.cmd, optarg);
347 break; 433 break;
434 case output_format_index: {
435 parsed_output_format parser = mp_parse_output_format(optarg);
436 if (!parser.parsing_success) {
437 // TODO List all available formats here, maybe add anothoer usage function
438 printf("Invalid output format: %s\n", optarg);
439 exit(STATE_UNKNOWN);
440 }
441
442 result.config.output_format_is_set = true;
443 result.config.output_format = parser.output_format;
444 break;
445 }
348 default: /* help */ 446 default: /* help */
349 usage5(); 447 usage5();
350 } 448 }
@@ -396,7 +494,8 @@ command_construct comm_append(command_construct cmd, const char *str) {
396 die(STATE_UNKNOWN, _("%s: Argument limit of %d exceeded\n"), progname, NP_MAXARGS); 494 die(STATE_UNKNOWN, _("%s: Argument limit of %d exceeded\n"), progname, NP_MAXARGS);
397 } 495 }
398 496
399 if ((cmd.commargv = (char **)realloc(cmd.commargv, (cmd.commargc + 1) * sizeof(char *))) == NULL) { 497 if ((cmd.commargv = (char **)realloc(cmd.commargv, (cmd.commargc + 1) * sizeof(char *))) ==
498 NULL) {
400 die(STATE_UNKNOWN, _("Can not (re)allocate 'commargv' buffer\n")); 499 die(STATE_UNKNOWN, _("Can not (re)allocate 'commargv' buffer\n"));
401 } 500 }
402 501
@@ -412,12 +511,18 @@ check_by_ssh_config_wrapper validate_arguments(check_by_ssh_config_wrapper confi
412 return config_wrapper; 511 return config_wrapper;
413 } 512 }
414 513
415 if (config_wrapper.config.passive && config_wrapper.config.commands != config_wrapper.config.number_of_services) { 514 if (config_wrapper.config.passive &&
416 die(STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname); 515 config_wrapper.config.commands != config_wrapper.config.number_of_services) {
516 die(STATE_UNKNOWN,
517 _("%s: In passive mode, you must provide a service name for each command.\n"),
518 progname);
417 } 519 }
418 520
419 if (config_wrapper.config.passive && config_wrapper.config.host_shortname == NULL) { 521 if (config_wrapper.config.passive && config_wrapper.config.host_shortname == NULL) {
420 die(STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the monitoring configs.\n"), progname); 522 die(STATE_UNKNOWN,
523 _("%s: In passive mode, you must provide the host short name from the monitoring "
524 "configs.\n"),
525 progname);
421 } 526 }
422 527
423 return config_wrapper; 528 return config_wrapper;
@@ -451,10 +556,13 @@ void print_help(void) {
451 printf(" %s\n", _("Ignore all or (if specified) first n lines on STDOUT [optional]")); 556 printf(" %s\n", _("Ignore all or (if specified) first n lines on STDOUT [optional]"));
452 printf(" %s\n", "-E, --skip-stderr[=n]"); 557 printf(" %s\n", "-E, --skip-stderr[=n]");
453 printf(" %s\n", _("Ignore all or (if specified) first n lines on STDERR [optional]")); 558 printf(" %s\n", _("Ignore all or (if specified) first n lines on STDERR [optional]"));
454 printf(" %s\n", "-W, --warn-on-stderr]"); 559 printf(" %s\n", "-e, --unknown-on-stderr");
455 printf(" %s\n", _("Exit with an warning, if there is an output on STDERR")); 560 printf(" %s\n", _("Exit with UNKNOWN, if there is output on STDERR"));
561 printf(" %s\n", "-W, --warn-on-stderr");
562 printf(" %s\n", _("Exit with WARNING, if there is output on STDERR"));
456 printf(" %s\n", "-f"); 563 printf(" %s\n", "-f");
457 printf(" %s\n", _("tells ssh to fork rather than create a tty [optional]. This will always return OK if ssh is executed")); 564 printf(" %s\n", _("tells ssh to fork rather than create a tty [optional]. This will always "
565 "return OK if ssh is executed"));
458 printf(" %s\n", "-C, --command='COMMAND STRING'"); 566 printf(" %s\n", "-C, --command='COMMAND STRING'");
459 printf(" %s\n", _("command to execute on the remote machine")); 567 printf(" %s\n", _("command to execute on the remote machine"));
460 printf(" %s\n", "-l, --logname=USERNAME"); 568 printf(" %s\n", "-l, --logname=USERNAME");
@@ -477,6 +585,7 @@ void print_help(void) {
477 printf(" %s\n", "-U, --unknown-timeout"); 585 printf(" %s\n", "-U, --unknown-timeout");
478 printf(" %s\n", _("Make connection problems return UNKNOWN instead of CRITICAL")); 586 printf(" %s\n", _("Make connection problems return UNKNOWN instead of CRITICAL"));
479 printf(UT_VERBOSE); 587 printf(UT_VERBOSE);
588 printf(UT_OUTPUT_FORMAT);
480 printf("\n"); 589 printf("\n");
481 printf(" %s\n", _("The most common mode of use is to refer to a local identity file with")); 590 printf(" %s\n", _("The most common mode of use is to refer to a local identity file with"));
482 printf(" %s\n", _("the '-i' option. In this mode, the identity pair should have a null")); 591 printf(" %s\n", _("the '-i' option. In this mode, the identity pair should have a null"));
@@ -490,7 +599,8 @@ void print_help(void) {
490 printf(" %s\n", _("all of -O, -s, and -n options (servicelist order must match '-C'options)")); 599 printf(" %s\n", _("all of -O, -s, and -n options (servicelist order must match '-C'options)"));
491 printf("\n"); 600 printf("\n");
492 printf("%s\n", _("Examples:")); 601 printf("%s\n", _("Examples:"));
493 printf(" %s\n", "$ check_by_ssh -H localhost -n lh -s c1:c2:c3 -C uptime -C uptime -C uptime -O /tmp/foo"); 602 printf(" %s\n", "$ check_by_ssh -H localhost -n lh -s c1:c2:c3 -C uptime -C uptime -C "
603 "uptime -O /tmp/foo");
494 printf(" %s\n", "$ cat /tmp/foo"); 604 printf(" %s\n", "$ cat /tmp/foo");
495 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days"); 605 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days");
496 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days"); 606 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days");
@@ -502,7 +612,7 @@ void print_help(void) {
502void print_usage(void) { 612void print_usage(void) {
503 printf("%s\n", _("Usage:")); 613 printf("%s\n", _("Usage:"));
504 printf(" %s -H <host> -C <command> [-fqvU] [-1|-2] [-4|-6]\n" 614 printf(" %s -H <host> -C <command> [-fqvU] [-1|-2] [-4|-6]\n"
505 " [-S [lines]] [-E [lines]] [-W] [-t timeout] [-i identity]\n" 615 " [-S [lines]] [-E [lines]] [-e|-W] [-t timeout] [-i identity]\n"
506 " [-l user] [-n name] [-s servicelist] [-O outputfile]\n" 616 " [-l user] [-n name] [-s servicelist] [-O outputfile]\n"
507 " [-p port] [-o ssh-option] [-F configfile]\n", 617 " [-p port] [-o ssh-option] [-F configfile]\n",
508 progname); 618 progname);
diff --git a/plugins/check_by_ssh.d/config.h b/plugins/check_by_ssh.d/config.h
index 05435def..b6a57964 100644
--- a/plugins/check_by_ssh.d/config.h
+++ b/plugins/check_by_ssh.d/config.h
@@ -1,6 +1,7 @@
1#pragma once 1#pragma once
2 2
3#include "../../config.h" 3#include "../../config.h"
4#include "output.h"
4#include <stddef.h> 5#include <stddef.h>
5 6
6typedef struct { 7typedef struct {
@@ -21,11 +22,18 @@ typedef struct {
21 command_construct cmd; 22 command_construct cmd;
22 23
23 bool unknown_timeout; 24 bool unknown_timeout;
25 bool unknown_on_stderr;
24 bool warn_on_stderr; 26 bool warn_on_stderr;
25 int skip_stdout; 27 bool skip_stdout;
26 int skip_stderr; 28 size_t stdout_lines_to_ignore;
29 bool skip_stderr;
30 size_t sterr_lines_to_ignore;
31
27 bool passive; 32 bool passive;
28 char *outputfile; 33 char *outputfile;
34
35 bool output_format_is_set;
36 mp_output_format output_format;
29} check_by_ssh_config; 37} check_by_ssh_config;
30 38
31check_by_ssh_config check_by_ssh_config_init() { 39check_by_ssh_config check_by_ssh_config_init() {
@@ -46,11 +54,18 @@ check_by_ssh_config check_by_ssh_config_init() {
46 }, 54 },
47 55
48 .unknown_timeout = false, 56 .unknown_timeout = false,
57 .unknown_on_stderr = false,
49 .warn_on_stderr = false, 58 .warn_on_stderr = false,
50 .skip_stderr = 0, 59
51 .skip_stdout = 0, 60 .skip_stderr = false,
61 .stdout_lines_to_ignore = 0,
62 .skip_stdout = false,
63 .sterr_lines_to_ignore = 0,
64
52 .passive = false, 65 .passive = false,
53 .outputfile = NULL, 66 .outputfile = NULL,
67
68 .output_format_is_set = false,
54 }; 69 };
55 return tmp; 70 return tmp;
56} 71}
diff --git a/plugins/check_cluster.c b/plugins/check_cluster.c
index 9b695499..1cbdcd60 100644
--- a/plugins/check_cluster.c
+++ b/plugins/check_cluster.c
@@ -26,6 +26,8 @@ const char *progname = "check_cluster";
26const char *copyright = "2000-2024"; 26const char *copyright = "2000-2024";
27const char *email = "devel@monitoring-plugins.org"; 27const char *email = "devel@monitoring-plugins.org";
28 28
29#include "output.h"
30#include "states.h"
29#include "common.h" 31#include "common.h"
30#include "utils.h" 32#include "utils.h"
31#include "utils_base.h" 33#include "utils_base.h"
@@ -57,6 +59,10 @@ int main(int argc, char **argv) {
57 59
58 const check_cluster_config config = tmp_config.config; 60 const check_cluster_config config = tmp_config.config;
59 61
62 if (config.output_format_is_set) {
63 mp_set_format(config.output_format);
64 }
65
60 /* Initialize the thresholds */ 66 /* Initialize the thresholds */
61 if (verbose) { 67 if (verbose) {
62 print_thresholds("check_cluster", config.thresholds); 68 print_thresholds("check_cluster", config.thresholds);
@@ -72,7 +78,6 @@ int main(int argc, char **argv) {
72 int total_hosts_unreachable = 0; 78 int total_hosts_unreachable = 0;
73 /* check the data values */ 79 /* check the data values */
74 for (char *ptr = strtok(config.data_vals, ","); ptr != NULL; ptr = strtok(NULL, ",")) { 80 for (char *ptr = strtok(config.data_vals, ","); ptr != NULL; ptr = strtok(NULL, ",")) {
75
76 data_val = atoi(ptr); 81 data_val = atoi(ptr);
77 82
78 if (config.check_type == CHECK_SERVICES) { 83 if (config.check_type == CHECK_SERVICES) {
@@ -109,28 +114,49 @@ int main(int argc, char **argv) {
109 } 114 }
110 } 115 }
111 116
112 int return_code = STATE_OK; 117 mp_check overall = mp_check_init();
118 mp_subcheck sc_real_test = mp_subcheck_init();
119 sc_real_test = mp_set_subcheck_default_state(sc_real_test, STATE_OK);
120
113 /* return the status of the cluster */ 121 /* return the status of the cluster */
114 if (config.check_type == CHECK_SERVICES) { 122 if (config.check_type == CHECK_SERVICES) {
115 return_code = get_status(total_services_warning + total_services_unknown + total_services_critical, config.thresholds); 123 sc_real_test = mp_set_subcheck_state(
116 printf("CLUSTER %s: %s: %d ok, %d warning, %d unknown, %d critical\n", state_text(return_code), 124 sc_real_test,
117 (config.label == NULL) ? "Service cluster" : config.label, total_services_ok, total_services_warning, total_services_unknown, 125 get_status(total_services_warning + total_services_unknown + total_services_critical,
118 total_services_critical); 126 config.thresholds));
127 xasprintf(&sc_real_test.output, "%s: %d ok, %d warning, %d unknown, %d critical",
128 (config.label == NULL) ? "Service cluster" : config.label, total_services_ok,
129 total_services_warning, total_services_unknown, total_services_critical);
119 } else { 130 } else {
120 return_code = get_status(total_hosts_down + total_hosts_unreachable, config.thresholds); 131 sc_real_test = mp_set_subcheck_state(
121 printf("CLUSTER %s: %s: %d up, %d down, %d unreachable\n", state_text(return_code), 132 sc_real_test,
122 (config.label == NULL) ? "Host cluster" : config.label, total_hosts_up, total_hosts_down, total_hosts_unreachable); 133 get_status(total_hosts_down + total_hosts_unreachable, config.thresholds));
134 xasprintf(&sc_real_test.output, "%s: %d up, %d down, %d unreachable\n",
135 (config.label == NULL) ? "Host cluster" : config.label, total_hosts_up,
136 total_hosts_down, total_hosts_unreachable);
123 } 137 }
124 138
125 exit(return_code); 139 mp_add_subcheck_to_check(&overall, sc_real_test);
140
141 mp_exit(overall);
126} 142}
127 143
128check_cluster_config_wrapper process_arguments(int argc, char **argv) { 144check_cluster_config_wrapper process_arguments(int argc, char **argv) {
129 static struct option longopts[] = {{"data", required_argument, 0, 'd'}, {"warning", required_argument, 0, 'w'}, 145 enum {
130 {"critical", required_argument, 0, 'c'}, {"label", required_argument, 0, 'l'}, 146 output_format_index = CHAR_MAX + 1,
131 {"host", no_argument, 0, 'h'}, {"service", no_argument, 0, 's'}, 147 };
132 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, 148
133 {"help", no_argument, 0, 'H'}, {0, 0, 0, 0}}; 149 static struct option longopts[] = {{"data", required_argument, 0, 'd'},
150 {"warning", required_argument, 0, 'w'},
151 {"critical", required_argument, 0, 'c'},
152 {"label", required_argument, 0, 'l'},
153 {"host", no_argument, 0, 'h'},
154 {"service", no_argument, 0, 's'},
155 {"verbose", no_argument, 0, 'v'},
156 {"version", no_argument, 0, 'V'},
157 {"help", no_argument, 0, 'H'},
158 {"output-format", required_argument, 0, output_format_index},
159 {0, 0, 0, 0}};
134 160
135 check_cluster_config_wrapper result = { 161 check_cluster_config_wrapper result = {
136 .errorcode = OK, 162 .errorcode = OK,
@@ -197,6 +223,18 @@ check_cluster_config_wrapper process_arguments(int argc, char **argv) {
197 print_help(); 223 print_help();
198 exit(STATE_UNKNOWN); 224 exit(STATE_UNKNOWN);
199 break; 225 break;
226 case output_format_index: {
227 parsed_output_format parser = mp_parse_output_format(optarg);
228 if (!parser.parsing_success) {
229 // TODO List all available formats here, maybe add anothoer usage function
230 printf("Invalid output format: %s\n", optarg);
231 exit(STATE_UNKNOWN);
232 }
233
234 result.config.output_format_is_set = true;
235 result.config.output_format = parser.output_format;
236 break;
237 }
200 default: 238 default:
201 result.errorcode = ERROR; 239 result.errorcode = ERROR;
202 return result; 240 return result;
@@ -244,6 +282,8 @@ void print_help(void) {
244 282
245 printf(UT_VERBOSE); 283 printf(UT_VERBOSE);
246 284
285 printf(UT_OUTPUT_FORMAT);
286
247 printf("\n"); 287 printf("\n");
248 printf("%s\n", _("Notes:")); 288 printf("%s\n", _("Notes:"));
249 printf(UT_THRESHOLDS_NOTES); 289 printf(UT_THRESHOLDS_NOTES);
@@ -251,7 +291,8 @@ void print_help(void) {
251 printf("\n"); 291 printf("\n");
252 printf("%s\n", _("Examples:")); 292 printf("%s\n", _("Examples:"));
253 printf(" %s\n", "check_cluster -s -d 2,0,2,0 -c @3:"); 293 printf(" %s\n", "check_cluster -s -d 2,0,2,0 -c @3:");
254 printf(" %s\n", _("Will alert critical if there are 3 or more service data points in a non-OK")); 294 printf(" %s\n",
295 _("Will alert critical if there are 3 or more service data points in a non-OK"));
255 printf(" %s\n", _("state.")); 296 printf(" %s\n", _("state."));
256 297
257 printf(UT_SUPPORT); 298 printf(UT_SUPPORT);
diff --git a/plugins/check_cluster.d/config.h b/plugins/check_cluster.d/config.h
index fc386415..054657b0 100644
--- a/plugins/check_cluster.d/config.h
+++ b/plugins/check_cluster.d/config.h
@@ -2,6 +2,7 @@
2 2
3#include "../../config.h" 3#include "../../config.h"
4#include "../../lib/thresholds.h" 4#include "../../lib/thresholds.h"
5#include "output.h"
5#include <stddef.h> 6#include <stddef.h>
6 7
7enum { 8enum {
@@ -14,6 +15,9 @@ typedef struct {
14 thresholds *thresholds; 15 thresholds *thresholds;
15 int check_type; 16 int check_type;
16 char *label; 17 char *label;
18
19 mp_output_format output_format;
20 bool output_format_is_set;
17} check_cluster_config; 21} check_cluster_config;
18 22
19check_cluster_config check_cluster_config_init() { 23check_cluster_config check_cluster_config_init() {
@@ -22,6 +26,8 @@ check_cluster_config check_cluster_config_init() {
22 .thresholds = NULL, 26 .thresholds = NULL,
23 .check_type = CHECK_SERVICES, 27 .check_type = CHECK_SERVICES,
24 .label = NULL, 28 .label = NULL,
29
30 .output_format_is_set = false,
25 }; 31 };
26 return tmp; 32 return tmp;
27} 33}
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index 748201e8..e7737c7c 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -32,16 +32,23 @@
32 * 32 *
33 * 33 *
34 *****************************************************************************/ 34 *****************************************************************************/
35const char *progname = "check_curl";
36 35
36const char *progname = "check_curl";
37const char *copyright = "2006-2024"; 37const char *copyright = "2006-2024";
38const char *email = "devel@monitoring-plugins.org"; 38const char *email = "devel@monitoring-plugins.org";
39 39
40#include "check_curl.d/config.h"
41#include "states.h"
42#include "thresholds.h"
40#include <stdbool.h> 43#include <stdbool.h>
41#include <ctype.h> 44#include <ctype.h>
45#include "output.h"
46#include "perfdata.h"
42 47
48#include <assert.h>
43#include "common.h" 49#include "common.h"
44#include "utils.h" 50#include "utils.h"
51#include "./check_curl.d/check_curl_helpers.h"
45 52
46#ifndef LIBCURL_PROTOCOL_HTTP 53#ifndef LIBCURL_PROTOCOL_HTTP
47# error libcurl compiled without HTTP support, compiling check_curl plugin does not makes a lot of sense 54# error libcurl compiled without HTTP support, compiling check_curl plugin does not makes a lot of sense
@@ -50,8 +57,6 @@ const char *email = "devel@monitoring-plugins.org";
50#include "curl/curl.h" 57#include "curl/curl.h"
51#include "curl/easy.h" 58#include "curl/easy.h"
52 59
53#include "picohttpparser.h"
54
55#include "uriparser/Uri.h" 60#include "uriparser/Uri.h"
56 61
57#include <arpa/inet.h> 62#include <arpa/inet.h>
@@ -63,207 +68,58 @@ const char *email = "devel@monitoring-plugins.org";
63 68
64#include <netdb.h> 69#include <netdb.h>
65 70
66#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major)*0x10000 + (minor)*0x100 + (patch))
67
68#define DEFAULT_BUFFER_SIZE 2048
69#define DEFAULT_SERVER_URL "/"
70#define HTTP_EXPECT "HTTP/"
71#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN
72enum { 71enum {
73 MAX_IPV4_HOSTLENGTH = 255, 72 REGS = 2,
74 HTTP_PORT = 80,
75 HTTPS_PORT = 443,
76 MAX_PORT = 65535,
77 DEFAULT_MAX_REDIRS = 15
78}; 73};
79 74
80enum { 75#include "regex.h"
81 STICKY_NONE = 0,
82 STICKY_HOST = 1,
83 STICKY_PORT = 2
84};
85 76
86enum { 77// Globals
87 FOLLOW_HTTP_CURL = 0, 78int verbose = 0;
88 FOLLOW_LIBCURL = 1
89};
90 79
91/* for buffers for header and body */ 80extern char errbuf[MAX_INPUT_BUFFER];
92typedef struct { 81extern bool is_openssl_callback;
93 char *buf; 82extern bool add_sslctx_verify_fun;
94 size_t buflen; 83
95 size_t bufsize; 84#if defined(HAVE_SSL) && defined(USE_OPENSSL)
96} curlhelp_write_curlbuf; 85static X509 *cert = NULL;
86#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
97 87
98/* for buffering the data sent in PUT */
99typedef struct { 88typedef struct {
100 char *buf; 89 int errorcode;
101 size_t buflen; 90 check_curl_config config;
102 off_t pos; 91} check_curl_config_wrapper;
103} curlhelp_read_curlbuf; 92static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
93
94static mp_subcheck check_http(check_curl_config /*config*/, check_curl_working_state workingState,
95 long redir_depth);
104 96
105/* for parsing the HTTP status line */
106typedef struct { 97typedef struct {
107 int http_major; /* major version of the protocol, always 1 (HTTP/0.9 98 long redir_depth;
108 * never reached the big internet most likely) */ 99 check_curl_working_state working_state;
109 int http_minor; /* minor version of the protocol, usually 0 or 1 */ 100 int error_code;
110 int http_code; /* HTTP return code as in RFC 2145 */ 101 check_curl_global_state curl_state;
111 int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see 102} redir_wrapper;
112 * http://support.microsoft.com/kb/318380/en-us */ 103static redir_wrapper redir(curlhelp_write_curlbuf * /*header_buf*/, check_curl_config /*config*/,
113 const char *msg; /* the human readable message */ 104 long redir_depth, check_curl_working_state working_state);
114 char *first_line; /* a copy of the first line */
115} curlhelp_statusline;
116
117/* to know the underlying SSL library used by libcurl */
118typedef enum curlhelp_ssl_library {
119 CURLHELP_SSL_LIBRARY_UNKNOWN,
120 CURLHELP_SSL_LIBRARY_OPENSSL,
121 CURLHELP_SSL_LIBRARY_LIBRESSL,
122 CURLHELP_SSL_LIBRARY_GNUTLS,
123 CURLHELP_SSL_LIBRARY_NSS
124} curlhelp_ssl_library;
125 105
126enum {
127 REGS = 2,
128 MAX_RE_SIZE = 1024
129};
130#include "regex.h"
131static regex_t preg;
132static regmatch_t pmatch[REGS];
133static char regexp[MAX_RE_SIZE];
134static int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
135static int errcode;
136static bool invert_regex = false;
137static int state_regex = STATE_CRITICAL;
138
139static char *server_address = NULL;
140static char *host_name = NULL;
141static char *server_url = 0;
142static struct curl_slist *server_ips = NULL;
143static bool specify_port = false;
144static unsigned short server_port = HTTP_PORT;
145static unsigned short virtual_port = 0;
146static int host_name_length;
147static char output_header_search[30] = "";
148static char output_string_search[30] = "";
149static char *warning_thresholds = NULL;
150static char *critical_thresholds = NULL;
151static int days_till_exp_warn, days_till_exp_crit;
152static thresholds *thlds;
153static char user_agent[DEFAULT_BUFFER_SIZE];
154static int verbose = 0;
155static bool show_extended_perfdata = false;
156static bool show_body = false;
157static int min_page_len = 0;
158static int max_page_len = 0;
159static int redir_depth = 0;
160static int max_depth = DEFAULT_MAX_REDIRS;
161static char *http_method = NULL;
162static char *http_post_data = NULL;
163static char *http_content_type = NULL;
164static CURL *curl;
165static bool curl_global_initialized = false;
166static bool curl_easy_initialized = false;
167static struct curl_slist *header_list = NULL;
168static bool body_buf_initialized = false;
169static curlhelp_write_curlbuf body_buf;
170static bool header_buf_initialized = false;
171static curlhelp_write_curlbuf header_buf;
172static bool status_line_initialized = false;
173static curlhelp_statusline status_line;
174static bool put_buf_initialized = false;
175static curlhelp_read_curlbuf put_buf;
176static char http_header[DEFAULT_BUFFER_SIZE];
177static long code;
178static long socket_timeout = DEFAULT_SOCKET_TIMEOUT;
179static double total_time;
180static double time_connect;
181static double time_appconnect;
182static double time_headers;
183static double time_firstbyte;
184static char errbuf[MAX_INPUT_BUFFER];
185static CURLcode res;
186static char url[DEFAULT_BUFFER_SIZE];
187static char msg[DEFAULT_BUFFER_SIZE];
188static char perfstring[DEFAULT_BUFFER_SIZE];
189static char header_expect[MAX_INPUT_BUFFER] = "";
190static char string_expect[MAX_INPUT_BUFFER] = "";
191static char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
192static int server_expect_yn = 0;
193static char user_auth[MAX_INPUT_BUFFER] = "";
194static char proxy_auth[MAX_INPUT_BUFFER] = "";
195static char **http_opt_headers;
196static int http_opt_headers_count = 0;
197static bool display_html = false;
198static int onredirect = STATE_OK;
199static int followmethod = FOLLOW_HTTP_CURL;
200static int followsticky = STICKY_NONE;
201static bool use_ssl = false;
202static bool check_cert = false;
203static bool continue_after_check_cert = false;
204typedef union {
205 struct curl_slist *to_info;
206 struct curl_certinfo *to_certinfo;
207} cert_ptr_union;
208static cert_ptr_union cert_ptr;
209static int ssl_version = CURL_SSLVERSION_DEFAULT;
210static char *client_cert = NULL;
211static char *client_privkey = NULL;
212static char *ca_cert = NULL;
213static bool verify_peer_and_host = false;
214static bool is_openssl_callback = false;
215static bool add_sslctx_verify_fun = false;
216#if defined(HAVE_SSL) && defined(USE_OPENSSL)
217static X509 *cert = NULL;
218#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
219static bool no_body = false;
220static int maximum_age = -1;
221static int address_family = AF_UNSPEC;
222static curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
223static int curl_http_version = CURL_HTTP_VERSION_NONE;
224static bool automatic_decompression = false;
225static char *cookie_jar_file = NULL;
226static bool haproxy_protocol = false;
227
228static bool process_arguments(int /*argc*/, char ** /*argv*/);
229static void handle_curl_option_return_code(CURLcode res, const char *option);
230static int check_http(void);
231static void redir(curlhelp_write_curlbuf * /*header_buf*/);
232static char *perfd_time(double elapsed_time);
233static char *perfd_time_connect(double elapsed_time_connect);
234static char *perfd_time_ssl(double elapsed_time_ssl);
235static char *perfd_time_firstbyte(double elapsed_time_firstbyte);
236static char *perfd_time_headers(double elapsed_time_headers);
237static char *perfd_time_transfer(double elapsed_time_transfer);
238static char *perfd_size(int page_len);
239static void print_help(void); 106static void print_help(void);
240void print_usage(void); 107void print_usage(void);
108
241static void print_curl_version(void); 109static void print_curl_version(void);
242static int curlhelp_initwritebuffer(curlhelp_write_curlbuf * /*buf*/); 110
243static size_t curlhelp_buffer_write_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/, void * /*stream*/); 111// typedef struct {
244static void curlhelp_freewritebuffer(curlhelp_write_curlbuf * /*buf*/); 112// int errorcode;
245static int curlhelp_initreadbuffer(curlhelp_read_curlbuf * /*buf*/, const char * /*data*/, size_t /*datalen*/); 113// } check_curl_evaluation_wrapper;
246static size_t curlhelp_buffer_read_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/, void * /*stream*/); 114// check_curl_evaluation_wrapper check_curl_evaluate(check_curl_config config,
247static void curlhelp_freereadbuffer(curlhelp_read_curlbuf * /*buf*/); 115// mp_check overall[static 1]) {}
248static curlhelp_ssl_library curlhelp_get_ssl_library(void);
249static const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library /*ssl_library*/);
250int net_noopenssl_check_certificate(cert_ptr_union *, int, int);
251
252static int curlhelp_parse_statusline(const char * /*buf*/, curlhelp_statusline * /*status_line*/);
253static void curlhelp_free_statusline(curlhelp_statusline * /*status_line*/);
254static char *get_header_value(const struct phr_header *headers, size_t nof_headers, const char *header);
255static int check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/, char (*msg)[DEFAULT_BUFFER_SIZE]);
256static int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_write_curlbuf *body_buf);
257 116
258#if defined(HAVE_SSL) && defined(USE_OPENSSL) 117#if defined(HAVE_SSL) && defined(USE_OPENSSL)
259int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit); 118mp_state_enum np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn,
119 int days_till_exp_crit);
260#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */ 120#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
261 121
262static void test_file(char * /*path*/);
263
264int main(int argc, char **argv) { 122int main(int argc, char **argv) {
265 int result = STATE_UNKNOWN;
266
267 setlocale(LC_ALL, ""); 123 setlocale(LC_ALL, "");
268 bindtextdomain(PACKAGE, LOCALEDIR); 124 bindtextdomain(PACKAGE, LOCALEDIR);
269 textdomain(PACKAGE); 125 textdomain(PACKAGE);
@@ -271,24 +127,30 @@ int main(int argc, char **argv) {
271 /* Parse extra opts if any */ 127 /* Parse extra opts if any */
272 argv = np_extra_opts(&argc, argv, progname); 128 argv = np_extra_opts(&argc, argv, progname);
273 129
274 /* set defaults */
275 snprintf(user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)", progname, NP_VERSION, VERSION, curl_version());
276
277 /* parse arguments */ 130 /* parse arguments */
278 if (process_arguments(argc, argv) == false) 131 check_curl_config_wrapper tmp_config = process_arguments(argc, argv);
132 if (tmp_config.errorcode == ERROR) {
279 usage4(_("Could not parse arguments")); 133 usage4(_("Could not parse arguments"));
134 }
280 135
281 if (display_html) 136 const check_curl_config config = tmp_config.config;
282 printf("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", use_ssl ? "https" : "http", host_name ? host_name : server_address,
283 virtual_port ? virtual_port : server_port, server_url);
284 137
285 result = check_http(); 138 if (config.output_format_is_set) {
286 return result; 139 mp_set_format(config.output_format);
140 }
141
142 check_curl_working_state working_state = config.initial_config;
143
144 mp_check overall = mp_check_init();
145 mp_subcheck sc_test = check_http(config, working_state, 0);
146
147 mp_add_subcheck_to_check(&overall, sc_test);
148
149 mp_exit(overall);
287} 150}
288 151
289#ifdef HAVE_SSL 152#ifdef HAVE_SSL
290# ifdef USE_OPENSSL 153# ifdef USE_OPENSSL
291
292int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) { 154int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) {
293 (void)preverify_ok; 155 (void)preverify_ok;
294 /* TODO: we get all certificates of the chain, so which ones 156 /* TODO: we get all certificates of the chain, so which ones
@@ -301,19 +163,21 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) {
301# endif 163# endif
302 if (verbose >= 2) { 164 if (verbose >= 2) {
303 puts("* SSL verify callback with certificate:"); 165 puts("* SSL verify callback with certificate:");
304 X509_NAME *subject;
305 X509_NAME *issuer;
306 printf("* issuer:\n"); 166 printf("* issuer:\n");
307 issuer = X509_get_issuer_name(cert); 167 X509_NAME *issuer = X509_get_issuer_name(cert);
308 X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE); 168 X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE);
309 printf("* curl verify_callback:\n* subject:\n"); 169 printf("* curl verify_callback:\n* subject:\n");
310 subject = X509_get_subject_name(cert); 170 X509_NAME *subject = X509_get_subject_name(cert);
311 X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE); 171 X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE);
312 puts(""); 172 puts("");
313 } 173 }
314 return 1; 174 return 1;
315} 175}
176# endif /* USE_OPENSSL */
177#endif /* HAVE_SSL */
316 178
179#ifdef HAVE_SSL
180# ifdef USE_OPENSSL
317CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) { 181CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) {
318 (void)curl; // ignore unused parameter 182 (void)curl; // ignore unused parameter
319 (void)parm; // ignore unused parameter 183 (void)parm; // ignore unused parameter
@@ -330,877 +194,508 @@ CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) {
330 194
331 return CURLE_OK; 195 return CURLE_OK;
332} 196}
333
334# endif /* USE_OPENSSL */ 197# endif /* USE_OPENSSL */
335#endif /* HAVE_SSL */ 198#endif /* HAVE_SSL */
336 199
337/* returns a string "HTTP/1.x" or "HTTP/2" */ 200mp_subcheck check_http(const check_curl_config config, check_curl_working_state workingState,
338static char *string_statuscode(int major, int minor) { 201 long redir_depth) {
339 static char buf[10];
340
341 switch (major) {
342 case 1:
343 snprintf(buf, sizeof(buf), "HTTP/%d.%d", major, minor);
344 break;
345 case 2:
346 case 3:
347 snprintf(buf, sizeof(buf), "HTTP/%d", major);
348 break;
349 default:
350 /* assuming here HTTP/N with N>=4 */
351 snprintf(buf, sizeof(buf), "HTTP/%d", major);
352 break;
353 }
354
355 return buf;
356}
357
358/* Checks if the server 'reply' is one of the expected 'statuscodes' */
359static int expected_statuscode(const char *reply, const char *statuscodes) {
360 char *expected;
361 char *code;
362 int result = 0;
363
364 if ((expected = strdup(statuscodes)) == NULL)
365 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
366
367 for (code = strtok(expected, ","); code != NULL; code = strtok(NULL, ","))
368 if (strstr(reply, code) != NULL) {
369 result = 1;
370 break;
371 }
372
373 free(expected);
374 return result;
375}
376 202
377void handle_curl_option_return_code(CURLcode res, const char *option) { 203 // =======================
378 if (res != CURLE_OK) { 204 // Initialisation for curl
379 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Error while setting cURL option '%s': cURL returned %d - %s"), option, res, 205 // =======================
380 curl_easy_strerror(res)); 206 check_curl_configure_curl_wrapper conf_curl_struct = check_curl_configure_curl(
381 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 207 config.curl_config, workingState, config.check_cert, config.on_redirect_dependent,
382 } 208 config.followmethod, config.max_depth);
383}
384 209
385int lookup_host(const char *host, char *buf, size_t buflen) { 210 check_curl_global_state curl_state = conf_curl_struct.curl_state;
386 struct addrinfo hints, *res, *result; 211 workingState = conf_curl_struct.working_state;
387 char addrstr[100];
388 size_t addrstr_len;
389 int errcode;
390 void *ptr = {0};
391 size_t buflen_remaining = buflen - 1;
392
393 memset(&hints, 0, sizeof(hints));
394 hints.ai_family = address_family;
395 hints.ai_socktype = SOCK_STREAM;
396 hints.ai_flags |= AI_CANONNAME;
397
398 errcode = getaddrinfo(host, NULL, &hints, &result);
399 if (errcode != 0)
400 return errcode;
401
402 strcpy(buf, "");
403 res = result;
404
405 while (res) {
406 switch (res->ai_family) {
407 case AF_INET:
408 ptr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
409 break;
410 case AF_INET6:
411 ptr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
412 break;
413 }
414 212
415 inet_ntop(res->ai_family, ptr, addrstr, 100); 213 mp_subcheck sc_result = mp_subcheck_init();
416 if (verbose >= 1) {
417 printf("* getaddrinfo IPv%d address: %s\n", res->ai_family == PF_INET6 ? 6 : 4, addrstr);
418 }
419 214
420 // Append all IPs to buf as a comma-separated string 215 char *url = fmt_url(workingState);
421 addrstr_len = strlen(addrstr); 216 xasprintf(&sc_result.output, "Testing %s", url);
422 if (buflen_remaining > addrstr_len + 1) { 217 // TODO add some output here URL or something
423 if (buf[0] != '\0') { 218 free(url);
424 strncat(buf, ",", buflen_remaining);
425 buflen_remaining -= 1;
426 }
427 strncat(buf, addrstr, buflen_remaining);
428 buflen_remaining -= addrstr_len;
429 }
430
431 res = res->ai_next;
432 }
433 219
434 freeaddrinfo(result); 220 // ==============
435 221 // do the request
436 return 0; 222 // ==============
437} 223 CURLcode res = curl_easy_perform(curl_state.curl);
438
439static void cleanup(void) {
440 if (status_line_initialized)
441 curlhelp_free_statusline(&status_line);
442 status_line_initialized = false;
443 if (curl_easy_initialized)
444 curl_easy_cleanup(curl);
445 curl_easy_initialized = false;
446 if (curl_global_initialized)
447 curl_global_cleanup();
448 curl_global_initialized = false;
449 if (body_buf_initialized)
450 curlhelp_freewritebuffer(&body_buf);
451 body_buf_initialized = false;
452 if (header_buf_initialized)
453 curlhelp_freewritebuffer(&header_buf);
454 header_buf_initialized = false;
455 if (put_buf_initialized)
456 curlhelp_freereadbuffer(&put_buf);
457 put_buf_initialized = false;
458}
459 224
460int check_http(void) { 225 if (verbose >= 2 && workingState.http_post_data) {
461 int result = STATE_OK; 226 printf("**** REQUEST CONTENT ****\n%s\n", workingState.http_post_data);
462 int result_ssl = STATE_OK;
463 int page_len = 0;
464 int i;
465 char *force_host_header = NULL;
466 struct curl_slist *host = NULL;
467 char addrstr[DEFAULT_BUFFER_SIZE / 2];
468 char dnscache[DEFAULT_BUFFER_SIZE];
469
470 /* initialize curl */
471 if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK)
472 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n");
473 curl_global_initialized = true;
474
475 if ((curl = curl_easy_init()) == NULL) {
476 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n");
477 } 227 }
478 curl_easy_initialized = true;
479 228
480 /* register cleanup function to shut down libcurl properly */ 229 mp_subcheck sc_curl = mp_subcheck_init();
481 atexit(cleanup);
482 230
483 if (verbose >= 1) 231 /* Curl errors, result in critical Nagios state */
484 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1), "CURLOPT_VERBOSE"); 232 if (res != CURLE_OK) {
485 233 xasprintf(&sc_curl.output, _("Error while performing connection: cURL returned %d - %s"),
486 /* print everything on stdout like check_http would do */ 234 res, errbuf[0] ? errbuf : curl_easy_strerror(res));
487 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR"); 235 sc_curl = mp_set_subcheck_state(sc_curl, STATE_CRITICAL);
488 236 mp_add_subcheck_to_subcheck(&sc_result, sc_curl);
489 if (automatic_decompression) 237 return sc_result;
490#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6)
491 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""), "CURLOPT_ACCEPT_ENCODING");
492#else
493 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING");
494#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */
495
496 /* initialize buffer for body of the answer */
497 if (curlhelp_initwritebuffer(&body_buf) < 0)
498 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
499 body_buf_initialized = true;
500 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback),
501 "CURLOPT_WRITEFUNCTION");
502 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body_buf), "CURLOPT_WRITEDATA");
503
504 /* initialize buffer for header of the answer */
505 if (curlhelp_initwritebuffer(&header_buf) < 0)
506 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n");
507 header_buf_initialized = true;
508 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback),
509 "CURLOPT_HEADERFUNCTION");
510 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *)&header_buf), "CURLOPT_WRITEHEADER");
511
512 /* set the error buffer */
513 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf), "CURLOPT_ERRORBUFFER");
514
515 /* set timeouts */
516 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, socket_timeout), "CURLOPT_CONNECTTIMEOUT");
517 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_TIMEOUT, socket_timeout), "CURLOPT_TIMEOUT");
518
519 /* enable haproxy protocol */
520 if (haproxy_protocol) {
521 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L), "CURLOPT_HAPROXYPROTOCOL");
522 }
523
524 // fill dns resolve cache to make curl connect to the given server_address instead of the host_name, only required for ssl, because we
525 // use the host_name later on to make SNI happy
526 if (use_ssl && host_name != NULL) {
527 if ((res = lookup_host(server_address, addrstr, DEFAULT_BUFFER_SIZE / 2)) != 0) {
528 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), server_address, res,
529 gai_strerror(res));
530 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
531 }
532 snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr);
533 host = curl_slist_append(NULL, dnscache);
534 curl_easy_setopt(curl, CURLOPT_RESOLVE, host);
535 if (verbose >= 1)
536 printf("* curl CURLOPT_RESOLVE: %s\n", dnscache);
537 }
538
539 // If server_address is an IPv6 address it must be surround by square brackets
540 struct in6_addr tmp_in_addr;
541 if (inet_pton(AF_INET6, server_address, &tmp_in_addr) == 1) {
542 char *new_server_address = malloc(strlen(server_address) + 3);
543 if (new_server_address == NULL) {
544 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n");
545 }
546 snprintf(new_server_address, strlen(server_address) + 3, "[%s]", server_address);
547 free(server_address);
548 server_address = new_server_address;
549 }
550
551 /* compose URL: use the address we want to connect to, set Host: header later */
552 snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", use_ssl ? "https" : "http",
553 (use_ssl & (host_name != NULL)) ? host_name : server_address, server_port, server_url);
554
555 if (verbose >= 1)
556 printf("* curl CURLOPT_URL: %s\n", url);
557 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, url), "CURLOPT_URL");
558
559 /* extract proxy information for legacy proxy https requests */
560 if (!strcmp(http_method, "CONNECT") || strstr(server_url, "http") == server_url) {
561 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXY, server_address), "CURLOPT_PROXY");
562 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXYPORT, (long)server_port), "CURLOPT_PROXYPORT");
563 if (verbose >= 2)
564 printf("* curl CURLOPT_PROXY: %s:%d\n", server_address, server_port);
565 http_method = "GET";
566 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, server_url), "CURLOPT_URL");
567 }
568
569 /* disable body for HEAD request */
570 if (http_method && !strcmp(http_method, "HEAD")) {
571 no_body = true;
572 } 238 }
573 239
574 /* set HTTP protocol version */ 240 /* get status line of answer, check sanity of HTTP code */
575 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, curl_http_version), "CURLOPT_HTTP_VERSION"); 241 if (curlhelp_parse_statusline(curl_state.header_buf->buf, curl_state.status_line) < 0) {
576 242 sc_result = mp_set_subcheck_state(sc_result, STATE_CRITICAL);
577 /* set HTTP method */ 243 /* we cannot know the major/minor version here for sure as we cannot parse the first
578 if (http_method) { 244 * line */
579 if (!strcmp(http_method, "POST")) 245 xasprintf(&sc_result.output, "HTTP/x.x unknown - Unparsable status line");
580 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_POST, 1), "CURLOPT_POST"); 246 return sc_result;
581 else if (!strcmp(http_method, "PUT"))
582 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD");
583 else
584 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, http_method), "CURLOPT_CUSTOMREQUEST");
585 } 247 }
586 248
587 /* check if Host header is explicitly set in options */ 249 curl_state.status_line_initialized = true;
588 if (http_opt_headers_count) {
589 for (i = 0; i < http_opt_headers_count; i++) {
590 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) {
591 force_host_header = http_opt_headers[i];
592 }
593 }
594 }
595 250
596 /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in anyway */ 251 size_t page_len = get_content_length(curl_state.header_buf, curl_state.body_buf);
597 if (host_name != NULL && force_host_header == NULL) {
598 if ((virtual_port != HTTP_PORT && !use_ssl) || (virtual_port != HTTPS_PORT && use_ssl)) {
599 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", host_name, virtual_port);
600 } else {
601 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name);
602 }
603 header_list = curl_slist_append(header_list, http_header);
604 }
605 252
606 /* always close connection, be nice to servers */ 253 double total_time;
607 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Connection: close"); 254 handle_curl_option_return_code(
608 header_list = curl_slist_append(header_list, http_header); 255 curl_easy_getinfo(curl_state.curl, CURLINFO_TOTAL_TIME, &total_time),
256 "CURLINFO_TOTAL_TIME");
609 257
610 /* attach additional headers supplied by the user */ 258 xasprintf(
611 /* optionally send any other header tag */ 259 &sc_curl.output, "%s %d %s - %ld bytes in %.3f second response time",
612 if (http_opt_headers_count) { 260 string_statuscode(curl_state.status_line->http_major, curl_state.status_line->http_minor),
613 for (i = 0; i < http_opt_headers_count; i++) { 261 curl_state.status_line->http_code, curl_state.status_line->msg, page_len, total_time);
614 header_list = curl_slist_append(header_list, http_opt_headers[i]); 262 sc_curl = mp_set_subcheck_state(sc_curl, STATE_OK);
615 } 263 mp_add_subcheck_to_subcheck(&sc_result, sc_curl);
616 /* This cannot be free'd here because a redirection will then try to access this and segfault */
617 /* Covered in a testcase in tests/check_http.t */
618 /* free(http_opt_headers); */
619 }
620 264
621 /* set HTTP headers */ 265 // ==========
622 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list), "CURLOPT_HTTPHEADER"); 266 // Evaluation
267 // ==========
623 268
624#ifdef LIBCURL_FEATURE_SSL 269#ifdef LIBCURL_FEATURE_SSL
270 if (workingState.use_ssl && config.check_cert) {
271 mp_subcheck sc_certificate = check_curl_certificate_checks(
272 curl_state.curl, cert, config.days_till_exp_warn, config.days_till_exp_crit);
625 273
626 /* set SSL version, warn about insecure or unsupported versions */ 274 mp_add_subcheck_to_subcheck(&sc_result, sc_certificate);
627 if (use_ssl) { 275 if (!config.continue_after_check_cert) {
628 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION"); 276 return sc_result;
629 }
630
631 /* client certificate and key to present to server (SSL) */
632 if (client_cert)
633 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert), "CURLOPT_SSLCERT");
634 if (client_privkey)
635 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLKEY, client_privkey), "CURLOPT_SSLKEY");
636 if (ca_cert) {
637 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO");
638 }
639 if (ca_cert || verify_peer_and_host) {
640 /* per default if we have a CA verify both the peer and the
641 * hostname in the certificate, can be switched off later */
642 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1), "CURLOPT_SSL_VERIFYPEER");
643 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2), "CURLOPT_SSL_VERIFYHOST");
644 } else {
645 /* backward-compatible behaviour, be tolerant in checks
646 * TODO: depending on more options have aspects we want
647 * to be less tolerant about ssl verfications
648 */
649 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER");
650 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST");
651 }
652
653 /* detect SSL library used by libcurl */
654 ssl_library = curlhelp_get_ssl_library();
655
656 /* try hard to get a stack of certificates to verify against */
657 if (check_cert) {
658# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1)
659 /* inform curl to report back certificates */
660 switch (ssl_library) {
661 case CURLHELP_SSL_LIBRARY_OPENSSL:
662 case CURLHELP_SSL_LIBRARY_LIBRESSL:
663 /* set callback to extract certificate with OpenSSL context function (works with
664 * OpenSSL-style libraries only!) */
665# ifdef USE_OPENSSL
666 /* libcurl and monitoring plugins built with OpenSSL, good */
667 add_sslctx_verify_fun = true;
668 is_openssl_callback = true;
669# endif /* USE_OPENSSL */
670 /* libcurl is built with OpenSSL, monitoring plugins, so falling
671 * back to manually extracting certificate information */
672 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
673 break;
674
675 case CURLHELP_SSL_LIBRARY_NSS:
676# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
677 /* NSS: support for CERTINFO is implemented since 7.34.0 */
678 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
679# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
680 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n",
681 curlhelp_get_ssl_library_string(ssl_library));
682# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
683 break;
684
685 case CURLHELP_SSL_LIBRARY_GNUTLS:
686# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0)
687 /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */
688 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
689# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
690 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n",
691 curlhelp_get_ssl_library_string(ssl_library));
692# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
693 break;
694
695 case CURLHELP_SSL_LIBRARY_UNKNOWN:
696 default:
697 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (unknown SSL library '%s', must implement first)\n",
698 curlhelp_get_ssl_library_string(ssl_library));
699 break;
700 } 277 }
701# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
702 /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */
703 if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL || ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL)
704 add_sslctx_verify_fun = true;
705 else
706 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library or libcurl "
707 "too old and has no CURLOPT_CERTINFO)\n");
708# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
709 } 278 }
710
711# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 10, 6) /* required for CURLOPT_SSL_CTX_FUNCTION */
712 // ssl ctx function is not available with all ssl backends
713 if (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, NULL) != CURLE_UNKNOWN_OPTION)
714 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION");
715# endif
716
717#endif /* LIBCURL_FEATURE_SSL */
718
719 /* set default or user-given user agent identification */
720 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT");
721
722 /* proxy-authentication */
723 if (strcmp(proxy_auth, ""))
724 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_auth), "CURLOPT_PROXYUSERPWD");
725
726 /* authentication */
727 if (strcmp(user_auth, ""))
728 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERPWD, user_auth), "CURLOPT_USERPWD");
729
730 /* TODO: parameter auth method, bitfield of following methods:
731 * CURLAUTH_BASIC (default)
732 * CURLAUTH_DIGEST
733 * CURLAUTH_DIGEST_IE
734 * CURLAUTH_NEGOTIATE
735 * CURLAUTH_NTLM
736 * CURLAUTH_NTLM_WB
737 *
738 * convenience tokens for typical sets of methods:
739 * CURLAUTH_ANYSAFE: most secure, without BASIC
740 * or CURLAUTH_ANY: most secure, even BASIC if necessary
741 *
742 * handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST ), "CURLOPT_HTTPAUTH");
743 */
744
745 /* handle redirections */
746 if (onredirect == STATE_DEPENDENT) {
747 if (followmethod == FOLLOW_LIBCURL) {
748 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1), "CURLOPT_FOLLOWLOCATION");
749
750 /* default -1 is infinite, not good, could lead to zombie plugins!
751 Setting it to one bigger than maximal limit to handle errors nicely below
752 */
753 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_MAXREDIRS, max_depth + 1), "CURLOPT_MAXREDIRS");
754
755 /* for now allow only http and https (we are a http(s) check plugin in the end) */
756#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0)
757 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"),
758 "CURLOPT_REDIR_PROTOCOLS_STR");
759#elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4)
760 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS),
761 "CURLOPT_REDIRECT_PROTOCOLS");
762#endif 279#endif
763 280
764 /* TODO: handle the following aspects of redirection, make them 281 /* we got the data and we executed the request in a given time, so we can append
765 * command line options too later: 282 * performance data to the answer always
766 CURLOPT_POSTREDIR: method switch 283 */
767 CURLINFO_REDIRECT_URL: custom redirect option
768 CURLOPT_REDIRECT_PROTOCOLS: allow people to step outside safe protocols
769 CURLINFO_REDIRECT_COUNT: get the number of redirects, print it, maybe a range option here is nice like for expected page size?
770 */
771 } else {
772 /* old style redirection is handled below */
773 }
774 }
775
776 /* no-body */
777 if (no_body)
778 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_NOBODY, 1), "CURLOPT_NOBODY");
779
780 /* IPv4 or IPv6 forced DNS resolution */
781 if (address_family == AF_UNSPEC)
782 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER),
783 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)");
784 else if (address_family == AF_INET)
785 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4),
786 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)");
787#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
788 else if (address_family == AF_INET6)
789 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6),
790 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)");
791#endif
792 284
793 /* either send http POST data (any data, not only POST)*/ 285 // total time the query took
794 if (!strcmp(http_method, "POST") || !strcmp(http_method, "PUT")) { 286 mp_perfdata pd_total_time = perfdata_init();
795 /* set content of payload for POST and PUT */ 287 mp_perfdata_value pd_val_total_time = mp_create_pd_value(total_time);
796 if (http_content_type) { 288 pd_total_time.value = pd_val_total_time;
797 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", http_content_type); 289 pd_total_time = mp_pd_set_thresholds(pd_total_time, config.thlds);
798 header_list = curl_slist_append(header_list, http_header); 290 pd_total_time.label = "time";
799 } 291 pd_total_time.uom = "s";
800 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string 292
801 * in case of no POST/PUT data */ 293 mp_subcheck sc_total_time = mp_subcheck_init();
802 if (!http_post_data) 294 sc_total_time = mp_set_subcheck_state(sc_total_time, mp_get_pd_status(pd_total_time));
803 http_post_data = ""; 295 xasprintf(&sc_total_time.output, "Total connection time: %fs", total_time);
804 if (!strcmp(http_method, "POST")) { 296 mp_add_perfdata_to_subcheck(&sc_total_time, pd_total_time);
805 /* POST method, set payload with CURLOPT_POSTFIELDS */ 297
806 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_POSTFIELDS, http_post_data), "CURLOPT_POSTFIELDS"); 298 mp_add_subcheck_to_subcheck(&sc_result, sc_total_time);
807 } else if (!strcmp(http_method, "PUT")) { 299
808 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback), 300 if (config.show_extended_perfdata) {
809 "CURLOPT_READFUNCTION"); 301 // overall connection time
810 if (curlhelp_initreadbuffer(&put_buf, http_post_data, strlen(http_post_data)) < 0) 302 mp_perfdata pd_time_connect = perfdata_init();
811 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating read buffer for PUT\n"); 303 double time_connect;
812 put_buf_initialized = true; 304 handle_curl_option_return_code(
813 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA"); 305 curl_easy_getinfo(curl_state.curl, CURLINFO_CONNECT_TIME, &time_connect),
814 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_INFILESIZE, (curl_off_t)strlen(http_post_data)), 306 "CURLINFO_CONNECT_TIME");
815 "CURLOPT_INFILESIZE"); 307
308 mp_perfdata_value pd_val_time_connect = mp_create_pd_value(time_connect);
309 pd_time_connect.value = pd_val_time_connect;
310 pd_time_connect.label = "time_connect";
311 pd_time_connect.uom = "s";
312 pd_time_connect = mp_set_pd_max_value(
313 pd_time_connect, mp_create_pd_value(config.curl_config.socket_timeout));
314
315 pd_time_connect = mp_pd_set_thresholds(pd_time_connect, config.thlds);
316 mp_add_perfdata_to_subcheck(&sc_result, pd_time_connect);
317
318 // application connection time, used to compute other timings
319 double time_appconnect;
320 handle_curl_option_return_code(
321 curl_easy_getinfo(curl_state.curl, CURLINFO_APPCONNECT_TIME, &time_appconnect),
322 "CURLINFO_APPCONNECT_TIME");
323
324 if (workingState.use_ssl) {
325 mp_perfdata pd_time_tls = perfdata_init();
326 {
327 mp_perfdata_value pd_val_time_tls =
328 mp_create_pd_value(time_appconnect - time_connect);
329
330 pd_time_tls.value = pd_val_time_tls;
331 }
332 pd_time_tls.label = "time_tls";
333 pd_time_tls.uom = "s";
334 mp_add_perfdata_to_subcheck(&sc_result, pd_time_tls);
816 } 335 }
817 }
818 336
819 /* cookie handling */ 337 mp_perfdata pd_time_headers = perfdata_init();
820 if (cookie_jar_file != NULL) { 338 {
821 /* enable reading cookies from a file, and if the filename is an empty string, only enable the curl cookie engine */ 339 double time_headers;
822 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookie_jar_file), "CURLOPT_COOKIEFILE"); 340 handle_curl_option_return_code(
823 /* now enable saving cookies to a file, but only if the filename is not an empty string, since writing it would fail */ 341 curl_easy_getinfo(curl_state.curl, CURLINFO_PRETRANSFER_TIME, &time_headers),
824 if (*cookie_jar_file) 342 "CURLINFO_PRETRANSFER_TIME");
825 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookie_jar_file), "CURLOPT_COOKIEJAR");
826 }
827
828 /* do the request */
829 res = curl_easy_perform(curl);
830
831 if (verbose >= 2 && http_post_data)
832 printf("**** REQUEST CONTENT ****\n%s\n", http_post_data);
833 343
834 /* free header and server IP resolve lists, we don't need it anymore */ 344 mp_perfdata_value pd_val_time_headers =
835 curl_slist_free_all(header_list); 345 mp_create_pd_value(time_headers - time_appconnect);
836 header_list = NULL;
837 curl_slist_free_all(server_ips);
838 server_ips = NULL;
839 if (host) {
840 curl_slist_free_all(host);
841 host = NULL;
842 }
843 346
844 /* Curl errors, result in critical Nagios state */ 347 pd_time_headers.value = pd_val_time_headers;
845 if (res != CURLE_OK) { 348 }
846 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"), server_port, 349 pd_time_headers.label = "time_headers";
847 res, errbuf[0] ? errbuf : curl_easy_strerror(res)); 350 pd_time_headers.uom = "s";
848 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 351 mp_add_perfdata_to_subcheck(&sc_result, pd_time_headers);
849 }
850 352
851 /* certificate checks */ 353 mp_perfdata pd_time_firstbyte = perfdata_init();
852#ifdef LIBCURL_FEATURE_SSL 354 double time_firstbyte;
853 if (use_ssl) { 355 handle_curl_option_return_code(
854 if (check_cert) { 356 curl_easy_getinfo(curl_state.curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte),
855 if (is_openssl_callback) { 357 "CURLINFO_STARTTRANSFER_TIME");
856# ifdef USE_OPENSSL
857 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
858 * and we actually have OpenSSL in the monitoring tools
859 */
860 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
861 if (!continue_after_check_cert) {
862 return result_ssl;
863 }
864# else /* USE_OPENSSL */
865 die(STATE_CRITICAL,
866 "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n");
867# endif /* USE_OPENSSL */
868 } else {
869 int i;
870 struct curl_slist *slist;
871 358
872 cert_ptr.to_info = NULL; 359 mp_perfdata_value pd_val_time_firstbyte = mp_create_pd_value(time_firstbyte);
873 res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &cert_ptr.to_info); 360 pd_time_firstbyte.value = pd_val_time_firstbyte;
874 if (!res && cert_ptr.to_info) { 361 pd_time_firstbyte.label = "time_firstbyte";
875# ifdef USE_OPENSSL 362 pd_time_firstbyte.uom = "s";
876 /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert parsing 363 mp_add_perfdata_to_subcheck(&sc_result, pd_time_firstbyte);
877 * We only check the first certificate and assume it's the one of the server
878 */
879 const char *raw_cert = NULL;
880 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) {
881 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) {
882 if (verbose >= 2)
883 printf("%d ** %s\n", i, slist->data);
884 if (strncmp(slist->data, "Cert:", 5) == 0) {
885 raw_cert = &slist->data[5];
886 goto GOT_FIRST_CERT;
887 }
888 }
889 }
890 GOT_FIRST_CERT:
891 if (!raw_cert) {
892 snprintf(msg, DEFAULT_BUFFER_SIZE,
893 _("Cannot retrieve certificates from CERTINFO information - certificate data was empty"));
894 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
895 }
896 BIO *cert_BIO = BIO_new(BIO_s_mem());
897 BIO_write(cert_BIO, raw_cert, strlen(raw_cert));
898 cert = PEM_read_bio_X509(cert_BIO, NULL, NULL, NULL);
899 if (!cert) {
900 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Cannot read certificate from CERTINFO information - BIO error"));
901 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
902 }
903 BIO_free(cert_BIO);
904 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
905 if (!continue_after_check_cert) {
906 return result_ssl;
907 }
908# else /* USE_OPENSSL */
909 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal,
910 * so we use the libcurl CURLINFO data
911 */
912 result_ssl = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit);
913 if (!continue_after_check_cert) {
914 return result_ssl;
915 }
916# endif /* USE_OPENSSL */
917 } else {
918 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Cannot retrieve certificates - cURL returned %d - %s"), res,
919 curl_easy_strerror(res));
920 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
921 }
922 }
923 }
924 }
925#endif /* LIBCURL_FEATURE_SSL */
926 364
927 /* we got the data and we executed the request in a given time, so we can append 365 mp_perfdata pd_time_transfer = perfdata_init();
928 * performance data to the answer always 366 pd_time_transfer.value = mp_create_pd_value(total_time - time_firstbyte);
929 */ 367 pd_time_transfer.label = "time_transfer";
930 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time), "CURLINFO_TOTAL_TIME"); 368 pd_time_transfer.uom = "s";
931 page_len = get_content_length(&header_buf, &body_buf); 369 mp_add_perfdata_to_subcheck(&sc_result, pd_time_transfer);
932 if (show_extended_perfdata) {
933 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &time_connect), "CURLINFO_CONNECT_TIME");
934 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), "CURLINFO_APPCONNECT_TIME");
935 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &time_headers), "CURLINFO_PRETRANSFER_TIME");
936 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte),
937 "CURLINFO_STARTTRANSFER_TIME");
938 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s", perfd_time(total_time), perfd_size(page_len),
939 perfd_time_connect(time_connect), use_ssl ? perfd_time_ssl(time_appconnect - time_connect) : "",
940 perfd_time_headers(time_headers - time_appconnect), perfd_time_firstbyte(time_firstbyte - time_headers),
941 perfd_time_transfer(total_time - time_firstbyte));
942 } else {
943 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s", perfd_time(total_time), perfd_size(page_len));
944 } 370 }
945 371
946 /* return a CRITICAL status if we couldn't read any data */ 372 /* return a CRITICAL status if we couldn't read any data */
947 if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0) 373 if (strlen(curl_state.header_buf->buf) == 0 && strlen(curl_state.body_buf->buf) == 0) {
948 die(STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n")); 374 sc_result = mp_set_subcheck_state(sc_result, STATE_CRITICAL);
949 375 xasprintf(&sc_result.output, "No header received from host");
950 /* get status line of answer, check sanity of HTTP code */ 376 return sc_result;
951 if (curlhelp_parse_statusline(header_buf.buf, &status_line) < 0) {
952 snprintf(msg, DEFAULT_BUFFER_SIZE, "Unparsable status line in %.3g seconds response time|%s\n", total_time, perfstring);
953 /* we cannot know the major/minor version here for sure as we cannot parse the first line */
954 die(STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", code, msg);
955 } 377 }
956 status_line_initialized = true;
957 378
958 /* get result code from cURL */ 379 /* get result code from cURL */
959 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code), "CURLINFO_RESPONSE_CODE"); 380 long httpReturnCode;
960 if (verbose >= 2) 381 handle_curl_option_return_code(
961 printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", code); 382 curl_easy_getinfo(curl_state.curl, CURLINFO_RESPONSE_CODE, &httpReturnCode),
383 "CURLINFO_RESPONSE_CODE");
384 if (verbose >= 2) {
385 printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", httpReturnCode);
386 }
962 387
963 /* print status line, header, body if verbose */ 388 /* print status line, header, body if verbose */
964 if (verbose >= 2) { 389 if (verbose >= 2) {
965 printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header_buf.buf, (no_body ? " [[ skipped ]]" : body_buf.buf)); 390 printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", curl_state.header_buf->buf,
391 (workingState.no_body ? " [[ skipped ]]" : curl_state.body_buf->buf));
966 } 392 }
967 393
968 /* make sure the status line matches the response we are looking for */ 394 /* make sure the status line matches the response we are looking for */
969 if (!expected_statuscode(status_line.first_line, server_expect)) { 395 mp_subcheck sc_expect = mp_subcheck_init();
970 if (server_port == HTTP_PORT) 396 sc_expect = mp_set_subcheck_default_state(sc_expect, STATE_OK);
971 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"), status_line.first_line); 397 if (!expected_statuscode(curl_state.status_line->first_line, config.server_expect.string)) {
972 else 398 if (workingState.serverPort == HTTP_PORT) {
973 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: %s\n"), server_port, 399 xasprintf(&sc_expect.output, _("Invalid HTTP response received from host: %s\n"),
974 status_line.first_line); 400 curl_state.status_line->first_line);
975 die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, show_body ? "\n" : "", show_body ? body_buf.buf : ""); 401 } else {
402 xasprintf(&sc_expect.output,
403 _("Invalid HTTP response received from host on port %d: %s\n"),
404 workingState.serverPort, curl_state.status_line->first_line);
405 }
406 sc_expect = mp_set_subcheck_default_state(sc_expect, STATE_CRITICAL);
407 } else {
408 xasprintf(&sc_expect.output, _("Status line output matched \"%s\""),
409 config.server_expect.string);
976 } 410 }
411 mp_add_subcheck_to_subcheck(&sc_result, sc_expect);
977 412
978 if (server_expect_yn) { 413 if (!config.server_expect.is_present) {
979 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), server_expect);
980 if (verbose)
981 printf("%s\n", msg);
982 result = STATE_OK;
983 } else {
984 /* illegal return codes result in a critical state */ 414 /* illegal return codes result in a critical state */
985 if (code >= 600 || code < 100) { 415 mp_subcheck sc_return_code = mp_subcheck_init();
986 die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), status_line.http_code, status_line.msg); 416 sc_return_code = mp_set_subcheck_default_state(sc_return_code, STATE_OK);
987 /* server errors result in a critical state */ 417 xasprintf(&sc_return_code.output, "HTTP return code: %d",
988 } else if (code >= 500) { 418 curl_state.status_line->http_code);
989 result = STATE_CRITICAL; 419
420 if (httpReturnCode >= 600 || httpReturnCode < 100) {
421 sc_return_code = mp_set_subcheck_state(sc_return_code, STATE_CRITICAL);
422 xasprintf(&sc_return_code.output, _("Invalid Status (%d, %.40s)"),
423 curl_state.status_line->http_code, curl_state.status_line->msg);
424 mp_add_subcheck_to_subcheck(&sc_result, sc_return_code);
425 return sc_result;
426 }
427
428 // server errors result in a critical state
429 if (httpReturnCode >= 500) {
430 sc_return_code = mp_set_subcheck_state(sc_return_code, STATE_CRITICAL);
990 /* client errors result in a warning state */ 431 /* client errors result in a warning state */
991 } else if (code >= 400) { 432 } else if (httpReturnCode >= 400) {
992 result = STATE_WARNING; 433 sc_return_code = mp_set_subcheck_state(sc_return_code, STATE_WARNING);
993 /* check redirected page if specified */ 434 /* check redirected page if specified */
994 } else if (code >= 300) { 435 } else if (httpReturnCode >= 300) {
995 if (onredirect == STATE_DEPENDENT) { 436 if (config.on_redirect_dependent) {
996 if (followmethod == FOLLOW_LIBCURL) { 437 if (config.followmethod == FOLLOW_LIBCURL) {
997 code = status_line.http_code; 438 httpReturnCode = curl_state.status_line->http_code;
439 handle_curl_option_return_code(
440 curl_easy_getinfo(curl_state.curl, CURLINFO_REDIRECT_COUNT, &redir_depth),
441 "CURLINFO_REDIRECT_COUNT");
442
443 if (verbose >= 2) {
444 printf(_("* curl LIBINFO_REDIRECT_COUNT is %ld\n"), redir_depth);
445 }
446
447 mp_subcheck sc_redir_depth = mp_subcheck_init();
448 if (redir_depth > config.max_depth) {
449 xasprintf(&sc_redir_depth.output,
450 "maximum redirection depth %ld exceeded in libcurl",
451 config.max_depth);
452 sc_redir_depth = mp_set_subcheck_state(sc_redir_depth, STATE_CRITICAL);
453 mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth);
454 return sc_result;
455 }
456 xasprintf(&sc_redir_depth.output, "redirection depth %ld (of a maximum %ld)",
457 redir_depth, config.max_depth);
458 mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth);
459
998 } else { 460 } else {
999 /* old check_http style redirection, if we come 461 /* old check_http style redirection, if we come
1000 * back here, we are in the same status as with 462 * back here, we are in the same status as with
1001 * the libcurl method 463 * the libcurl method
1002 */ 464 */
1003 redir(&header_buf); 465 redir_wrapper redir_result =
466 redir(curl_state.header_buf, config, redir_depth, workingState);
467 cleanup(curl_state);
468 mp_subcheck sc_redir =
469 check_http(config, redir_result.working_state, redir_result.redir_depth);
470 mp_add_subcheck_to_subcheck(&sc_result, sc_redir);
471
472 return sc_result;
1004 } 473 }
1005 } else { 474 } else {
1006 /* this is a specific code in the command line to 475 /* this is a specific code in the command line to
1007 * be returned when a redirection is encountered 476 * be returned when a redirection is encountered
1008 */ 477 */
478 sc_return_code =
479 mp_set_subcheck_state(sc_return_code, config.on_redirect_result_state);
1009 } 480 }
1010 result = max_state_alt(onredirect, result);
1011 /* all other codes are considered ok */
1012 } else { 481 } else {
1013 result = STATE_OK; 482 sc_return_code = mp_set_subcheck_state(sc_return_code, STATE_OK);
1014 } 483 }
1015 }
1016 484
1017 /* libcurl redirection internally, handle error states here */ 485 mp_add_subcheck_to_subcheck(&sc_result, sc_return_code);
1018 if (followmethod == FOLLOW_LIBCURL) {
1019 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &redir_depth), "CURLINFO_REDIRECT_COUNT");
1020 if (verbose >= 2)
1021 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth);
1022 if (redir_depth > max_depth) {
1023 snprintf(msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl", max_depth);
1024 die(STATE_WARNING, "HTTP WARNING - %s", msg);
1025 }
1026 } 486 }
1027 487
1028 /* check status codes, set exit status accordingly */ 488 /* check status codes, set exit status accordingly */
1029 if (status_line.http_code != code) { 489 if (curl_state.status_line->http_code != httpReturnCode) {
1030 die(STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"), 490 mp_subcheck sc_http_return_code_sanity = mp_subcheck_init();
1031 string_statuscode(status_line.http_major, status_line.http_minor), status_line.http_code, status_line.msg, code); 491 sc_http_return_code_sanity =
492 mp_set_subcheck_state(sc_http_return_code_sanity, STATE_CRITICAL);
493 xasprintf(&sc_http_return_code_sanity.output,
494 _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"),
495 string_statuscode(curl_state.status_line->http_major,
496 curl_state.status_line->http_minor),
497 curl_state.status_line->http_code, curl_state.status_line->msg, httpReturnCode);
498
499 mp_add_subcheck_to_subcheck(&sc_result, sc_http_return_code_sanity);
500 return sc_result;
1032 } 501 }
1033 502
1034 if (maximum_age >= 0) { 503 if (config.maximum_age >= 0) {
1035 result = max_state_alt(check_document_dates(&header_buf, &msg), result); 504 mp_subcheck sc_max_age = check_document_dates(curl_state.header_buf, config.maximum_age);
505 mp_add_subcheck_to_subcheck(&sc_result, sc_max_age);
1036 } 506 }
1037 507
1038 /* Page and Header content checks go here */ 508 /* Page and Header content checks go here */
509 if (strlen(config.header_expect)) {
510 mp_subcheck sc_header_expect = mp_subcheck_init();
511 sc_header_expect = mp_set_subcheck_default_state(sc_header_expect, STATE_OK);
512 xasprintf(&sc_header_expect.output, "Expect %s in header", config.header_expect);
1039 513
1040 if (strlen(header_expect)) { 514 if (!strstr(curl_state.header_buf->buf, config.header_expect)) {
1041 if (!strstr(header_buf.buf, header_expect)) { 515 char output_header_search[30] = "";
1042 516 strncpy(&output_header_search[0], config.header_expect, sizeof(output_header_search));
1043 strncpy(&output_header_search[0], header_expect, sizeof(output_header_search));
1044 517
1045 if (output_header_search[sizeof(output_header_search) - 1] != '\0') { 518 if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
1046 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4); 519 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4);
1047 } 520 }
1048 521
1049 char tmp[DEFAULT_BUFFER_SIZE]; 522 xasprintf(&sc_header_expect.output, _("header '%s' not found on '%s://%s:%d%s', "),
1050 523 output_header_search, workingState.use_ssl ? "https" : "http",
1051 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sheader '%s' not found on '%s://%s:%d%s', "), msg, output_header_search, 524 workingState.host_name ? workingState.host_name : workingState.server_address,
1052 use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url); 525 workingState.serverPort, workingState.server_url);
1053 526
1054 strcpy(msg, tmp); 527 sc_header_expect = mp_set_subcheck_state(sc_header_expect, STATE_CRITICAL);
1055
1056 result = STATE_CRITICAL;
1057 } 528 }
529
530 mp_add_subcheck_to_subcheck(&sc_result, sc_header_expect);
1058 } 531 }
1059 532
1060 if (strlen(string_expect)) { 533 if (strlen(config.string_expect)) {
1061 if (!strstr(body_buf.buf, string_expect)) { 534 mp_subcheck sc_string_expect = mp_subcheck_init();
535 sc_string_expect = mp_set_subcheck_default_state(sc_string_expect, STATE_OK);
536 xasprintf(&sc_string_expect.output, "Expect string \"%s\" in body", config.string_expect);
1062 537
1063 strncpy(&output_string_search[0], string_expect, sizeof(output_string_search)); 538 if (!strstr(curl_state.body_buf->buf, config.string_expect)) {
539 char output_string_search[30] = "";
540 strncpy(&output_string_search[0], config.string_expect, sizeof(output_string_search));
1064 541
1065 if (output_string_search[sizeof(output_string_search) - 1] != '\0') { 542 if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
1066 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4); 543 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4);
1067 } 544 }
1068 545
1069 char tmp[DEFAULT_BUFFER_SIZE]; 546 xasprintf(&sc_string_expect.output, _("string '%s' not found on '%s://%s:%d%s', "),
547 output_string_search, workingState.use_ssl ? "https" : "http",
548 workingState.host_name ? workingState.host_name : workingState.server_address,
549 workingState.serverPort, workingState.server_url);
1070 550
1071 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search, 551 sc_string_expect = mp_set_subcheck_state(sc_string_expect, STATE_CRITICAL);
1072 use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url);
1073
1074 strcpy(msg, tmp);
1075
1076 result = STATE_CRITICAL;
1077 } 552 }
553
554 mp_add_subcheck_to_subcheck(&sc_result, sc_string_expect);
1078 } 555 }
1079 556
1080 if (strlen(regexp)) { 557 if (strlen(config.regexp)) {
1081 errcode = regexec(&preg, body_buf.buf, REGS, pmatch, 0); 558 mp_subcheck sc_body_regex = mp_subcheck_init();
1082 if ((errcode == 0 && !invert_regex) || (errcode == REG_NOMATCH && invert_regex)) { 559 xasprintf(&sc_body_regex.output, "Regex \"%s\" in body matched", config.regexp);
1083 /* OK - No-op to avoid changing the logic around it */ 560 regmatch_t pmatch[REGS];
1084 result = max_state_alt(STATE_OK, result);
1085 } else if ((errcode == REG_NOMATCH && !invert_regex) || (errcode == 0 && invert_regex)) {
1086 if (!invert_regex) {
1087 char tmp[DEFAULT_BUFFER_SIZE];
1088 561
1089 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg); 562 int errcode = regexec(&config.compiled_regex, curl_state.body_buf->buf, REGS, pmatch, 0);
1090 strcpy(msg, tmp);
1091 563
564 if (errcode == 0) {
565 // got a match
566 if (config.invert_regex) {
567 sc_body_regex = mp_set_subcheck_state(sc_body_regex, config.state_regex);
1092 } else { 568 } else {
1093 char tmp[DEFAULT_BUFFER_SIZE]; 569 sc_body_regex = mp_set_subcheck_state(sc_body_regex, STATE_OK);
570 }
571 } else if (errcode == REG_NOMATCH) {
572 // got no match
573 xasprintf(&sc_body_regex.output, "%s not", sc_body_regex.output);
1094 574
1095 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg); 575 if (config.invert_regex) {
1096 strcpy(msg, tmp); 576 sc_body_regex = mp_set_subcheck_state(sc_body_regex, STATE_OK);
577 } else {
578 sc_body_regex = mp_set_subcheck_state(sc_body_regex, config.state_regex);
1097 } 579 }
1098 result = state_regex;
1099 } else { 580 } else {
1100 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER); 581 // error in regexec
1101 582 char error_buffer[DEFAULT_BUFFER_SIZE];
1102 char tmp[DEFAULT_BUFFER_SIZE]; 583 regerror(errcode, &config.compiled_regex, &error_buffer[0], DEFAULT_BUFFER_SIZE);
1103 584 xasprintf(&sc_body_regex.output, "regexec error: %s", error_buffer);
1104 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sExecute Error: %s, "), msg, errbuf); 585 sc_body_regex = mp_set_subcheck_state(sc_body_regex, STATE_UNKNOWN);
1105 strcpy(msg, tmp);
1106 result = STATE_UNKNOWN;
1107 } 586 }
587
588 mp_add_subcheck_to_subcheck(&sc_result, sc_body_regex);
1108 } 589 }
1109 590
1110 /* make sure the page is of an appropriate size */ 591 // size a.k.a. page length
1111 if ((max_page_len > 0) && (page_len > max_page_len)) { 592 mp_perfdata pd_page_length = perfdata_init();
1112 char tmp[DEFAULT_BUFFER_SIZE]; 593 mp_perfdata_value pd_val_page_length = mp_create_pd_value(page_len);
594 pd_page_length.value = pd_val_page_length;
595 pd_page_length.label = "size";
596 pd_page_length.uom = "B";
597 pd_page_length.min = mp_create_pd_value(0);
598 pd_page_length.warn = config.page_length_limits;
599 pd_page_length.warn_present = true;
1113 600
1114 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len); 601 /* make sure the page is of an appropriate size */
602 if (config.page_length_limits_is_set) {
603 mp_thresholds page_length_threshold = mp_thresholds_init();
604 page_length_threshold.warning = config.page_length_limits;
605 page_length_threshold.warning_is_set = true;
1115 606
1116 strcpy(msg, tmp); 607 pd_page_length = mp_pd_set_thresholds(pd_page_length, page_length_threshold);
1117 608
1118 result = max_state_alt(STATE_WARNING, result); 609 mp_subcheck sc_page_length = mp_subcheck_init();
1119 610
1120 } else if ((min_page_len > 0) && (page_len < min_page_len)) { 611 mp_add_perfdata_to_subcheck(&sc_page_length, pd_page_length);
1121 char tmp[DEFAULT_BUFFER_SIZE];
1122 612
1123 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len); 613 mp_state_enum tmp_state = mp_get_pd_status(pd_page_length);
1124 strcpy(msg, tmp); 614 sc_page_length = mp_set_subcheck_state(sc_page_length, tmp_state);
1125 result = max_state_alt(STATE_WARNING, result);
1126 }
1127 615
1128 /* -w, -c: check warning and critical level */ 616 switch (tmp_state) {
1129 result = max_state_alt(get_status(total_time, thlds), result); 617 case STATE_CRITICAL:
618 case STATE_WARNING:
619 xasprintf(&sc_page_length.output, _("page size %zu violates threshold"), page_len);
620 break;
621 case STATE_OK:
622 xasprintf(&sc_page_length.output, _("page size %zu is OK"), page_len);
623 break;
624 default:
625 assert(false);
626 }
1130 627
1131 /* Cut-off trailing characters */ 628 mp_add_subcheck_to_subcheck(&sc_result, sc_page_length);
1132 if (strlen(msg) >= 2) {
1133 if (msg[strlen(msg) - 2] == ',')
1134 msg[strlen(msg) - 2] = '\0';
1135 else
1136 msg[strlen(msg) - 3] = '\0';
1137 } 629 }
1138 630
1139 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */ 631 return sc_result;
1140 die(max_state_alt(result, result_ssl), "HTTP %s: %s %d %s%s%s - %d bytes in %.3f second response time %s|%s\n%s%s", state_text(result),
1141 string_statuscode(status_line.http_major, status_line.http_minor), status_line.http_code, status_line.msg,
1142 strlen(msg) > 0 ? " - " : "", msg, page_len, total_time, (display_html ? "</A>" : ""), perfstring, (show_body ? body_buf.buf : ""),
1143 (show_body ? "\n" : ""));
1144
1145 return max_state_alt(result, result_ssl);
1146} 632}
1147 633
1148int uri_strcmp(const UriTextRangeA range, const char *s) { 634int uri_strcmp(const UriTextRangeA range, const char *stringToCompare) {
1149 if (!range.first) 635 if (!range.first) {
1150 return -1; 636 return -1;
1151 if ((size_t)(range.afterLast - range.first) < strlen(s)) 637 }
638 if ((size_t)(range.afterLast - range.first) < strlen(stringToCompare)) {
1152 return -1; 639 return -1;
1153 return strncmp(s, range.first, min((size_t)(range.afterLast - range.first), strlen(s))); 640 }
641 return strncmp(stringToCompare, range.first,
642 min((size_t)(range.afterLast - range.first), strlen(stringToCompare)));
1154} 643}
1155 644
1156char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) { 645char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) {
1157 if (!range.first) 646 if (!range.first) {
1158 return "(null)"; 647 return "(null)";
648 }
1159 strncpy(buf, range.first, max(buflen - 1, (size_t)(range.afterLast - range.first))); 649 strncpy(buf, range.first, max(buflen - 1, (size_t)(range.afterLast - range.first)));
1160 buf[max(buflen - 1, (size_t)(range.afterLast - range.first))] = '\0'; 650 buf[max(buflen - 1, (size_t)(range.afterLast - range.first))] = '\0';
1161 buf[range.afterLast - range.first] = '\0'; 651 buf[range.afterLast - range.first] = '\0';
1162 return buf; 652 return buf;
1163} 653}
1164 654
1165void redir(curlhelp_write_curlbuf *header_buf) { 655redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config config,
1166 char *location = NULL; 656 long redir_depth, check_curl_working_state working_state) {
1167 curlhelp_statusline status_line; 657 curlhelp_statusline status_line;
1168 struct phr_header headers[255]; 658 struct phr_header headers[255];
1169 size_t nof_headers = 255;
1170 size_t msglen; 659 size_t msglen;
1171 char buf[DEFAULT_BUFFER_SIZE]; 660 size_t nof_headers = 255;
1172 char ipstr[INET_ADDR_MAX_SIZE]; 661 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major,
1173 int new_port; 662 &status_line.http_minor, &status_line.http_code, &status_line.msg,
1174 char *new_host; 663 &msglen, headers, &nof_headers, 0);
1175 char *new_url;
1176
1177 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
1178 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
1179 664
1180 if (res == -1) { 665 if (res == -1) {
1181 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 666 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
1182 } 667 }
1183 668
1184 location = get_header_value(headers, nof_headers, "location"); 669 char *location = get_header_value(headers, nof_headers, "location");
1185 670
1186 if (verbose >= 2) 671 if (location == NULL) {
672 // location header not found
673 die(STATE_UNKNOWN, "HTTP UNKNOWN - could not find \"location\" header\n");
674 }
675
676 if (verbose >= 2) {
1187 printf(_("* Seen redirect location %s\n"), location); 677 printf(_("* Seen redirect location %s\n"), location);
678 }
1188 679
1189 if (++redir_depth > max_depth) 680 if (++redir_depth > config.max_depth) {
1190 die(STATE_WARNING, _("HTTP WARNING - maximum redirection depth %d exceeded - %s%s\n"), max_depth, location, 681 die(STATE_WARNING, _("HTTP WARNING - maximum redirection depth %ld exceeded - %s\n"),
1191 (display_html ? "</A>" : "")); 682 config.max_depth, location);
683 }
1192 684
1193 UriParserStateA state; 685 UriParserStateA state;
1194 UriUriA uri; 686 UriUriA uri;
1195 state.uri = &uri; 687 state.uri = &uri;
1196 if (uriParseUriA(&state, location) != URI_SUCCESS) { 688 if (uriParseUriA(&state, location) != URI_SUCCESS) {
1197 if (state.errorCode == URI_ERROR_SYNTAX) { 689 if (state.errorCode == URI_ERROR_SYNTAX) {
1198 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"), location, (display_html ? "</A>" : "")); 690 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not parse redirect location '%s'\n"),
691 location);
1199 } else if (state.errorCode == URI_ERROR_MALLOC) { 692 } else if (state.errorCode == URI_ERROR_MALLOC) {
1200 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n")); 693 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1201 } 694 }
1202 } 695 }
1203 696
697 char ipstr[INET_ADDR_MAX_SIZE];
698 char buf[DEFAULT_BUFFER_SIZE];
1204 if (verbose >= 2) { 699 if (verbose >= 2) {
1205 printf(_("** scheme: %s\n"), uri_string(uri.scheme, buf, DEFAULT_BUFFER_SIZE)); 700 printf(_("** scheme: %s\n"), uri_string(uri.scheme, buf, DEFAULT_BUFFER_SIZE));
1206 printf(_("** host: %s\n"), uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE)); 701 printf(_("** host: %s\n"), uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
@@ -1215,9 +710,9 @@ void redir(curlhelp_write_curlbuf *header_buf) {
1215 } 710 }
1216 if (uri.pathHead) { 711 if (uri.pathHead) {
1217 printf(_("** path: ")); 712 printf(_("** path: "));
1218 const UriPathSegmentA *p = uri.pathHead; 713 for (UriPathSegmentA *path_segment = uri.pathHead; path_segment;
1219 for (; p; p = p->next) { 714 path_segment = path_segment->next) {
1220 printf("/%s", uri_string(p->text, buf, DEFAULT_BUFFER_SIZE)); 715 printf("/%s", uri_string(path_segment->text, buf, DEFAULT_BUFFER_SIZE));
1221 } 716 }
1222 puts(""); 717 puts("");
1223 } 718 }
@@ -1230,99 +725,123 @@ void redir(curlhelp_write_curlbuf *header_buf) {
1230 } 725 }
1231 726
1232 if (uri.scheme.first) { 727 if (uri.scheme.first) {
1233 if (!uri_strcmp(uri.scheme, "https")) 728 working_state.use_ssl = (bool)(!uri_strcmp(uri.scheme, "https"));
1234 use_ssl = true;
1235 else
1236 use_ssl = false;
1237 } 729 }
1238 730
1239 /* we do a sloppy test here only, because uriparser would have failed 731 /* we do a sloppy test here only, because uriparser would have failed
1240 * above, if the port would be invalid, we just check for MAX_PORT 732 * above, if the port would be invalid, we just check for MAX_PORT
1241 */ 733 */
734 int new_port;
1242 if (uri.portText.first) { 735 if (uri.portText.first) {
1243 new_port = atoi(uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE)); 736 new_port = atoi(uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE));
1244 } else { 737 } else {
1245 new_port = HTTP_PORT; 738 new_port = HTTP_PORT;
1246 if (use_ssl) 739 if (working_state.use_ssl) {
1247 new_port = HTTPS_PORT; 740 new_port = HTTPS_PORT;
741 }
742 }
743 if (new_port > MAX_PORT) {
744 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Redirection to port above %d - %s\n"), MAX_PORT,
745 location);
1248 } 746 }
1249 if (new_port > MAX_PORT)
1250 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"), MAX_PORT, location, display_html ? "</A>" : "");
1251 747
1252 /* by RFC 7231 relative URLs in Location should be taken relative to 748 /* by RFC 7231 relative URLs in Location should be taken relative to
1253 * the original URL, so we try to form a new absolute URL here 749 * the original URL, so we try to form a new absolute URL here
1254 */ 750 */
751 char *new_host;
1255 if (!uri.scheme.first && !uri.hostText.first) { 752 if (!uri.scheme.first && !uri.hostText.first) {
1256 new_host = strdup(host_name ? host_name : server_address); 753 new_host = strdup(working_state.host_name ? working_state.host_name
1257 new_port = server_port; 754 : working_state.server_address);
1258 if (use_ssl) 755 new_port = working_state.serverPort;
756 if (working_state.use_ssl) {
1259 uri_string(uri.scheme, "https", DEFAULT_BUFFER_SIZE); 757 uri_string(uri.scheme, "https", DEFAULT_BUFFER_SIZE);
758 }
1260 } else { 759 } else {
1261 new_host = strdup(uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE)); 760 new_host = strdup(uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
1262 } 761 }
1263 762
1264 /* compose new path */ 763 /* compose new path */
1265 /* TODO: handle fragments and query part of URL */ 764 /* TODO: handle fragments of URL */
1266 new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE); 765 char *new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE);
1267 if (uri.pathHead) { 766 if (uri.pathHead) {
1268 const UriPathSegmentA *p = uri.pathHead; 767 for (UriPathSegmentA *pathSegment = uri.pathHead; pathSegment;
1269 for (; p; p = p->next) { 768 pathSegment = pathSegment->next) {
1270 strncat(new_url, "/", DEFAULT_BUFFER_SIZE); 769 strncat(new_url, "/", DEFAULT_BUFFER_SIZE);
1271 strncat(new_url, uri_string(p->text, buf, DEFAULT_BUFFER_SIZE), DEFAULT_BUFFER_SIZE - 1); 770 strncat(new_url, uri_string(pathSegment->text, buf, DEFAULT_BUFFER_SIZE),
771 DEFAULT_BUFFER_SIZE - 1);
1272 } 772 }
1273 } 773 }
1274 774
1275 if (server_port == new_port && !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) && 775 /* missing components have null,null in their UriTextRangeA
1276 (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) && !strcmp(server_url, new_url)) 776 * add query parameters if they exist.
1277 die(STATE_CRITICAL, _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), use_ssl ? "https" : "http", 777 */
1278 new_host, new_port, new_url, (display_html ? "</A>" : "")); 778 if (uri.query.first && uri.query.afterLast){
779 // Ensure we have space for '?' + query_str + '\0' ahead of time, instead of calling strncat twice
780 size_t current_len = strlen(new_url);
781 size_t remaining_space = DEFAULT_BUFFER_SIZE - current_len - 1;
782
783 const char* query_str = uri_string(uri.query, buf, DEFAULT_BUFFER_SIZE);
784 size_t query_str_len = strlen(query_str);
785
786 if (remaining_space >= query_str_len + 1) {
787 strcat(new_url, "?");
788 strcat(new_url, query_str);
789 }else{
790 die(STATE_UNKNOWN, _("HTTP UNKNOWN - No space to add query part of size %d to the buffer, buffer has remaining size %d"), query_str_len , current_len );
791 }
792 }
793
794 if (working_state.serverPort == new_port &&
795 !strncmp(working_state.server_address, new_host, MAX_IPV4_HOSTLENGTH) &&
796 (working_state.host_name &&
797 !strncmp(working_state.host_name, new_host, MAX_IPV4_HOSTLENGTH)) &&
798 !strcmp(working_state.server_url, new_url)) {
799 die(STATE_CRITICAL,
800 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s\n"),
801 working_state.use_ssl ? "https" : "http", new_host, new_port, new_url);
802 }
1279 803
1280 /* set new values for redirected request */ 804 /* set new values for redirected request */
1281 805
1282 if (!(followsticky & STICKY_HOST)) { 806 if (!(config.followsticky & STICKY_HOST)) {
1283 free(server_address); 807 // free(working_state.server_address);
1284 server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH); 808 working_state.server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1285 } 809 }
1286 if (!(followsticky & STICKY_PORT)) { 810 if (!(config.followsticky & STICKY_PORT)) {
1287 server_port = (unsigned short)new_port; 811 working_state.serverPort = (unsigned short)new_port;
1288 } 812 }
1289 813
1290 free(host_name); 814 // free(working_state.host_name);
1291 host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH); 815 working_state.host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1292 816
1293 /* reset virtual port */ 817 /* reset virtual port */
1294 virtual_port = server_port; 818 working_state.virtualPort = working_state.serverPort;
1295 819
1296 free(new_host); 820 free(new_host);
1297 free(server_url); 821 // free(working_state.server_url);
1298 server_url = new_url; 822 working_state.server_url = new_url;
1299 823
1300 uriFreeUriMembersA(&uri); 824 uriFreeUriMembersA(&uri);
1301 825
1302 if (verbose) 826 if (verbose) {
1303 printf(_("Redirection to %s://%s:%d%s\n"), use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, 827 printf(_("Redirection to %s://%s:%d%s\n"), working_state.use_ssl ? "https" : "http",
1304 server_url); 828 working_state.host_name ? working_state.host_name : working_state.server_address,
829 working_state.serverPort, working_state.server_url);
830 }
1305 831
1306 /* TODO: the hash component MUST be taken from the original URL and 832 /* TODO: the hash component MUST be taken from the original URL and
1307 * attached to the URL in Location 833 * attached to the URL in Location
1308 */ 834 */
1309 835
1310 cleanup(); 836 redir_wrapper result = {
1311 check_http(); 837 .redir_depth = redir_depth,
1312} 838 .working_state = working_state,
1313 839 .error_code = OK,
1314/* check whether a file exists */ 840 };
1315void test_file(char *path) { 841 return result;
1316 if (access(path, R_OK) == 0)
1317 return;
1318 usage2(_("file does not exist or is not readable"), path);
1319} 842}
1320 843
1321bool process_arguments(int argc, char **argv) { 844check_curl_config_wrapper process_arguments(int argc, char **argv) {
1322 char *p;
1323 int c = 1;
1324 char *temp;
1325
1326 enum { 845 enum {
1327 INVERT_REGEX = CHAR_MAX + 1, 846 INVERT_REGEX = CHAR_MAX + 1,
1328 SNI_OPTION, 847 SNI_OPTION,
@@ -1333,81 +852,101 @@ bool process_arguments(int argc, char **argv) {
1333 AUTOMATIC_DECOMPRESSION, 852 AUTOMATIC_DECOMPRESSION,
1334 COOKIE_JAR, 853 COOKIE_JAR,
1335 HAPROXY_PROTOCOL, 854 HAPROXY_PROTOCOL,
1336 STATE_REGEX 855 STATE_REGEX,
856 OUTPUT_FORMAT
1337 }; 857 };
1338 858
1339 int option = 0; 859 static struct option longopts[] = {
1340 int got_plus = 0; 860 STD_LONG_OPTS,
1341 static struct option longopts[] = {STD_LONG_OPTS, 861 {"link", no_argument, 0, 'L'},
1342 {"link", no_argument, 0, 'L'}, 862 {"nohtml", no_argument, 0, 'n'},
1343 {"nohtml", no_argument, 0, 'n'}, 863 {"ssl", optional_argument, 0, 'S'},
1344 {"ssl", optional_argument, 0, 'S'}, 864 {"sni", no_argument, 0, SNI_OPTION},
1345 {"sni", no_argument, 0, SNI_OPTION}, 865 {"post", required_argument, 0, 'P'},
1346 {"post", required_argument, 0, 'P'}, 866 {"method", required_argument, 0, 'j'},
1347 {"method", required_argument, 0, 'j'}, 867 {"IP-address", required_argument, 0, 'I'},
1348 {"IP-address", required_argument, 0, 'I'}, 868 {"url", required_argument, 0, 'u'},
1349 {"url", required_argument, 0, 'u'}, 869 {"port", required_argument, 0, 'p'},
1350 {"port", required_argument, 0, 'p'}, 870 {"authorization", required_argument, 0, 'a'},
1351 {"authorization", required_argument, 0, 'a'}, 871 {"proxy-authorization", required_argument, 0, 'b'},
1352 {"proxy-authorization", required_argument, 0, 'b'}, 872 {"header-string", required_argument, 0, 'd'},
1353 {"header-string", required_argument, 0, 'd'}, 873 {"string", required_argument, 0, 's'},
1354 {"string", required_argument, 0, 's'}, 874 {"expect", required_argument, 0, 'e'},
1355 {"expect", required_argument, 0, 'e'}, 875 {"regex", required_argument, 0, 'r'},
1356 {"regex", required_argument, 0, 'r'}, 876 {"ereg", required_argument, 0, 'r'},
1357 {"ereg", required_argument, 0, 'r'}, 877 {"eregi", required_argument, 0, 'R'},
1358 {"eregi", required_argument, 0, 'R'}, 878 {"linespan", no_argument, 0, 'l'},
1359 {"linespan", no_argument, 0, 'l'}, 879 {"onredirect", required_argument, 0, 'f'},
1360 {"onredirect", required_argument, 0, 'f'}, 880 {"certificate", required_argument, 0, 'C'},
1361 {"certificate", required_argument, 0, 'C'}, 881 {"client-cert", required_argument, 0, 'J'},
1362 {"client-cert", required_argument, 0, 'J'}, 882 {"private-key", required_argument, 0, 'K'},
1363 {"private-key", required_argument, 0, 'K'}, 883 {"ca-cert", required_argument, 0, CA_CERT_OPTION},
1364 {"ca-cert", required_argument, 0, CA_CERT_OPTION}, 884 {"verify-cert", no_argument, 0, 'D'},
1365 {"verify-cert", no_argument, 0, 'D'}, 885 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
1366 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT}, 886 {"useragent", required_argument, 0, 'A'},
1367 {"useragent", required_argument, 0, 'A'}, 887 {"header", required_argument, 0, 'k'},
1368 {"header", required_argument, 0, 'k'}, 888 {"no-body", no_argument, 0, 'N'},
1369 {"no-body", no_argument, 0, 'N'}, 889 {"max-age", required_argument, 0, 'M'},
1370 {"max-age", required_argument, 0, 'M'}, 890 {"content-type", required_argument, 0, 'T'},
1371 {"content-type", required_argument, 0, 'T'}, 891 {"pagesize", required_argument, 0, 'm'},
1372 {"pagesize", required_argument, 0, 'm'}, 892 {"invert-regex", no_argument, NULL, INVERT_REGEX},
1373 {"invert-regex", no_argument, NULL, INVERT_REGEX}, 893 {"state-regex", required_argument, 0, STATE_REGEX},
1374 {"state-regex", required_argument, 0, STATE_REGEX}, 894 {"use-ipv4", no_argument, 0, '4'},
1375 {"use-ipv4", no_argument, 0, '4'}, 895 {"use-ipv6", no_argument, 0, '6'},
1376 {"use-ipv6", no_argument, 0, '6'}, 896 {"extended-perfdata", no_argument, 0, 'E'},
1377 {"extended-perfdata", no_argument, 0, 'E'}, 897 {"show-body", no_argument, 0, 'B'},
1378 {"show-body", no_argument, 0, 'B'}, 898 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
1379 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION}, 899 {"http-version", required_argument, 0, HTTP_VERSION_OPTION},
1380 {"http-version", required_argument, 0, HTTP_VERSION_OPTION}, 900 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION},
1381 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION}, 901 {"cookie-jar", required_argument, 0, COOKIE_JAR},
1382 {"cookie-jar", required_argument, 0, COOKIE_JAR}, 902 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL},
1383 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL}, 903 {"output-format", required_argument, 0, OUTPUT_FORMAT},
1384 {0, 0, 0, 0}}; 904 {0, 0, 0, 0}};
1385 905
1386 if (argc < 2) 906 check_curl_config_wrapper result = {
1387 return false; 907 .errorcode = OK,
908 .config = check_curl_config_init(),
909 };
1388 910
1389 /* support check_http compatible arguments */ 911 if (argc < 2) {
1390 for (c = 1; c < argc; c++) { 912 result.errorcode = ERROR;
1391 if (strcmp("-to", argv[c]) == 0) 913 return result;
1392 strcpy(argv[c], "-t");
1393 if (strcmp("-hn", argv[c]) == 0)
1394 strcpy(argv[c], "-H");
1395 if (strcmp("-wt", argv[c]) == 0)
1396 strcpy(argv[c], "-w");
1397 if (strcmp("-ct", argv[c]) == 0)
1398 strcpy(argv[c], "-c");
1399 if (strcmp("-nohtml", argv[c]) == 0)
1400 strcpy(argv[c], "-n");
1401 } 914 }
1402 915
1403 server_url = strdup(DEFAULT_SERVER_URL); 916 /* support check_http compatible arguments */
917 for (int index = 1; index < argc; index++) {
918 if (strcmp("-to", argv[index]) == 0) {
919 strcpy(argv[index], "-t");
920 }
921 if (strcmp("-hn", argv[index]) == 0) {
922 strcpy(argv[index], "-H");
923 }
924 if (strcmp("-wt", argv[index]) == 0) {
925 strcpy(argv[index], "-w");
926 }
927 if (strcmp("-ct", argv[index]) == 0) {
928 strcpy(argv[index], "-c");
929 }
930 if (strcmp("-nohtml", argv[index]) == 0) {
931 strcpy(argv[index], "-n");
932 }
933 }
1404 934
1405 while (1) { 935 int option = 0;
1406 c = getopt_long(argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:DnlLS::m:M:NEB", longopts, &option); 936 int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
1407 if (c == -1 || c == EOF || c == 1) 937 bool specify_port = false;
938 bool enable_tls = false;
939 char *tls_option_optarg = NULL;
940
941 while (true) {
942 int option_index = getopt_long(
943 argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:DnlLS::m:M:NEB",
944 longopts, &option);
945 if (option_index == -1 || option_index == EOF || option_index == 1) {
1408 break; 946 break;
947 }
1409 948
1410 switch (c) { 949 switch (option_index) {
1411 case 'h': 950 case 'h':
1412 print_help(); 951 print_help();
1413 exit(STATE_UNKNOWN); 952 exit(STATE_UNKNOWN);
@@ -1421,270 +960,253 @@ bool process_arguments(int argc, char **argv) {
1421 verbose++; 960 verbose++;
1422 break; 961 break;
1423 case 't': /* timeout period */ 962 case 't': /* timeout period */
1424 if (!is_intnonneg(optarg)) 963 if (!is_intnonneg(optarg)) {
1425 usage2(_("Timeout interval must be a positive integer"), optarg); 964 usage2(_("Timeout interval must be a positive integer"), optarg);
1426 else 965 } else {
1427 socket_timeout = (int)strtol(optarg, NULL, 10); 966 result.config.curl_config.socket_timeout = (int)strtol(optarg, NULL, 10);
967 }
1428 break; 968 break;
1429 case 'c': /* critical time threshold */ 969 case 'c': /* critical time threshold */
1430 critical_thresholds = optarg; 970 {
1431 break; 971 mp_range_parsed critical_range = mp_parse_range_string(optarg);
972 if (critical_range.error != MP_PARSING_SUCCES) {
973 die(STATE_UNKNOWN, "failed to parse critical threshold: %s", optarg);
974 }
975 result.config.thlds = mp_thresholds_set_crit(result.config.thlds, critical_range.range);
976 } break;
1432 case 'w': /* warning time threshold */ 977 case 'w': /* warning time threshold */
1433 warning_thresholds = optarg; 978 {
1434 break; 979 mp_range_parsed warning_range = mp_parse_range_string(optarg);
980
981 if (warning_range.error != MP_PARSING_SUCCES) {
982 die(STATE_UNKNOWN, "failed to parse warning threshold: %s", optarg);
983 }
984 result.config.thlds = mp_thresholds_set_warn(result.config.thlds, warning_range.range);
985 } break;
1435 case 'H': /* virtual host */ 986 case 'H': /* virtual host */
1436 host_name = strdup(optarg); 987 result.config.initial_config.host_name = strdup(optarg);
1437 if (host_name[0] == '[') { 988 char *tmp_string;
1438 if ((p = strstr(host_name, "]:")) != NULL) { /* [IPv6]:port */ 989 size_t host_name_length;
1439 virtual_port = atoi(p + 2); 990 if (result.config.initial_config.host_name[0] == '[') {
991 if ((tmp_string = strstr(result.config.initial_config.host_name, "]:")) !=
992 NULL) { /* [IPv6]:port */
993 result.config.initial_config.virtualPort = atoi(tmp_string + 2);
1440 /* cut off the port */ 994 /* cut off the port */
1441 host_name_length = strlen(host_name) - strlen(p) - 1; 995 host_name_length =
1442 free(host_name); 996 strlen(result.config.initial_config.host_name) - strlen(tmp_string) - 1;
1443 host_name = strndup(optarg, host_name_length); 997 free(result.config.initial_config.host_name);
998 result.config.initial_config.host_name = strndup(optarg, host_name_length);
1444 } 999 }
1445 } else if ((p = strchr(host_name, ':')) != NULL && strchr(++p, ':') == NULL) { /* IPv4:port or host:port */ 1000 } else if ((tmp_string = strchr(result.config.initial_config.host_name, ':')) != NULL &&
1446 virtual_port = atoi(p); 1001 strchr(++tmp_string, ':') == NULL) { /* IPv4:port or host:port */
1002 result.config.initial_config.virtualPort = atoi(tmp_string);
1447 /* cut off the port */ 1003 /* cut off the port */
1448 host_name_length = strlen(host_name) - strlen(p) - 1; 1004 host_name_length =
1449 free(host_name); 1005 strlen(result.config.initial_config.host_name) - strlen(tmp_string) - 1;
1450 host_name = strndup(optarg, host_name_length); 1006 free(result.config.initial_config.host_name);
1007 result.config.initial_config.host_name = strndup(optarg, host_name_length);
1451 } 1008 }
1452 break; 1009 break;
1453 case 'I': /* internet address */ 1010 case 'I': /* internet address */
1454 server_address = strdup(optarg); 1011 result.config.initial_config.server_address = strdup(optarg);
1455 break; 1012 break;
1456 case 'u': /* URL path */ 1013 case 'u': /* URL path */
1457 server_url = strdup(optarg); 1014 result.config.initial_config.server_url = strdup(optarg);
1458 break; 1015 break;
1459 case 'p': /* Server port */ 1016 case 'p': /* Server port */
1460 if (!is_intnonneg(optarg)) 1017 if (!is_intnonneg(optarg)) {
1461 usage2(_("Invalid port number, expecting a non-negative number"), optarg); 1018 usage2(_("Invalid port number, expecting a non-negative number"), optarg);
1462 else { 1019 } else {
1463 if (strtol(optarg, NULL, 10) > MAX_PORT) 1020 if (strtol(optarg, NULL, 10) > MAX_PORT) {
1464 usage2(_("Invalid port number, supplied port number is too big"), optarg); 1021 usage2(_("Invalid port number, supplied port number is too big"), optarg);
1465 server_port = (unsigned short)strtol(optarg, NULL, 10); 1022 }
1023 result.config.initial_config.serverPort = (unsigned short)strtol(optarg, NULL, 10);
1466 specify_port = true; 1024 specify_port = true;
1467 } 1025 }
1468 break; 1026 break;
1469 case 'a': /* authorization info */ 1027 case 'a': /* authorization info */
1470 strncpy(user_auth, optarg, MAX_INPUT_BUFFER - 1); 1028 strncpy(result.config.curl_config.user_auth, optarg, MAX_INPUT_BUFFER - 1);
1471 user_auth[MAX_INPUT_BUFFER - 1] = 0; 1029 result.config.curl_config.user_auth[MAX_INPUT_BUFFER - 1] = 0;
1472 break; 1030 break;
1473 case 'b': /* proxy-authorization info */ 1031 case 'b': /* proxy-authorization info */
1474 strncpy(proxy_auth, optarg, MAX_INPUT_BUFFER - 1); 1032 strncpy(result.config.curl_config.proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
1475 proxy_auth[MAX_INPUT_BUFFER - 1] = 0; 1033 result.config.curl_config.proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
1476 break; 1034 break;
1477 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */ 1035 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
1478 if (!http_post_data) 1036 if (!result.config.initial_config.http_post_data) {
1479 http_post_data = strdup(optarg); 1037 result.config.initial_config.http_post_data = strdup(optarg);
1480 if (!http_method) 1038 }
1481 http_method = strdup("POST"); 1039 if (!result.config.initial_config.http_method) {
1040 result.config.initial_config.http_method = strdup("POST");
1041 }
1482 break; 1042 break;
1483 case 'j': /* Set HTTP method */ 1043 case 'j': /* Set HTTP method */
1484 if (http_method) 1044 if (result.config.initial_config.http_method) {
1485 free(http_method); 1045 free(result.config.initial_config.http_method);
1486 http_method = strdup(optarg); 1046 }
1047 result.config.initial_config.http_method = strdup(optarg);
1487 break; 1048 break;
1488 case 'A': /* useragent */ 1049 case 'A': /* useragent */
1489 strncpy(user_agent, optarg, DEFAULT_BUFFER_SIZE); 1050 strncpy(result.config.curl_config.user_agent, optarg, DEFAULT_BUFFER_SIZE);
1490 user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0'; 1051 result.config.curl_config.user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0';
1491 break; 1052 break;
1492 case 'k': /* Additional headers */ 1053 case 'k': /* Additional headers */
1493 if (http_opt_headers_count == 0) 1054 if (result.config.curl_config.http_opt_headers_count == 0) {
1494 http_opt_headers = malloc(sizeof(char *) * (++http_opt_headers_count)); 1055 result.config.curl_config.http_opt_headers =
1495 else 1056 malloc(sizeof(char *) * (++result.config.curl_config.http_opt_headers_count));
1496 http_opt_headers = realloc(http_opt_headers, sizeof(char *) * (++http_opt_headers_count)); 1057 } else {
1497 http_opt_headers[http_opt_headers_count - 1] = optarg; 1058 result.config.curl_config.http_opt_headers =
1059 realloc(result.config.curl_config.http_opt_headers,
1060 sizeof(char *) * (++result.config.curl_config.http_opt_headers_count));
1061 }
1062 result.config.curl_config
1063 .http_opt_headers[result.config.curl_config.http_opt_headers_count - 1] = optarg;
1498 break; 1064 break;
1499 case 'L': /* show html link */ 1065 case 'L': /* show html link */
1500 display_html = true;
1501 break;
1502 case 'n': /* do not show html link */ 1066 case 'n': /* do not show html link */
1503 display_html = false; 1067 // HTML link related options are deprecated
1504 break; 1068 break;
1505 case 'C': /* Check SSL cert validity */ 1069 case 'C': /* Check SSL cert validity */
1506#ifdef LIBCURL_FEATURE_SSL 1070#ifndef LIBCURL_FEATURE_SSL
1507 if ((temp = strchr(optarg, ',')) != NULL) { 1071 usage4(_("Invalid option - SSL is not available"));
1508 *temp = '\0';
1509 if (!is_intnonneg(optarg))
1510 usage2(_("Invalid certificate expiration period"), optarg);
1511 days_till_exp_warn = atoi(optarg);
1512 *temp = ',';
1513 temp++;
1514 if (!is_intnonneg(temp))
1515 usage2(_("Invalid certificate expiration period"), temp);
1516 days_till_exp_crit = atoi(temp);
1517 } else {
1518 days_till_exp_crit = 0;
1519 if (!is_intnonneg(optarg))
1520 usage2(_("Invalid certificate expiration period"), optarg);
1521 days_till_exp_warn = atoi(optarg);
1522 }
1523 check_cert = true;
1524 goto enable_ssl;
1525#endif 1072#endif
1073 {
1074 char *temp;
1075 if ((temp = strchr(optarg, ',')) != NULL) {
1076 *temp = '\0';
1077 if (!is_intnonneg(optarg)) {
1078 usage2(_("Invalid certificate expiration period"), optarg);
1079 }
1080 result.config.days_till_exp_warn = atoi(optarg);
1081 *temp = ',';
1082 temp++;
1083 if (!is_intnonneg(temp)) {
1084 usage2(_("Invalid certificate expiration period"), temp);
1085 }
1086 result.config.days_till_exp_crit = atoi(temp);
1087 } else {
1088 result.config.days_till_exp_crit = 0;
1089 if (!is_intnonneg(optarg)) {
1090 usage2(_("Invalid certificate expiration period"), optarg);
1091 }
1092 result.config.days_till_exp_warn = atoi(optarg);
1093 }
1094 result.config.check_cert = true;
1095 enable_tls = true;
1096 }
1097 break;
1526 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */ 1098 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
1527#ifdef HAVE_SSL 1099#ifdef HAVE_SSL
1528 continue_after_check_cert = true; 1100 result.config.continue_after_check_cert = true;
1529 break; 1101 break;
1530#endif 1102#endif
1531 case 'J': /* use client certificate */ 1103 case 'J': /* use client certificate */
1532#ifdef LIBCURL_FEATURE_SSL 1104#ifndef LIBCURL_FEATURE_SSL
1533 test_file(optarg); 1105 usage4(_("Invalid option - SSL is not available"));
1534 client_cert = optarg;
1535 goto enable_ssl;
1536#endif 1106#endif
1537 case 'K': /* use client private key */
1538#ifdef LIBCURL_FEATURE_SSL
1539 test_file(optarg); 1107 test_file(optarg);
1540 client_privkey = optarg; 1108 result.config.curl_config.client_cert = optarg;
1541 goto enable_ssl; 1109 enable_tls = true;
1110 break;
1111 case 'K': /* use client private key */
1112#ifndef LIBCURL_FEATURE_SSL
1113 usage4(_("Invalid option - SSL is not available"));
1542#endif 1114#endif
1543#ifdef LIBCURL_FEATURE_SSL
1544 case CA_CERT_OPTION: /* use CA chain file */
1545 test_file(optarg); 1115 test_file(optarg);
1546 ca_cert = optarg; 1116 result.config.curl_config.client_privkey = optarg;
1547 goto enable_ssl; 1117 enable_tls = true;
1118 break;
1119 case CA_CERT_OPTION: /* use CA chain file */
1120#ifndef LIBCURL_FEATURE_SSL
1121 usage4(_("Invalid option - SSL is not available"));
1548#endif 1122#endif
1549#ifdef LIBCURL_FEATURE_SSL 1123 test_file(optarg);
1550 case 'D': /* verify peer certificate & host */ 1124 result.config.curl_config.ca_cert = optarg;
1551 verify_peer_and_host = true; 1125 enable_tls = true;
1552 break; 1126 break;
1127 case 'D': /* verify peer certificate & host */
1128#ifndef LIBCURL_FEATURE_SSL
1129 usage4(_("Invalid option - SSL is not available"));
1553#endif 1130#endif
1554 case 'S': /* use SSL */ 1131 result.config.curl_config.verify_peer_and_host = true;
1555#ifdef LIBCURL_FEATURE_SSL 1132 enable_tls = true;
1556 enable_ssl:
1557 use_ssl = true;
1558 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default.
1559 * Only set if it's non-zero. This helps when we include multiple
1560 * parameters, like -S and -C combinations */
1561 ssl_version = CURL_SSLVERSION_DEFAULT;
1562 if (c == 'S' && optarg != NULL) {
1563 char *plus_ptr = strchr(optarg, '+');
1564 if (plus_ptr) {
1565 got_plus = 1;
1566 *plus_ptr = '\0';
1567 }
1568
1569 if (optarg[0] == '2')
1570 ssl_version = CURL_SSLVERSION_SSLv2;
1571 else if (optarg[0] == '3')
1572 ssl_version = CURL_SSLVERSION_SSLv3;
1573 else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0"))
1574# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1575 ssl_version = CURL_SSLVERSION_TLSv1_0;
1576# else
1577 ssl_version = CURL_SSLVERSION_DEFAULT;
1578# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1579 else if (!strcmp(optarg, "1.1"))
1580# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1581 ssl_version = CURL_SSLVERSION_TLSv1_1;
1582# else
1583 ssl_version = CURL_SSLVERSION_DEFAULT;
1584# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1585 else if (!strcmp(optarg, "1.2"))
1586# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1587 ssl_version = CURL_SSLVERSION_TLSv1_2;
1588# else
1589 ssl_version = CURL_SSLVERSION_DEFAULT;
1590# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1591 else if (!strcmp(optarg, "1.3"))
1592# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
1593 ssl_version = CURL_SSLVERSION_TLSv1_3;
1594# else
1595 ssl_version = CURL_SSLVERSION_DEFAULT;
1596# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */
1597 else
1598 usage4(_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 (with optional '+' suffix)"));
1599 }
1600# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0)
1601 if (got_plus) {
1602 switch (ssl_version) {
1603 case CURL_SSLVERSION_TLSv1_3:
1604 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1605 break;
1606 case CURL_SSLVERSION_TLSv1_2:
1607 case CURL_SSLVERSION_TLSv1_1:
1608 case CURL_SSLVERSION_TLSv1_0:
1609 ssl_version |= CURL_SSLVERSION_MAX_DEFAULT;
1610 break;
1611 }
1612 } else {
1613 switch (ssl_version) {
1614 case CURL_SSLVERSION_TLSv1_3:
1615 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1616 break;
1617 case CURL_SSLVERSION_TLSv1_2:
1618 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2;
1619 break;
1620 case CURL_SSLVERSION_TLSv1_1:
1621 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1;
1622 break;
1623 case CURL_SSLVERSION_TLSv1_0:
1624 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0;
1625 break;
1626 }
1627 }
1628# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
1629 if (verbose >= 2)
1630 printf(_("* Set SSL/TLS version to %d\n"), ssl_version);
1631 if (!specify_port)
1632 server_port = HTTPS_PORT;
1633 break; 1133 break;
1634#else /* LIBCURL_FEATURE_SSL */ 1134 case 'S': /* use SSL */
1635 /* -C -J and -K fall through to here without SSL */ 1135 tls_option_optarg = optarg;
1136 enable_tls = true;
1137#ifndef LIBCURL_FEATURE_SSL
1636 usage4(_("Invalid option - SSL is not available")); 1138 usage4(_("Invalid option - SSL is not available"));
1139#endif
1637 break; 1140 break;
1638 case SNI_OPTION: /* --sni is parsed, but ignored, the default is true with libcurl */ 1141 case SNI_OPTION: /* --sni is parsed, but ignored, the default is true with libcurl */
1639 use_sni = true; 1142#ifndef LIBCURL_FEATURE_SSL
1640 break; 1143 usage4(_("Invalid option - SSL is not available"));
1641#endif /* LIBCURL_FEATURE_SSL */ 1144#endif /* LIBCURL_FEATURE_SSL */
1145 break;
1642 case MAX_REDIRS_OPTION: 1146 case MAX_REDIRS_OPTION:
1643 if (!is_intnonneg(optarg)) 1147 if (!is_intnonneg(optarg)) {
1644 usage2(_("Invalid max_redirs count"), optarg); 1148 usage2(_("Invalid max_redirs count"), optarg);
1645 else { 1149 } else {
1646 max_depth = atoi(optarg); 1150 result.config.max_depth = atoi(optarg);
1647 } 1151 }
1648 break; 1152 break;
1649 case 'f': /* onredirect */ 1153 case 'f': /* onredirect */
1650 if (!strcmp(optarg, "ok")) 1154 if (!strcmp(optarg, "ok")) {
1651 onredirect = STATE_OK; 1155 result.config.on_redirect_result_state = STATE_OK;
1652 else if (!strcmp(optarg, "warning")) 1156 result.config.on_redirect_dependent = false;
1653 onredirect = STATE_WARNING; 1157 } else if (!strcmp(optarg, "warning")) {
1654 else if (!strcmp(optarg, "critical")) 1158 result.config.on_redirect_result_state = STATE_WARNING;
1655 onredirect = STATE_CRITICAL; 1159 result.config.on_redirect_dependent = false;
1656 else if (!strcmp(optarg, "unknown")) 1160 } else if (!strcmp(optarg, "critical")) {
1657 onredirect = STATE_UNKNOWN; 1161 result.config.on_redirect_result_state = STATE_CRITICAL;
1658 else if (!strcmp(optarg, "follow")) 1162 result.config.on_redirect_dependent = false;
1659 onredirect = STATE_DEPENDENT; 1163 } else if (!strcmp(optarg, "unknown")) {
1660 else if (!strcmp(optarg, "stickyport")) 1164 result.config.on_redirect_result_state = STATE_UNKNOWN;
1661 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST | STICKY_PORT; 1165 result.config.on_redirect_dependent = false;
1662 else if (!strcmp(optarg, "sticky")) 1166 } else if (!strcmp(optarg, "follow")) {
1663 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST; 1167 result.config.on_redirect_dependent = true;
1664 else if (!strcmp(optarg, "follow")) 1168 } else if (!strcmp(optarg, "stickyport")) {
1665 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE; 1169 result.config.on_redirect_dependent = true;
1666 else if (!strcmp(optarg, "curl")) 1170 result.config.followmethod = FOLLOW_HTTP_CURL,
1667 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL; 1171 result.config.followsticky = STICKY_HOST | STICKY_PORT;
1668 else 1172 } else if (!strcmp(optarg, "sticky")) {
1173 result.config.on_redirect_dependent = true;
1174 result.config.followmethod = FOLLOW_HTTP_CURL,
1175 result.config.followsticky = STICKY_HOST;
1176 } else if (!strcmp(optarg, "follow")) {
1177 result.config.on_redirect_dependent = true;
1178 result.config.followmethod = FOLLOW_HTTP_CURL,
1179 result.config.followsticky = STICKY_NONE;
1180 } else if (!strcmp(optarg, "curl")) {
1181 result.config.on_redirect_dependent = true;
1182 result.config.followmethod = FOLLOW_LIBCURL;
1183 } else {
1669 usage2(_("Invalid onredirect option"), optarg); 1184 usage2(_("Invalid onredirect option"), optarg);
1670 if (verbose >= 2) 1185 }
1671 printf(_("* Following redirects set to %s\n"), state_text(onredirect)); 1186 if (verbose >= 2) {
1187 if (result.config.on_redirect_dependent) {
1188 printf(_("* Following redirects\n"));
1189 } else {
1190 printf(_("* Following redirects set to state %s\n"),
1191 state_text(result.config.on_redirect_result_state));
1192 }
1193 }
1672 break; 1194 break;
1673 case 'd': /* string or substring */ 1195 case 'd': /* string or substring */
1674 strncpy(header_expect, optarg, MAX_INPUT_BUFFER - 1); 1196 strncpy(result.config.header_expect, optarg, MAX_INPUT_BUFFER - 1);
1675 header_expect[MAX_INPUT_BUFFER - 1] = 0; 1197 result.config.header_expect[MAX_INPUT_BUFFER - 1] = 0;
1676 break; 1198 break;
1677 case 's': /* string or substring */ 1199 case 's': /* string or substring */
1678 strncpy(string_expect, optarg, MAX_INPUT_BUFFER - 1); 1200 strncpy(result.config.string_expect, optarg, MAX_INPUT_BUFFER - 1);
1679 string_expect[MAX_INPUT_BUFFER - 1] = 0; 1201 result.config.string_expect[MAX_INPUT_BUFFER - 1] = 0;
1680 break; 1202 break;
1681 case 'e': /* string or substring */ 1203 case 'e': /* string or substring */
1682 strncpy(server_expect, optarg, MAX_INPUT_BUFFER - 1); 1204 strncpy(result.config.server_expect.string, optarg, MAX_INPUT_BUFFER - 1);
1683 server_expect[MAX_INPUT_BUFFER - 1] = 0; 1205 result.config.server_expect.string[MAX_INPUT_BUFFER - 1] = 0;
1684 server_expect_yn = 1; 1206 result.config.server_expect.is_present = true;
1685 break; 1207 break;
1686 case 'T': /* Content-type */ 1208 case 'T': /* Content-type */
1687 http_content_type = strdup(optarg); 1209 result.config.curl_config.http_content_type = strdup(optarg);
1688 break; 1210 break;
1689 case 'l': /* linespan */ 1211 case 'l': /* linespan */
1690 cflags &= ~REG_NEWLINE; 1212 cflags &= ~REG_NEWLINE;
@@ -1693,185 +1215,258 @@ bool process_arguments(int argc, char **argv) {
1693 cflags |= REG_ICASE; 1215 cflags |= REG_ICASE;
1694 // fall through 1216 // fall through
1695 case 'r': /* regex */ 1217 case 'r': /* regex */
1696 strncpy(regexp, optarg, MAX_RE_SIZE - 1); 1218 strncpy(result.config.regexp, optarg, MAX_RE_SIZE - 1);
1697 regexp[MAX_RE_SIZE - 1] = 0; 1219 result.config.regexp[MAX_RE_SIZE - 1] = 0;
1698 errcode = regcomp(&preg, regexp, cflags); 1220 regex_t preg;
1221 int errcode = regcomp(&preg, result.config.regexp, cflags);
1699 if (errcode != 0) { 1222 if (errcode != 0) {
1700 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1223 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1701 printf(_("Could Not Compile Regular Expression: %s"), errbuf); 1224 printf(_("Could Not Compile Regular Expression: %s"), errbuf);
1702 return false; 1225 result.errorcode = ERROR;
1226 return result;
1703 } 1227 }
1228
1229 result.config.compiled_regex = preg;
1704 break; 1230 break;
1705 case INVERT_REGEX: 1231 case INVERT_REGEX:
1706 invert_regex = true; 1232 result.config.invert_regex = true;
1707 break; 1233 break;
1708 case STATE_REGEX: 1234 case STATE_REGEX:
1709 if (!strcasecmp(optarg, "critical")) 1235 if (!strcasecmp(optarg, "critical")) {
1710 state_regex = STATE_CRITICAL; 1236 result.config.state_regex = STATE_CRITICAL;
1711 else if (!strcasecmp(optarg, "warning")) 1237 } else if (!strcasecmp(optarg, "warning")) {
1712 state_regex = STATE_WARNING; 1238 result.config.state_regex = STATE_WARNING;
1713 else 1239 } else {
1714 usage2(_("Invalid state-regex option"), optarg); 1240 usage2(_("Invalid state-regex option"), optarg);
1241 }
1715 break; 1242 break;
1716 case '4': 1243 case '4':
1717 address_family = AF_INET; 1244 result.config.curl_config.sin_family = AF_INET;
1718 break; 1245 break;
1719 case '6': 1246 case '6':
1720#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6) 1247#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
1721 address_family = AF_INET6; 1248 result.config.curl_config.sin_family = AF_INET6;
1722#else 1249#else
1723 usage4(_("IPv6 support not available")); 1250 usage4(_("IPv6 support not available"));
1724#endif 1251#endif
1725 break; 1252 break;
1726 case 'm': /* min_page_length */ 1253 case 'm': /* min_page_length */
1727 { 1254 {
1728 char *tmp; 1255 mp_range_parsed foo = mp_parse_range_string(optarg);
1729 if (strchr(optarg, ':') != (char *)NULL) { 1256
1730 /* range, so get two values, min:max */ 1257 if (foo.error != MP_PARSING_SUCCES) {
1731 tmp = strtok(optarg, ":"); 1258 die(STATE_CRITICAL, "failed to parse page size limits: %s", optarg);
1732 if (tmp == NULL) { 1259 }
1733 printf("Bad format: try \"-m min:max\"\n"); 1260
1734 exit(STATE_WARNING); 1261 result.config.page_length_limits = foo.range;
1735 } else 1262 result.config.page_length_limits_is_set = true;
1736 min_page_len = atoi(tmp);
1737
1738 tmp = strtok(NULL, ":");
1739 if (tmp == NULL) {
1740 printf("Bad format: try \"-m min:max\"\n");
1741 exit(STATE_WARNING);
1742 } else
1743 max_page_len = atoi(tmp);
1744 } else
1745 min_page_len = atoi(optarg);
1746 break; 1263 break;
1747 } 1264 }
1748 case 'N': /* no-body */ 1265 case 'N': /* no-body */
1749 no_body = true; 1266 result.config.initial_config.no_body = true;
1750 break; 1267 break;
1751 case 'M': /* max-age */ 1268 case 'M': /* max-age */
1752 { 1269 {
1753 int L = strlen(optarg); 1270 size_t option_length = strlen(optarg);
1754 if (L && optarg[L - 1] == 'm') 1271 if (option_length && optarg[option_length - 1] == 'm') {
1755 maximum_age = atoi(optarg) * 60; 1272 result.config.maximum_age = atoi(optarg) * 60;
1756 else if (L && optarg[L - 1] == 'h') 1273 } else if (option_length && optarg[option_length - 1] == 'h') {
1757 maximum_age = atoi(optarg) * 60 * 60; 1274 result.config.maximum_age = atoi(optarg) * 60 * 60;
1758 else if (L && optarg[L - 1] == 'd') 1275 } else if (option_length && optarg[option_length - 1] == 'd') {
1759 maximum_age = atoi(optarg) * 60 * 60 * 24; 1276 result.config.maximum_age = atoi(optarg) * 60 * 60 * 24;
1760 else if (L && (optarg[L - 1] == 's' || isdigit(optarg[L - 1]))) 1277 } else if (option_length &&
1761 maximum_age = atoi(optarg); 1278 (optarg[option_length - 1] == 's' || isdigit(optarg[option_length - 1]))) {
1762 else { 1279 result.config.maximum_age = atoi(optarg);
1280 } else {
1763 fprintf(stderr, "unparsable max-age: %s\n", optarg); 1281 fprintf(stderr, "unparsable max-age: %s\n", optarg);
1764 exit(STATE_WARNING); 1282 exit(STATE_WARNING);
1765 } 1283 }
1766 if (verbose >= 2) 1284 if (verbose >= 2) {
1767 printf("* Maximal age of document set to %d seconds\n", maximum_age); 1285 printf("* Maximal age of document set to %d seconds\n", result.config.maximum_age);
1286 }
1768 } break; 1287 } break;
1769 case 'E': /* show extended perfdata */ 1288 case 'E': /* show extended perfdata */
1770 show_extended_perfdata = true; 1289 result.config.show_extended_perfdata = true;
1771 break; 1290 break;
1772 case 'B': /* print body content after status line */ 1291 case 'B': /* print body content after status line */
1773 show_body = true; 1292 result.config.show_body = true;
1774 break; 1293 break;
1775 case HTTP_VERSION_OPTION: 1294 case HTTP_VERSION_OPTION:
1776 curl_http_version = CURL_HTTP_VERSION_NONE; 1295 result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_NONE;
1777 if (strcmp(optarg, "1.0") == 0) { 1296 if (strcmp(optarg, "1.0") == 0) {
1778 curl_http_version = CURL_HTTP_VERSION_1_0; 1297 result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_1_0;
1779 } else if (strcmp(optarg, "1.1") == 0) { 1298 } else if (strcmp(optarg, "1.1") == 0) {
1780 curl_http_version = CURL_HTTP_VERSION_1_1; 1299 result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_1_1;
1781 } else if ((strcmp(optarg, "2.0") == 0) || (strcmp(optarg, "2") == 0)) { 1300 } else if ((strcmp(optarg, "2.0") == 0) || (strcmp(optarg, "2") == 0)) {
1782#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) 1301#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
1783 curl_http_version = CURL_HTTP_VERSION_2_0; 1302 result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_2_0;
1784#else 1303#else
1785 curl_http_version = CURL_HTTP_VERSION_NONE; 1304 result.config.curl_http_version = CURL_HTTP_VERSION_NONE;
1786#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */ 1305#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */
1306 } else if ((strcmp(optarg, "3") == 0)) {
1307#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 66, 0)
1308 result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_3;
1309#else
1310 result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_NONE;
1311#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 66, 0) */
1787 } else { 1312 } else {
1788 fprintf(stderr, "unknown http-version parameter: %s\n", optarg); 1313 fprintf(stderr, "unknown http-version parameter: %s\n", optarg);
1789 exit(STATE_WARNING); 1314 exit(STATE_WARNING);
1790 } 1315 }
1791 break; 1316 break;
1792 case AUTOMATIC_DECOMPRESSION: 1317 case AUTOMATIC_DECOMPRESSION:
1793 automatic_decompression = true; 1318 result.config.curl_config.automatic_decompression = true;
1794 break; 1319 break;
1795 case COOKIE_JAR: 1320 case COOKIE_JAR:
1796 cookie_jar_file = optarg; 1321 result.config.curl_config.cookie_jar_file = optarg;
1797 break; 1322 break;
1798 case HAPROXY_PROTOCOL: 1323 case HAPROXY_PROTOCOL:
1799 haproxy_protocol = true; 1324 result.config.curl_config.haproxy_protocol = true;
1800 break; 1325 break;
1801 case '?': 1326 case '?':
1802 /* print short usage statement if args not parsable */ 1327 /* print short usage statement if args not parsable */
1803 usage5(); 1328 usage5();
1804 break; 1329 break;
1330 case OUTPUT_FORMAT: {
1331 parsed_output_format parser = mp_parse_output_format(optarg);
1332 if (!parser.parsing_success) {
1333 // TODO List all available formats here, maybe add anothoer usage function
1334 printf("Invalid output format: %s\n", optarg);
1335 exit(STATE_UNKNOWN);
1336 }
1337
1338 result.config.output_format_is_set = true;
1339 result.config.output_format = parser.output_format;
1340 break;
1341 }
1805 } 1342 }
1806 } 1343 }
1807 1344
1808 c = optind; 1345 if (enable_tls) {
1346 bool got_plus = false;
1347 result.config.initial_config.use_ssl = true;
1348 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default.
1349 * Only set if it's non-zero. This helps when we include multiple
1350 * parameters, like -S and -C combinations */
1351 result.config.curl_config.ssl_version = CURL_SSLVERSION_DEFAULT;
1352 if (tls_option_optarg != NULL) {
1353 char *plus_ptr = strchr(optarg, '+');
1354 if (plus_ptr) {
1355 got_plus = true;
1356 *plus_ptr = '\0';
1357 }
1809 1358
1810 if (server_address == NULL && c < argc) 1359 if (optarg[0] == '2') {
1811 server_address = strdup(argv[c++]); 1360 result.config.curl_config.ssl_version = CURL_SSLVERSION_SSLv2;
1361 } else if (optarg[0] == '3') {
1362 result.config.curl_config.ssl_version = CURL_SSLVERSION_SSLv3;
1363 } else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0")) {
1364#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1365 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_0;
1366#else
1367 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1368#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1369 } else if (!strcmp(optarg, "1.1")) {
1370#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1371 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_1;
1372#else
1373 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1374#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1375 } else if (!strcmp(optarg, "1.2")) {
1376#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1377 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_2;
1378#else
1379 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1380#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1381 } else if (!strcmp(optarg, "1.3")) {
1382#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
1383 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_3;
1384#else
1385 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1386#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */
1387 } else {
1388 usage4(_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 "
1389 "(with optional '+' suffix)"));
1390 }
1391 }
1392#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0)
1393 if (got_plus) {
1394 switch (result.config.curl_config.ssl_version) {
1395 case CURL_SSLVERSION_TLSv1_3:
1396 result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1397 break;
1398 case CURL_SSLVERSION_TLSv1_2:
1399 case CURL_SSLVERSION_TLSv1_1:
1400 case CURL_SSLVERSION_TLSv1_0:
1401 result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_DEFAULT;
1402 break;
1403 }
1404 } else {
1405 switch (result.config.curl_config.ssl_version) {
1406 case CURL_SSLVERSION_TLSv1_3:
1407 result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1408 break;
1409 case CURL_SSLVERSION_TLSv1_2:
1410 result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2;
1411 break;
1412 case CURL_SSLVERSION_TLSv1_1:
1413 result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1;
1414 break;
1415 case CURL_SSLVERSION_TLSv1_0:
1416 result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0;
1417 break;
1418 }
1419 }
1420#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
1421 if (verbose >= 2) {
1422 printf(_("* Set SSL/TLS version to %ld\n"), result.config.curl_config.ssl_version);
1423 }
1424 if (!specify_port) {
1425 result.config.initial_config.serverPort = HTTPS_PORT;
1426 }
1427 }
1812 1428
1813 if (host_name == NULL && c < argc) 1429 int option_counter = optind;
1814 host_name = strdup(argv[c++]);
1815 1430
1816 if (server_address == NULL) { 1431 if (result.config.initial_config.server_address == NULL && option_counter < argc) {
1817 if (host_name == NULL) 1432 result.config.initial_config.server_address = strdup(argv[option_counter++]);
1818 usage4(_("You must specify a server address or host name"));
1819 else
1820 server_address = strdup(host_name);
1821 } 1433 }
1822 1434
1823 set_thresholds(&thlds, warning_thresholds, critical_thresholds); 1435 if (result.config.initial_config.host_name == NULL && option_counter < argc) {
1436 result.config.initial_config.host_name = strdup(argv[option_counter++]);
1437 }
1824 1438
1825 if (critical_thresholds && thlds->critical->end > (double)socket_timeout) 1439 if (result.config.initial_config.server_address == NULL) {
1826 socket_timeout = (int)thlds->critical->end + 1; 1440 if (result.config.initial_config.host_name == NULL) {
1827 if (verbose >= 2) 1441 usage4(_("You must specify a server address or host name"));
1828 printf("* Socket timeout set to %ld seconds\n", socket_timeout); 1442 } else {
1443 result.config.initial_config.server_address =
1444 strdup(result.config.initial_config.host_name);
1445 }
1446 }
1829 1447
1830 if (http_method == NULL) 1448 if (result.config.initial_config.http_method == NULL) {
1831 http_method = strdup("GET"); 1449 result.config.initial_config.http_method = strdup("GET");
1450 }
1832 1451
1833 if (client_cert && !client_privkey) 1452 if (result.config.curl_config.client_cert && !result.config.curl_config.client_privkey) {
1834 usage4(_("If you use a client certificate you must also specify a private key file")); 1453 usage4(_("If you use a client certificate you must also specify a private key file"));
1835
1836 if (virtual_port == 0)
1837 virtual_port = server_port;
1838 else {
1839 if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT))
1840 if (!specify_port)
1841 server_port = virtual_port;
1842 } 1454 }
1843 1455
1844 return true; 1456 if (result.config.initial_config.virtualPort == 0) {
1845} 1457 result.config.initial_config.virtualPort = result.config.initial_config.serverPort;
1846 1458 } else {
1847char *perfd_time(double elapsed_time) { 1459 if ((result.config.initial_config.use_ssl &&
1848 return fperfdata("time", elapsed_time, "s", thlds->warning ? true : false, thlds->warning ? thlds->warning->end : 0, 1460 result.config.initial_config.serverPort == HTTPS_PORT) ||
1849 thlds->critical ? true : false, thlds->critical ? thlds->critical->end : 0, true, 0, true, socket_timeout); 1461 (!result.config.initial_config.use_ssl &&
1850} 1462 result.config.initial_config.serverPort == HTTP_PORT)) {
1851 1463 if (!specify_port) {
1852char *perfd_time_connect(double elapsed_time_connect) { 1464 result.config.initial_config.serverPort = result.config.initial_config.virtualPort;
1853 return fperfdata("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1465 }
1854} 1466 }
1855 1467 }
1856char *perfd_time_ssl(double elapsed_time_ssl) {
1857 return fperfdata("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1858}
1859
1860char *perfd_time_headers(double elapsed_time_headers) {
1861 return fperfdata("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1862}
1863
1864char *perfd_time_firstbyte(double elapsed_time_firstbyte) {
1865 return fperfdata("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1866}
1867
1868char *perfd_time_transfer(double elapsed_time_transfer) {
1869 return fperfdata("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1870}
1871 1468
1872char *perfd_size(int page_len) { 1469 return result;
1873 return perfdata("size", page_len, "B", (min_page_len > 0 ? true : false), min_page_len, (min_page_len > 0 ? true : false), 0, true, 0,
1874 false, 0);
1875} 1470}
1876 1471
1877void print_help(void) { 1472void print_help(void) {
@@ -1885,7 +1480,8 @@ void print_help(void) {
1885 printf("%s\n", _("strings and regular expressions, check connection times, and report on")); 1480 printf("%s\n", _("strings and regular expressions, check connection times, and report on"));
1886 printf("%s\n", _("certificate expiration times.")); 1481 printf("%s\n", _("certificate expiration times."));
1887 printf("\n"); 1482 printf("\n");
1888 printf("%s\n", _("It makes use of libcurl to do so. It tries to be as compatible to check_http")); 1483 printf("%s\n",
1484 _("It makes use of libcurl to do so. It tries to be as compatible to check_http"));
1889 printf("%s\n", _("as possible.")); 1485 printf("%s\n", _("as possible."));
1890 1486
1891 printf("\n\n"); 1487 printf("\n\n");
@@ -1903,7 +1499,10 @@ void print_help(void) {
1903 printf(" %s\n", _("Host name argument for servers using host headers (virtual host)")); 1499 printf(" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1904 printf(" %s\n", _("Append a port to include it in the header (eg: example.com:5000)")); 1500 printf(" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1905 printf(" %s\n", "-I, --IP-address=ADDRESS"); 1501 printf(" %s\n", "-I, --IP-address=ADDRESS");
1906 printf(" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup).")); 1502 printf(" %s\n",
1503 "IP address or name (use numeric address if possible to bypass DNS lookup).");
1504 printf(" %s\n",
1505 "This overwrites the network address of the target while leaving everything else (HTTP headers) as they are");
1907 printf(" %s\n", "-p, --port=INTEGER"); 1506 printf(" %s\n", "-p, --port=INTEGER");
1908 printf(" %s", _("Port number (default: ")); 1507 printf(" %s", _("Port number (default: "));
1909 printf("%d)\n", HTTP_PORT); 1508 printf("%d)\n", HTTP_PORT);
@@ -1912,27 +1511,36 @@ void print_help(void) {
1912 1511
1913#ifdef LIBCURL_FEATURE_SSL 1512#ifdef LIBCURL_FEATURE_SSL
1914 printf(" %s\n", "-S, --ssl=VERSION[+]"); 1513 printf(" %s\n", "-S, --ssl=VERSION[+]");
1915 printf(" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents")); 1514 printf(" %s\n",
1515 _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents"));
1916 printf(" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,")); 1516 printf(" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,"));
1917 printf(" %s\n", _("1.2 = TLSv1.2, 1.3 = TLSv1.3). With a '+' suffix, newer versions are also accepted.")); 1517 printf(" %s\n", _("1.2 = TLSv1.2, 1.3 = TLSv1.3). With a '+' suffix, newer versions are "
1918 printf(" %s\n", _("Note: SSLv2, SSLv3, TLSv1.0 and TLSv1.1 are deprecated and are usually disabled in libcurl")); 1518 "also accepted."));
1519 printf(" %s\n", _("Note: SSLv2, SSLv3, TLSv1.0 and TLSv1.1 are deprecated and are usually "
1520 "disabled in libcurl"));
1919 printf(" %s\n", "--sni"); 1521 printf(" %s\n", "--sni");
1920 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); 1522 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
1921# if LIBCURL_VERSION_NUM >= 0x071801 1523# if LIBCURL_VERSION_NUM >= 0x071801
1922 printf(" %s\n", _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and")); 1524 printf(" %s\n",
1525 _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and"));
1923 printf(" %s\n", _(" SNI only really works since TLSv1.0")); 1526 printf(" %s\n", _(" SNI only really works since TLSv1.0"));
1924# else 1527# else
1925 printf(" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1")); 1528 printf(" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1"));
1926# endif 1529# endif
1927 printf(" %s\n", "-C, --certificate=INTEGER[,INTEGER]"); 1530 printf(" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
1928 printf(" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443.")); 1531 printf(" %s\n",
1929 printf(" %s\n", _("A STATE_WARNING is returned if the certificate has a validity less than the")); 1532 _("Minimum number of days a certificate has to be valid. Port defaults to 443."));
1930 printf(" %s\n", _("first agument's value. If there is a second argument and the certificate's")); 1533 printf(" %s\n",
1534 _("A STATE_WARNING is returned if the certificate has a validity less than the"));
1535 printf(" %s\n",
1536 _("first agument's value. If there is a second argument and the certificate's"));
1931 printf(" %s\n", _("validity is less than its value, a STATE_CRITICAL is returned.")); 1537 printf(" %s\n", _("validity is less than its value, a STATE_CRITICAL is returned."));
1932 printf(" %s\n", _("(When this option is used the URL is not checked by default. You can use")); 1538 printf(" %s\n",
1539 _("(When this option is used the URL is not checked by default. You can use"));
1933 printf(" %s\n", _(" --continue-after-certificate to override this behavior)")); 1540 printf(" %s\n", _(" --continue-after-certificate to override this behavior)"));
1934 printf(" %s\n", "--continue-after-certificate"); 1541 printf(" %s\n", "--continue-after-certificate");
1935 printf(" %s\n", _("Allows the HTTP check to continue after performing the certificate check.")); 1542 printf(" %s\n",
1543 _("Allows the HTTP check to continue after performing the certificate check."));
1936 printf(" %s\n", _("Does nothing unless -C is used.")); 1544 printf(" %s\n", _("Does nothing unless -C is used."));
1937 printf(" %s\n", "-J, --client-cert=FILE"); 1545 printf(" %s\n", "-J, --client-cert=FILE");
1938 printf(" %s\n", _("Name of file that contains the client certificate (PEM format)")); 1546 printf(" %s\n", _("Name of file that contains the client certificate (PEM format)"));
@@ -1950,16 +1558,19 @@ void print_help(void) {
1950 printf(" %s\n", _("Comma-delimited list of strings, at least one of them is expected in")); 1558 printf(" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
1951 printf(" %s", _("the first (status) line of the server response (default: ")); 1559 printf(" %s", _("the first (status) line of the server response (default: "));
1952 printf("%s)\n", HTTP_EXPECT); 1560 printf("%s)\n", HTTP_EXPECT);
1953 printf(" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)")); 1561 printf(" %s\n",
1562 _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1954 printf(" %s\n", "-d, --header-string=STRING"); 1563 printf(" %s\n", "-d, --header-string=STRING");
1955 printf(" %s\n", _("String to expect in the response headers")); 1564 printf(" %s\n", _("String to expect in the response headers"));
1956 printf(" %s\n", "-s, --string=STRING"); 1565 printf(" %s\n", "-s, --string=STRING");
1957 printf(" %s\n", _("String to expect in the content")); 1566 printf(" %s\n", _("String to expect in the content"));
1958 printf(" %s\n", "-u, --url=PATH"); 1567 printf(" %s\n", "-u, --url=PATH");
1959 printf(" %s\n", _("URL to GET or POST (default: /)")); 1568 printf(" %s\n", _("URL to GET or POST (default: /)"));
1569 printf(" %s\n", _("This is the part after the address in a URL, so for \"https://example.com/index.html\" it would be '-u /index.html'"));
1960 printf(" %s\n", "-P, --post=STRING"); 1570 printf(" %s\n", "-P, --post=STRING");
1961 printf(" %s\n", _("URL decoded http POST data")); 1571 printf(" %s\n", _("URL decoded http POST data"));
1962 printf(" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)"); 1572 printf(" %s\n",
1573 "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)");
1963 printf(" %s\n", _("Set HTTP method.")); 1574 printf(" %s\n", _("Set HTTP method."));
1964 printf(" %s\n", "-N, --no-body"); 1575 printf(" %s\n", "-N, --no-body");
1965 printf(" %s\n", _("Don't wait for document body: stop reading after headers.")); 1576 printf(" %s\n", _("Don't wait for document body: stop reading after headers."));
@@ -1968,7 +1579,7 @@ void print_help(void) {
1968 printf(" %s\n", _("Warn if document is more than SECONDS old. the number can also be of")); 1579 printf(" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1969 printf(" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days.")); 1580 printf(" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1970 printf(" %s\n", "-T, --content-type=STRING"); 1581 printf(" %s\n", "-T, --content-type=STRING");
1971 printf(" %s\n", _("specify Content-Type header media type when POSTing\n")); 1582 printf(" %s\n", _("specify Content-Type header media type when POSTing"));
1972 printf(" %s\n", "-l, --linespan"); 1583 printf(" %s\n", "-l, --linespan");
1973 printf(" %s\n", _("Allow regex to span newlines (must precede -r or -R)")); 1584 printf(" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1974 printf(" %s\n", "-r, --regex, --ereg=STRING"); 1585 printf(" %s\n", "-r, --regex, --ereg=STRING");
@@ -1979,7 +1590,8 @@ void print_help(void) {
1979 printf(" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)")); 1590 printf(" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)"));
1980 printf(" %s\n", _("can be changed with --state--regex)")); 1591 printf(" %s\n", _("can be changed with --state--regex)"));
1981 printf(" %s\n", "--state-regex=STATE"); 1592 printf(" %s\n", "--state-regex=STATE");
1982 printf(" %s\n", _("Return STATE if regex is found, OK if not. STATE can be one of \"critical\",\"warning\"")); 1593 printf(" %s\n", _("Return STATE if regex is found, OK if not. STATE can be one of "
1594 "\"critical\",\"warning\""));
1983 printf(" %s\n", "-a, --authorization=AUTH_PAIR"); 1595 printf(" %s\n", "-a, --authorization=AUTH_PAIR");
1984 printf(" %s\n", _("Username:password on sites with basic authentication")); 1596 printf(" %s\n", _("Username:password on sites with basic authentication"));
1985 printf(" %s\n", "-b, --proxy-authorization=AUTH_PAIR"); 1597 printf(" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
@@ -1987,13 +1599,14 @@ void print_help(void) {
1987 printf(" %s\n", "-A, --useragent=STRING"); 1599 printf(" %s\n", "-A, --useragent=STRING");
1988 printf(" %s\n", _("String to be sent in http header as \"User Agent\"")); 1600 printf(" %s\n", _("String to be sent in http header as \"User Agent\""));
1989 printf(" %s\n", "-k, --header=STRING"); 1601 printf(" %s\n", "-k, --header=STRING");
1990 printf(" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers")); 1602 printf(" %s\n", _("Any other tags to be sent in http header. Use multiple times for "
1603 "additional headers"));
1991 printf(" %s\n", "-E, --extended-perfdata"); 1604 printf(" %s\n", "-E, --extended-perfdata");
1992 printf(" %s\n", _("Print additional performance data")); 1605 printf(" %s\n", _("Print additional performance data"));
1993 printf(" %s\n", "-B, --show-body"); 1606 printf(" %s\n", "-B, --show-body");
1994 printf(" %s\n", _("Print body content below status line")); 1607 printf(" %s\n", _("Print body content below status line"));
1995 printf(" %s\n", "-L, --link"); 1608 // printf(" %s\n", "-L, --link");
1996 printf(" %s\n", _("Wrap output in HTML link (obsoleted by urlize)")); 1609 // printf(" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1997 printf(" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport|curl>"); 1610 printf(" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport|curl>");
1998 printf(" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the")); 1611 printf(" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
1999 printf(" %s\n", _("specified IP address. stickyport also ensures port stays the same.")); 1612 printf(" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
@@ -2003,20 +1616,25 @@ void print_help(void) {
2003 printf(" %s", _("Maximal number of redirects (default: ")); 1616 printf(" %s", _("Maximal number of redirects (default: "));
2004 printf("%d)\n", DEFAULT_MAX_REDIRS); 1617 printf("%d)\n", DEFAULT_MAX_REDIRS);
2005 printf(" %s\n", "-m, --pagesize=INTEGER<:INTEGER>"); 1618 printf(" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
2006 printf(" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)")); 1619 printf(" %s\n",
1620 _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
2007 printf("\n"); 1621 printf("\n");
2008 printf(" %s\n", "--http-version=VERSION"); 1622 printf(" %s\n", "--http-version=VERSION");
2009 printf(" %s\n", _("Connect via specific HTTP protocol.")); 1623 printf(" %s\n", _("Connect via specific HTTP protocol."));
2010 printf(" %s\n", _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)")); 1624 printf(" %s\n",
1625 _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)"));
2011 printf(" %s\n", "--enable-automatic-decompression"); 1626 printf(" %s\n", "--enable-automatic-decompression");
2012 printf(" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING).")); 1627 printf(" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING)."));
2013 printf(" %s\n", "--haproxy-protocol"); 1628 printf(" %s\n", "--haproxy-protocol");
2014 printf(" %s\n", _("Send HAProxy proxy protocol v1 header (CURLOPT_HAPROXYPROTOCOL).")); 1629 printf(" %s\n", _("Send HAProxy proxy protocol v1 header (CURLOPT_HAPROXYPROTOCOL)."));
2015 printf(" %s\n", "--cookie-jar=FILE"); 1630 printf(" %s\n", "--cookie-jar=FILE");
2016 printf(" %s\n", _("Store cookies in the cookie jar and send them out when requested.")); 1631 printf(" %s\n", _("Store cookies in the cookie jar and send them out when requested."));
2017 printf(" %s\n", _("Specify an empty string as FILE to enable curl's cookie engine without saving")); 1632 printf(" %s\n",
2018 printf(" %s\n", _("the cookies to disk. Only enabling the engine without saving to disk requires")); 1633 _("Specify an empty string as FILE to enable curl's cookie engine without saving"));
2019 printf(" %s\n", _("handling multiple requests internally to curl, so use it with --onredirect=curl")); 1634 printf(" %s\n",
1635 _("the cookies to disk. Only enabling the engine without saving to disk requires"));
1636 printf(" %s\n",
1637 _("handling multiple requests internally to curl, so use it with --onredirect=curl"));
2020 printf("\n"); 1638 printf("\n");
2021 1639
2022 printf(UT_WARN_CRIT); 1640 printf(UT_WARN_CRIT);
@@ -2025,13 +1643,18 @@ void print_help(void) {
2025 1643
2026 printf(UT_VERBOSE); 1644 printf(UT_VERBOSE);
2027 1645
1646 printf(UT_OUTPUT_FORMAT);
1647
2028 printf("\n"); 1648 printf("\n");
2029 printf("%s\n", _("Notes:")); 1649 printf("%s\n", _("Notes:"));
2030 printf(" %s\n", _("This plugin will attempt to open an HTTP connection with the host.")); 1650 printf(" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
2031 printf(" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL")); 1651 printf(" %s\n",
2032 printf(" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response")); 1652 _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1653 printf(" %s\n",
1654 _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response"));
2033 printf(" %s\n", _("messages from the host result in STATE_WARNING return values. If you are")); 1655 printf(" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
2034 printf(" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN")); 1656 printf(" %s\n",
1657 _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
2035 printf(" %s\n", _("(fully qualified domain name) as the [host_name] argument.")); 1658 printf(" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
2036 1659
2037#ifdef LIBCURL_FEATURE_SSL 1660#ifdef LIBCURL_FEATURE_SSL
@@ -2044,41 +1667,60 @@ void print_help(void) {
2044 printf(" %s\n", _("certificate matches the hostname of the server, or if the certificate")); 1667 printf(" %s\n", _("certificate matches the hostname of the server, or if the certificate"));
2045 printf(" %s\n", _("has a valid chain of trust to one of the locally installed CAs.")); 1668 printf(" %s\n", _("has a valid chain of trust to one of the locally installed CAs."));
2046 printf("\n"); 1669 printf("\n");
1670 printf(" %s\n", _("To also verify certificates, please set --verify-cert."));
1671 printf("\n");
2047 printf("%s\n", _("Examples:")); 1672 printf("%s\n", _("Examples:"));
2048 printf(" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com"); 1673 printf(" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com");
2049 printf(" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,")); 1674 printf(" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
2050 printf(" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 1675 printf(" %s\n",
2051 printf(" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 1676 _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1677 printf(" %s\n",
1678 _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
2052 printf(" %s\n", _("a STATE_CRITICAL will be returned.")); 1679 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
2053 printf("\n"); 1680 printf("\n");
2054 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14"); 1681 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14 -D");
2055 printf(" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,")); 1682 printf(" %s\n",
2056 printf(" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 1683 _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
2057 printf(" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when")); 1684 printf(" %s\n",
2058 printf(" %s\n\n", _("the certificate is expired.")); 1685 _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1686 printf(" %s\n",
1687 _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1688 printf(" %s\n", _("the certificate is expired."));
1689 printf("\n");
1690 printf(" %s\n", _("The -D flag enforces a certificate validation beyond expiration time."));
2059 printf("\n"); 1691 printf("\n");
2060 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14"); 1692 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14 -D");
2061 printf(" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 30 days,")); 1693 printf(" %s\n",
2062 printf(" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 1694 _("When the certificate of 'www.verisign.com' is valid for more than 30 days,"));
1695 printf(" %s\n",
1696 _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
2063 printf(" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned.")); 1697 printf(" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned."));
2064 printf(" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days")); 1698 printf(" %s\n",
1699 _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days"));
2065#endif 1700#endif
2066 1701
2067 printf("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:"); 1702 printf("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:");
2068 printf(" %s\n", _("It is recommended to use an environment proxy like:")); 1703 printf(" %s\n", _("It is recommended to use an environment proxy like:"));
2069 printf(" %s\n", _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org")); 1704 printf(" %s\n",
1705 _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org"));
2070 printf(" %s\n", _("legacy proxy requests in check_http style still work:")); 1706 printf(" %s\n", _("legacy proxy requests in check_http style still work:"));
2071 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ -H www.monitoring-plugins.org")); 1707 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ "
1708 "-H www.monitoring-plugins.org"));
2072 1709
2073#ifdef LIBCURL_FEATURE_SSL 1710#ifdef LIBCURL_FEATURE_SSL
2074 printf("\n %s\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: "); 1711 printf("\n %s\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: ");
2075 printf(" %s\n", _("It is recommended to use an environment proxy like:")); 1712 printf(" %s\n", _("It is recommended to use an environment proxy like:"));
2076 printf(" %s\n", _("https_proxy=http://192.168.100.35:3128 ./check_curl -H www.verisign.com -S")); 1713 printf(" %s\n",
2077 printf(" %s\n", _("legacy proxy requests in check_http style still work:")); 1714 _("https_proxy=http://192.168.100.35:3128 ./check_curl -H www.verisign.com -S"));
2078 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com ")); 1715 printf(" %s\n", _("legacy proxy requests in check_http style might still work, but are frowned upon, so DONT:"));
2079 printf(" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>")); 1716 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u https://www.verisign.com/ -S -j "
2080 printf(" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 1717 "CONNECT -H www.verisign.com "));
2081 printf(" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 1718 printf(" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> "
1719 "-S(sl) -j CONNECT -H <webserver>"));
1720 printf(" %s\n",
1721 _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1722 printf(" %s\n",
1723 _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
2082 printf(" %s\n", _("a STATE_CRITICAL will be returned.")); 1724 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
2083 1725
2084#endif 1726#endif
@@ -2089,10 +1731,12 @@ void print_help(void) {
2089void print_usage(void) { 1731void print_usage(void) {
2090 printf("%s\n", _("Usage:")); 1732 printf("%s\n", _("Usage:"));
2091 printf(" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n", progname); 1733 printf(" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n", progname);
2092 printf(" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>] [-D]\n"); 1734 printf(" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate "
1735 "file>] [-D]\n");
2093 printf(" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n"); 1736 printf(" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
2094 printf(" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n"); 1737 printf(" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n");
2095 printf(" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n"); 1738 printf(" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive "
1739 "regex>]\n");
2096 printf(" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n"); 1740 printf(" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
2097 printf(" [-A string] [-k string] [-S <version>] [--sni] [--haproxy-protocol]\n"); 1741 printf(" [-A string] [-k string] [-S <version>] [--sni] [--haproxy-protocol]\n");
2098 printf(" [-T <content-type>] [-j method]\n"); 1742 printf(" [-T <content-type>] [-j method]\n");
@@ -2109,435 +1753,49 @@ void print_usage(void) {
2109 1753
2110void print_curl_version(void) { printf("%s\n", curl_version()); } 1754void print_curl_version(void) { printf("%s\n", curl_version()); }
2111 1755
2112int curlhelp_initwritebuffer(curlhelp_write_curlbuf *buf) {
2113 buf->bufsize = DEFAULT_BUFFER_SIZE;
2114 buf->buflen = 0;
2115 buf->buf = (char *)malloc((size_t)buf->bufsize);
2116 if (buf->buf == NULL)
2117 return -1;
2118 return 0;
2119}
2120
2121size_t curlhelp_buffer_write_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
2122 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream;
2123
2124 while (buf->bufsize < buf->buflen + size * nmemb + 1) {
2125 buf->bufsize = buf->bufsize * 2;
2126 buf->buf = (char *)realloc(buf->buf, buf->bufsize);
2127 if (buf->buf == NULL) {
2128 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno));
2129 return -1;
2130 }
2131 }
2132
2133 memcpy(buf->buf + buf->buflen, buffer, size * nmemb);
2134 buf->buflen += size * nmemb;
2135 buf->buf[buf->buflen] = '\0';
2136
2137 return (int)(size * nmemb);
2138}
2139
2140size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
2141 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream;
2142
2143 size_t n = min(nmemb * size, buf->buflen - buf->pos);
2144
2145 memcpy(buffer, buf->buf + buf->pos, n);
2146 buf->pos += n;
2147
2148 return (int)n;
2149}
2150
2151void curlhelp_freewritebuffer(curlhelp_write_curlbuf *buf) {
2152 free(buf->buf);
2153 buf->buf = NULL;
2154}
2155
2156int curlhelp_initreadbuffer(curlhelp_read_curlbuf *buf, const char *data, size_t datalen) {
2157 buf->buflen = datalen;
2158 buf->buf = (char *)malloc((size_t)buf->buflen);
2159 if (buf->buf == NULL)
2160 return -1;
2161 memcpy(buf->buf, data, datalen);
2162 buf->pos = 0;
2163 return 0;
2164}
2165
2166void curlhelp_freereadbuffer(curlhelp_read_curlbuf *buf) {
2167 free(buf->buf);
2168 buf->buf = NULL;
2169}
2170
2171/* TODO: where to put this, it's actually part of sstrings2 (logically)?
2172 */
2173const char *strrstr2(const char *haystack, const char *needle) {
2174 int counter;
2175 size_t len;
2176 const char *prev_pos;
2177 const char *pos;
2178
2179 if (haystack == NULL || needle == NULL)
2180 return NULL;
2181
2182 if (haystack[0] == '\0' || needle[0] == '\0')
2183 return NULL;
2184
2185 counter = 0;
2186 prev_pos = NULL;
2187 pos = haystack;
2188 len = strlen(needle);
2189 for (;;) {
2190 pos = strstr(pos, needle);
2191 if (pos == NULL) {
2192 if (counter == 0)
2193 return NULL;
2194 return prev_pos;
2195 }
2196 counter++;
2197 prev_pos = pos;
2198 pos += len;
2199 if (*pos == '\0')
2200 return prev_pos;
2201 }
2202}
2203
2204int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) {
2205 char *first_line_end;
2206 char *p;
2207 size_t first_line_len;
2208 char *pp;
2209 const char *start;
2210 char *first_line_buf;
2211
2212 /* find last start of a new header */
2213 start = strrstr2(buf, "\r\nHTTP/");
2214 if (start != NULL) {
2215 start += 2;
2216 buf = start;
2217 }
2218
2219 first_line_end = strstr(buf, "\r\n");
2220 if (first_line_end == NULL)
2221 return -1;
2222
2223 first_line_len = (size_t)(first_line_end - buf);
2224 status_line->first_line = (char *)malloc(first_line_len + 1);
2225 if (status_line->first_line == NULL)
2226 return -1;
2227 memcpy(status_line->first_line, buf, first_line_len);
2228 status_line->first_line[first_line_len] = '\0';
2229 first_line_buf = strdup(status_line->first_line);
2230
2231 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */
2232
2233 p = strtok(first_line_buf, "/");
2234 if (p == NULL) {
2235 free(first_line_buf);
2236 return -1;
2237 }
2238 if (strcmp(p, "HTTP") != 0) {
2239 free(first_line_buf);
2240 return -1;
2241 }
2242
2243 p = strtok(NULL, " ");
2244 if (p == NULL) {
2245 free(first_line_buf);
2246 return -1;
2247 }
2248 if (strchr(p, '.') != NULL) {
2249
2250 /* HTTP 1.x case */
2251 strtok(p, ".");
2252 status_line->http_major = (int)strtol(p, &pp, 10);
2253 if (*pp != '\0') {
2254 free(first_line_buf);
2255 return -1;
2256 }
2257 strtok(NULL, " ");
2258 status_line->http_minor = (int)strtol(p, &pp, 10);
2259 if (*pp != '\0') {
2260 free(first_line_buf);
2261 return -1;
2262 }
2263 p += 4; /* 1.x SP */
2264 } else {
2265 /* HTTP 2 case */
2266 status_line->http_major = (int)strtol(p, &pp, 10);
2267 status_line->http_minor = 0;
2268 p += 2; /* 2 SP */
2269 }
2270
2271 /* status code: "404" or "404.1", then SP */
2272
2273 p = strtok(p, " ");
2274 if (p == NULL) {
2275 free(first_line_buf);
2276 return -1;
2277 }
2278 if (strchr(p, '.') != NULL) {
2279 char *ppp;
2280 ppp = strtok(p, ".");
2281 status_line->http_code = (int)strtol(ppp, &pp, 10);
2282 if (*pp != '\0') {
2283 free(first_line_buf);
2284 return -1;
2285 }
2286 ppp = strtok(NULL, "");
2287 status_line->http_subcode = (int)strtol(ppp, &pp, 10);
2288 if (*pp != '\0') {
2289 free(first_line_buf);
2290 return -1;
2291 }
2292 p += 6; /* 400.1 SP */
2293 } else {
2294 status_line->http_code = (int)strtol(p, &pp, 10);
2295 status_line->http_subcode = -1;
2296 if (*pp != '\0') {
2297 free(first_line_buf);
2298 return -1;
2299 }
2300 p += 4; /* 400 SP */
2301 }
2302
2303 /* Human readable message: "Not Found" CRLF */
2304
2305 p = strtok(p, "");
2306 if (p == NULL) {
2307 status_line->msg = "";
2308 return 0;
2309 }
2310 status_line->msg = status_line->first_line + (p - first_line_buf);
2311 free(first_line_buf);
2312
2313 return 0;
2314}
2315
2316void curlhelp_free_statusline(curlhelp_statusline *status_line) { free(status_line->first_line); }
2317
2318char *get_header_value(const struct phr_header *headers, const size_t nof_headers, const char *header) {
2319 for (size_t i = 0; i < nof_headers; i++) {
2320 if (headers[i].name != NULL && strncasecmp(header, headers[i].name, max(headers[i].name_len, 4)) == 0) {
2321 return strndup(headers[i].value, headers[i].value_len);
2322 }
2323 }
2324 return NULL;
2325}
2326
2327int check_document_dates(const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE]) {
2328 char *server_date = NULL;
2329 char *document_date = NULL;
2330 int date_result = STATE_OK;
2331 curlhelp_statusline status_line;
2332 struct phr_header headers[255];
2333 size_t nof_headers = 255;
2334 size_t msglen;
2335
2336 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
2337 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
2338
2339 if (res == -1) {
2340 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2341 }
2342
2343 server_date = get_header_value(headers, nof_headers, "date");
2344 document_date = get_header_value(headers, nof_headers, "last-modified");
2345
2346 if (!server_date || !*server_date) {
2347 char tmp[DEFAULT_BUFFER_SIZE];
2348
2349 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sServer date unknown, "), *msg);
2350 strcpy(*msg, tmp);
2351
2352 date_result = max_state_alt(STATE_UNKNOWN, date_result);
2353
2354 } else if (!document_date || !*document_date) {
2355 char tmp[DEFAULT_BUFFER_SIZE];
2356
2357 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument modification date unknown, "), *msg);
2358 strcpy(*msg, tmp);
2359
2360 date_result = max_state_alt(STATE_CRITICAL, date_result);
2361
2362 } else {
2363 time_t srv_data = curl_getdate(server_date, NULL);
2364 time_t doc_data = curl_getdate(document_date, NULL);
2365 if (verbose >= 2)
2366 printf("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data);
2367 if (srv_data <= 0) {
2368 char tmp[DEFAULT_BUFFER_SIZE];
2369
2370 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg, server_date);
2371 strcpy(*msg, tmp);
2372
2373 date_result = max_state_alt(STATE_CRITICAL, date_result);
2374 } else if (doc_data <= 0) {
2375 char tmp[DEFAULT_BUFFER_SIZE];
2376
2377 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date);
2378 strcpy(*msg, tmp);
2379
2380 date_result = max_state_alt(STATE_CRITICAL, date_result);
2381 } else if (doc_data > srv_data + 30) {
2382 char tmp[DEFAULT_BUFFER_SIZE];
2383
2384 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data);
2385 strcpy(*msg, tmp);
2386
2387 date_result = max_state_alt(STATE_CRITICAL, date_result);
2388 } else if (doc_data < srv_data - maximum_age) {
2389 int n = (srv_data - doc_data);
2390 if (n > (60 * 60 * 24 * 2)) {
2391 char tmp[DEFAULT_BUFFER_SIZE];
2392
2393 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg, ((float)n) / (60 * 60 * 24));
2394 strcpy(*msg, tmp);
2395
2396 date_result = max_state_alt(STATE_CRITICAL, date_result);
2397 } else {
2398 char tmp[DEFAULT_BUFFER_SIZE];
2399
2400 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60);
2401 strcpy(*msg, tmp);
2402
2403 date_result = max_state_alt(STATE_CRITICAL, date_result);
2404 }
2405 }
2406 }
2407
2408 if (server_date)
2409 free(server_date);
2410 if (document_date)
2411 free(document_date);
2412
2413 return date_result;
2414}
2415
2416int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_write_curlbuf *body_buf) {
2417 size_t content_length = 0;
2418 struct phr_header headers[255];
2419 size_t nof_headers = 255;
2420 size_t msglen;
2421 char *content_length_s = NULL;
2422 curlhelp_statusline status_line;
2423
2424 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
2425 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
2426
2427 if (res == -1) {
2428 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2429 }
2430
2431 content_length_s = get_header_value(headers, nof_headers, "content-length");
2432 if (!content_length_s) {
2433 return header_buf->buflen + body_buf->buflen;
2434 }
2435 content_length_s += strspn(content_length_s, " \t");
2436 content_length = atoi(content_length_s);
2437 if (content_length != body_buf->buflen) {
2438 /* TODO: should we warn if the actual and the reported body length don't match? */
2439 }
2440
2441 if (content_length_s)
2442 free(content_length_s);
2443
2444 return header_buf->buflen + body_buf->buflen;
2445}
2446
2447/* TODO: is there a better way in libcurl to check for the SSL library? */
2448curlhelp_ssl_library curlhelp_get_ssl_library(void) {
2449 curl_version_info_data *version_data;
2450 char *ssl_version;
2451 char *library;
2452 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
2453
2454 version_data = curl_version_info(CURLVERSION_NOW);
2455 if (version_data == NULL)
2456 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2457
2458 ssl_version = strdup(version_data->ssl_version);
2459 if (ssl_version == NULL)
2460 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2461
2462 library = strtok(ssl_version, "/");
2463 if (library == NULL)
2464 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2465
2466 if (strcmp(library, "OpenSSL") == 0)
2467 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL;
2468 else if (strcmp(library, "LibreSSL") == 0)
2469 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL;
2470 else if (strcmp(library, "GnuTLS") == 0)
2471 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS;
2472 else if (strcmp(library, "NSS") == 0)
2473 ssl_library = CURLHELP_SSL_LIBRARY_NSS;
2474
2475 if (verbose >= 2)
2476 printf("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library);
2477
2478 free(ssl_version);
2479
2480 return ssl_library;
2481}
2482
2483const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library ssl_library) {
2484 switch (ssl_library) {
2485 case CURLHELP_SSL_LIBRARY_OPENSSL:
2486 return "OpenSSL";
2487 case CURLHELP_SSL_LIBRARY_LIBRESSL:
2488 return "LibreSSL";
2489 case CURLHELP_SSL_LIBRARY_GNUTLS:
2490 return "GnuTLS";
2491 case CURLHELP_SSL_LIBRARY_NSS:
2492 return "NSS";
2493 case CURLHELP_SSL_LIBRARY_UNKNOWN:
2494 default:
2495 return "unknown";
2496 }
2497}
2498
2499#ifdef LIBCURL_FEATURE_SSL 1756#ifdef LIBCURL_FEATURE_SSL
2500# ifndef USE_OPENSSL 1757# ifndef USE_OPENSSL
2501time_t parse_cert_date(const char *s) { 1758time_t parse_cert_date(const char *s) {
2502 struct tm tm; 1759 if (!s) {
2503 time_t date;
2504 char *res;
2505
2506 if (!s)
2507 return -1; 1760 return -1;
1761 }
2508 1762
2509 /* Jan 17 14:25:12 2020 GMT */ 1763 /* Jan 17 14:25:12 2020 GMT */
2510 res = strptime(s, "%Y-%m-%d %H:%M:%S GMT", &tm); 1764 struct tm tm;
1765 char *res = strptime(s, "%Y-%m-%d %H:%M:%S GMT", &tm);
2511 /* Sep 11 12:00:00 2020 GMT */ 1766 /* Sep 11 12:00:00 2020 GMT */
2512 if (res == NULL) 1767 if (res == NULL) {
2513 strptime(s, "%Y %m %d %H:%M:%S GMT", &tm); 1768 strptime(s, "%Y %m %d %H:%M:%S GMT", &tm);
2514 date = mktime(&tm); 1769 }
1770 time_t date = mktime(&tm);
2515 1771
2516 return date; 1772 return date;
2517} 1773}
1774# endif /* USE_OPENSSL */
1775#endif /* LIBCURL_FEATURE_SSL */
2518 1776
1777#ifdef LIBCURL_FEATURE_SSL
1778# ifndef USE_OPENSSL
2519/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to 1779/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to
2520 * OpenSSL could be this function 1780 * OpenSSL could be this function
2521 */ 1781 */
2522int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_warn, int days_till_exp_crit) { 1782int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_warn,
2523 int i; 1783 int days_till_exp_crit) {
2524 struct curl_slist *slist;
2525 int cname_found = 0;
2526 char *start_date_str = NULL;
2527 char *end_date_str = NULL;
2528 time_t start_date;
2529 time_t end_date;
2530 char *tz;
2531 float time_left;
2532 int days_left;
2533 int time_remaining;
2534 char timestamp[50] = "";
2535 int status = STATE_UNKNOWN;
2536 1784
2537 if (verbose >= 2) 1785 if (verbose >= 2) {
2538 printf("**** REQUEST CERTIFICATES ****\n"); 1786 printf("**** REQUEST CERTIFICATES ****\n");
1787 }
1788
1789 char *start_date_str = NULL;
1790 char *end_date_str = NULL;
1791 bool have_first_cert = false;
1792 bool cname_found = false;
1793 for (int i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) {
1794 if (have_first_cert) {
1795 break;
1796 }
2539 1797
2540 for (i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) { 1798 struct curl_slist *slist;
2541 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) { 1799 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) {
2542 /* find first common name in subject, 1800 /* find first common name in subject,
2543 * TODO: check alternative subjects for 1801 * TODO: check alternative subjects for
@@ -2553,7 +1811,7 @@ int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_
2553 } 1811 }
2554 if (p != NULL) { 1812 if (p != NULL) {
2555 if (strncmp(host_name, p + d, strlen(host_name)) == 0) { 1813 if (strncmp(host_name, p + d, strlen(host_name)) == 0) {
2556 cname_found = 1; 1814 cname_found = true;
2557 } 1815 }
2558 } 1816 }
2559 } else if (strncasecmp(slist->data, "Start Date:", 11) == 0) { 1817 } else if (strncasecmp(slist->data, "Start Date:", 11) == 0) {
@@ -2561,78 +1819,93 @@ int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_
2561 } else if (strncasecmp(slist->data, "Expire Date:", 12) == 0) { 1819 } else if (strncasecmp(slist->data, "Expire Date:", 12) == 0) {
2562 end_date_str = &slist->data[12]; 1820 end_date_str = &slist->data[12];
2563 } else if (strncasecmp(slist->data, "Cert:", 5) == 0) { 1821 } else if (strncasecmp(slist->data, "Cert:", 5) == 0) {
2564 goto HAVE_FIRST_CERT; 1822 have_first_cert = true;
1823 break;
2565 } 1824 }
2566 if (verbose >= 2) 1825 if (verbose >= 2) {
2567 printf("%d ** %s\n", i, slist->data); 1826 printf("%d ** %s\n", i, slist->data);
1827 }
2568 } 1828 }
2569 } 1829 }
2570HAVE_FIRST_CERT:
2571 1830
2572 if (verbose >= 2) 1831 if (verbose >= 2) {
2573 printf("**** REQUEST CERTIFICATES ****\n"); 1832 printf("**** REQUEST CERTIFICATES ****\n");
1833 }
2574 1834
2575 if (!cname_found) { 1835 if (!cname_found) {
2576 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject.")); 1836 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject."));
2577 return STATE_CRITICAL; 1837 return STATE_CRITICAL;
2578 } 1838 }
2579 1839
2580 start_date = parse_cert_date(start_date_str); 1840 time_t start_date = parse_cert_date(start_date_str);
2581 if (start_date <= 0) { 1841 if (start_date <= 0) {
2582 snprintf(msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Start Date' in certificate: '%s'"), start_date_str); 1842 snprintf(msg, DEFAULT_BUFFER_SIZE,
1843 _("WARNING - Unparsable 'Start Date' in certificate: '%s'"), start_date_str);
2583 puts(msg); 1844 puts(msg);
2584 return STATE_WARNING; 1845 return STATE_WARNING;
2585 } 1846 }
2586 1847
2587 end_date = parse_cert_date(end_date_str); 1848 time_t end_date = parse_cert_date(end_date_str);
2588 if (end_date <= 0) { 1849 if (end_date <= 0) {
2589 snprintf(msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"), start_date_str); 1850 snprintf(msg, DEFAULT_BUFFER_SIZE,
1851 _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"), start_date_str);
2590 puts(msg); 1852 puts(msg);
2591 return STATE_WARNING; 1853 return STATE_WARNING;
2592 } 1854 }
2593 1855
2594 time_left = difftime(end_date, time(NULL)); 1856 float time_left = difftime(end_date, time(NULL));
2595 days_left = time_left / 86400; 1857 int days_left = time_left / 86400;
2596 tz = getenv("TZ"); 1858 char *tz = getenv("TZ");
2597 setenv("TZ", "GMT", 1); 1859 setenv("TZ", "GMT", 1);
2598 tzset(); 1860 tzset();
1861
1862 char timestamp[50] = "";
2599 strftime(timestamp, 50, "%c %z", localtime(&end_date)); 1863 strftime(timestamp, 50, "%c %z", localtime(&end_date));
2600 if (tz) 1864 if (tz) {
2601 setenv("TZ", tz, 1); 1865 setenv("TZ", tz, 1);
2602 else 1866 } else {
2603 unsetenv("TZ"); 1867 unsetenv("TZ");
1868 }
2604 tzset(); 1869 tzset();
2605 1870
1871 mp_state_enum status = STATE_UNKNOWN;
1872 int time_remaining;
2606 if (days_left > 0 && days_left <= days_till_exp_warn) { 1873 if (days_left > 0 && days_left <= days_till_exp_warn) {
2607 printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", 1874 printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"),
2608 host_name, days_left, timestamp); 1875 (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, days_left,
2609 if (days_left > days_till_exp_crit) 1876 timestamp);
1877 if (days_left > days_till_exp_crit) {
2610 status = STATE_WARNING; 1878 status = STATE_WARNING;
2611 else 1879 } else {
2612 status = STATE_CRITICAL; 1880 status = STATE_CRITICAL;
1881 }
2613 } else if (days_left == 0 && time_left > 0) { 1882 } else if (days_left == 0 && time_left > 0) {
2614 if (time_left >= 3600) 1883 if (time_left >= 3600) {
2615 time_remaining = (int)time_left / 3600; 1884 time_remaining = (int)time_left / 3600;
2616 else 1885 } else {
2617 time_remaining = (int)time_left / 60; 1886 time_remaining = (int)time_left / 60;
1887 }
2618 1888
2619 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, 1889 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"),
2620 time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp); 1890 (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, time_remaining,
1891 time_left >= 3600 ? "hours" : "minutes", timestamp);
2621 1892
2622 if (days_left > days_till_exp_crit) 1893 if (days_left > days_till_exp_crit) {
2623 status = STATE_WARNING; 1894 status = STATE_WARNING;
2624 else 1895 } else {
2625 status = STATE_CRITICAL; 1896 status = STATE_CRITICAL;
1897 }
2626 } else if (time_left < 0) { 1898 } else if (time_left < 0) {
2627 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp); 1899 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp);
2628 status = STATE_CRITICAL; 1900 status = STATE_CRITICAL;
2629 } else if (days_left == 0) { 1901 } else if (days_left == 0) {
2630 printf(_("%s - Certificate '%s' just expired (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, 1902 printf(_("%s - Certificate '%s' just expired (%s).\n"),
2631 timestamp); 1903 (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, timestamp);
2632 if (days_left > days_till_exp_crit) 1904 if (days_left > days_till_exp_crit) {
2633 status = STATE_WARNING; 1905 status = STATE_WARNING;
2634 else 1906 } else {
2635 status = STATE_CRITICAL; 1907 status = STATE_CRITICAL;
1908 }
2636 } else { 1909 } else {
2637 printf(_("OK - Certificate '%s' will expire on %s.\n"), host_name, timestamp); 1910 printf(_("OK - Certificate '%s' will expire on %s.\n"), host_name, timestamp);
2638 status = STATE_OK; 1911 status = STATE_OK;
diff --git a/plugins/check_curl.d/check_curl_helpers.c b/plugins/check_curl.d/check_curl_helpers.c
new file mode 100644
index 00000000..7be781fc
--- /dev/null
+++ b/plugins/check_curl.d/check_curl_helpers.c
@@ -0,0 +1,1297 @@
1#include "./check_curl_helpers.h"
2#include <stdbool.h>
3#include <arpa/inet.h>
4#include <netinet/in.h>
5#include <netdb.h>
6#include <stdlib.h>
7#include <string.h>
8#include "../utils.h"
9#include "check_curl.d/config.h"
10#include "output.h"
11#include "perfdata.h"
12#include "states.h"
13
14extern int verbose;
15char errbuf[MAX_INPUT_BUFFER];
16bool is_openssl_callback = false;
17bool add_sslctx_verify_fun = false;
18
19check_curl_configure_curl_wrapper
20check_curl_configure_curl(const check_curl_static_curl_config config,
21 check_curl_working_state working_state, bool check_cert,
22 bool on_redirect_dependent, int follow_method, long max_depth) {
23 check_curl_configure_curl_wrapper result = {
24 .errorcode = OK,
25 .curl_state =
26 {
27 .curl_global_initialized = false,
28 .curl_easy_initialized = false,
29 .curl = NULL,
30
31 .body_buf_initialized = false,
32 .body_buf = NULL,
33 .header_buf_initialized = false,
34 .header_buf = NULL,
35 .status_line_initialized = false,
36 .status_line = NULL,
37 .put_buf_initialized = false,
38 .put_buf = NULL,
39
40 .header_list = NULL,
41 .host = NULL,
42 },
43 };
44
45 if ((result.curl_state.status_line = calloc(1, sizeof(curlhelp_statusline))) == NULL) {
46 die(STATE_UNKNOWN, "HTTP UNKNOWN - allocation of statusline failed\n");
47 }
48
49 if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) {
50 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n");
51 }
52 result.curl_state.curl_global_initialized = true;
53
54 if ((result.curl_state.curl = curl_easy_init()) == NULL) {
55 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n");
56 }
57 result.curl_state.curl_easy_initialized = true;
58
59 if (verbose >= 1) {
60 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_VERBOSE, 1L),
61 "CURLOPT_VERBOSE");
62 }
63
64 /* print everything on stdout like check_http would do */
65 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_STDERR, stdout),
66 "CURLOPT_STDERR");
67
68 if (config.automatic_decompression) {
69#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6)
70 handle_curl_option_return_code(
71 curl_easy_setopt(result.curl_state.curl, CURLOPT_ACCEPT_ENCODING, ""),
72 "CURLOPT_ACCEPT_ENCODING");
73#else
74 handle_curl_option_return_code(
75 curl_easy_setopt(result.curl_state.curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING");
76#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */
77 }
78
79 /* initialize buffer for body of the answer */
80 if (curlhelp_initwritebuffer(&result.curl_state.body_buf) < 0) {
81 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
82 }
83 result.curl_state.body_buf_initialized = true;
84
85 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_WRITEFUNCTION,
86 curlhelp_buffer_write_callback),
87 "CURLOPT_WRITEFUNCTION");
88 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_WRITEDATA,
89 (void *)result.curl_state.body_buf),
90 "CURLOPT_WRITEDATA");
91
92 /* initialize buffer for header of the answer */
93 if (curlhelp_initwritebuffer(&result.curl_state.header_buf) < 0) {
94 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n");
95 }
96 result.curl_state.header_buf_initialized = true;
97
98 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_HEADERFUNCTION,
99 curlhelp_buffer_write_callback),
100 "CURLOPT_HEADERFUNCTION");
101 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_WRITEHEADER,
102 (void *)result.curl_state.header_buf),
103 "CURLOPT_WRITEHEADER");
104
105 /* set the error buffer */
106 handle_curl_option_return_code(
107 curl_easy_setopt(result.curl_state.curl, CURLOPT_ERRORBUFFER, errbuf),
108 "CURLOPT_ERRORBUFFER");
109
110 /* set timeouts */
111 handle_curl_option_return_code(
112 curl_easy_setopt(result.curl_state.curl, CURLOPT_CONNECTTIMEOUT, config.socket_timeout),
113 "CURLOPT_CONNECTTIMEOUT");
114
115 handle_curl_option_return_code(
116 curl_easy_setopt(result.curl_state.curl, CURLOPT_TIMEOUT, config.socket_timeout),
117 "CURLOPT_TIMEOUT");
118
119 /* enable haproxy protocol */
120 if (config.haproxy_protocol) {
121 handle_curl_option_return_code(
122 curl_easy_setopt(result.curl_state.curl, CURLOPT_HAPROXYPROTOCOL, 1L),
123 "CURLOPT_HAPROXYPROTOCOL");
124 }
125
126 // fill dns resolve cache to make curl connect to the given server_address instead of the
127 // host_name, only required for ssl, because we use the host_name later on to make SNI happy
128 char dnscache[DEFAULT_BUFFER_SIZE];
129 char addrstr[DEFAULT_BUFFER_SIZE / 2];
130 if (working_state.use_ssl && working_state.host_name != NULL) {
131 char *tmp_mod_address;
132
133 /* lookup_host() requires an IPv6 address without the brackets. */
134 if ((strnlen(working_state.server_address, MAX_IPV4_HOSTLENGTH) > 2) &&
135 (working_state.server_address[0] == '[')) {
136 // Duplicate and strip the leading '['
137 tmp_mod_address =
138 strndup(working_state.server_address + 1, strlen(working_state.server_address) - 2);
139 } else {
140 tmp_mod_address = working_state.server_address;
141 }
142
143 int res;
144 if ((res = lookup_host(tmp_mod_address, addrstr, DEFAULT_BUFFER_SIZE / 2,
145 config.sin_family)) != 0) {
146 die(STATE_CRITICAL,
147 _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"),
148 working_state.server_address, res, gai_strerror(res));
149 }
150
151 snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", working_state.host_name,
152 working_state.serverPort, addrstr);
153 result.curl_state.host = curl_slist_append(NULL, dnscache);
154 curl_easy_setopt(result.curl_state.curl, CURLOPT_RESOLVE, result.curl_state.host);
155
156 if (verbose >= 1) {
157 printf("* curl CURLOPT_RESOLVE: %s\n", dnscache);
158 }
159 }
160
161 // If server_address is an IPv6 address it must be surround by square brackets
162 struct in6_addr tmp_in_addr;
163 if (inet_pton(AF_INET6, working_state.server_address, &tmp_in_addr) == 1) {
164 char *new_server_address = calloc(strlen(working_state.server_address) + 3, sizeof(char));
165 if (new_server_address == NULL) {
166 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n");
167 }
168 snprintf(new_server_address, strlen(working_state.server_address) + 3, "[%s]",
169 working_state.server_address);
170 working_state.server_address = new_server_address;
171 }
172
173 /* compose URL: use the address we want to connect to, set Host: header later */
174 char *url = fmt_url(working_state);
175
176 if (verbose >= 1) {
177 printf("* curl CURLOPT_URL: %s\n", url);
178 }
179 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_URL, url),
180 "CURLOPT_URL");
181
182 free(url);
183
184 /* extract proxy information for legacy proxy https requests */
185 if (!strcmp(working_state.http_method, "CONNECT") ||
186 strstr(working_state.server_url, "http") == working_state.server_url) {
187 handle_curl_option_return_code(
188 curl_easy_setopt(result.curl_state.curl, CURLOPT_PROXY, working_state.server_address),
189 "CURLOPT_PROXY");
190 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_PROXYPORT,
191 (long)working_state.serverPort),
192 "CURLOPT_PROXYPORT");
193 if (verbose >= 2) {
194 printf("* curl CURLOPT_PROXY: %s:%d\n", working_state.server_address,
195 working_state.serverPort);
196 }
197 working_state.http_method = "GET";
198 handle_curl_option_return_code(
199 curl_easy_setopt(result.curl_state.curl, CURLOPT_URL, working_state.server_url),
200 "CURLOPT_URL");
201 }
202
203 /* disable body for HEAD request */
204 if (working_state.http_method && !strcmp(working_state.http_method, "HEAD")) {
205 working_state.no_body = true;
206 }
207
208 /* set HTTP protocol version */
209 handle_curl_option_return_code(
210 curl_easy_setopt(result.curl_state.curl, CURLOPT_HTTP_VERSION, config.curl_http_version),
211 "CURLOPT_HTTP_VERSION");
212
213 /* set HTTP method */
214 if (working_state.http_method) {
215 if (!strcmp(working_state.http_method, "POST")) {
216 handle_curl_option_return_code(
217 curl_easy_setopt(result.curl_state.curl, CURLOPT_POST, 1L), "CURLOPT_POST");
218 } else if (!strcmp(working_state.http_method, "PUT")) {
219 handle_curl_option_return_code(
220 curl_easy_setopt(result.curl_state.curl, CURLOPT_UPLOAD, 1L), "CURLOPT_UPLOAD");
221 } else {
222 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl,
223 CURLOPT_CUSTOMREQUEST,
224 working_state.http_method),
225 "CURLOPT_CUSTOMREQUEST");
226 }
227 }
228
229 char *force_host_header = NULL;
230 /* check if Host header is explicitly set in options */
231 if (config.http_opt_headers_count) {
232 for (size_t i = 0; i < config.http_opt_headers_count; i++) {
233 if (strncmp(config.http_opt_headers[i], "Host:", 5) == 0) {
234 force_host_header = config.http_opt_headers[i];
235 }
236 }
237 }
238
239 /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in
240 * anyway */
241 char http_header[DEFAULT_BUFFER_SIZE];
242 if (working_state.host_name != NULL && force_host_header == NULL) {
243 if ((working_state.virtualPort != HTTP_PORT && !working_state.use_ssl) ||
244 (working_state.virtualPort != HTTPS_PORT && working_state.use_ssl)) {
245 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", working_state.host_name,
246 working_state.virtualPort);
247 } else {
248 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", working_state.host_name);
249 }
250 result.curl_state.header_list =
251 curl_slist_append(result.curl_state.header_list, http_header);
252 }
253
254 /* always close connection, be nice to servers */
255 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Connection: close");
256 result.curl_state.header_list = curl_slist_append(result.curl_state.header_list, http_header);
257
258 /* attach additional headers supplied by the user */
259 /* optionally send any other header tag */
260 if (config.http_opt_headers_count) {
261 for (size_t i = 0; i < config.http_opt_headers_count; i++) {
262 result.curl_state.header_list =
263 curl_slist_append(result.curl_state.header_list, config.http_opt_headers[i]);
264 }
265 }
266
267 /* set HTTP headers */
268 handle_curl_option_return_code(
269 curl_easy_setopt(result.curl_state.curl, CURLOPT_HTTPHEADER, result.curl_state.header_list),
270 "CURLOPT_HTTPHEADER");
271
272#ifdef LIBCURL_FEATURE_SSL
273 /* set SSL version, warn about insecure or unsupported versions */
274 if (working_state.use_ssl) {
275 handle_curl_option_return_code(
276 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSLVERSION, config.ssl_version),
277 "CURLOPT_SSLVERSION");
278 }
279
280 /* client certificate and key to present to server (SSL) */
281 if (config.client_cert) {
282 handle_curl_option_return_code(
283 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSLCERT, config.client_cert),
284 "CURLOPT_SSLCERT");
285 }
286
287 if (config.client_privkey) {
288 handle_curl_option_return_code(
289 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSLKEY, config.client_privkey),
290 "CURLOPT_SSLKEY");
291 }
292
293 if (config.ca_cert) {
294 handle_curl_option_return_code(
295 curl_easy_setopt(result.curl_state.curl, CURLOPT_CAINFO, config.ca_cert),
296 "CURLOPT_CAINFO");
297 }
298
299 if (config.ca_cert || config.verify_peer_and_host) {
300 /* per default if we have a CA verify both the peer and the
301 * hostname in the certificate, can be switched off later */
302 handle_curl_option_return_code(
303 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 1L),
304 "CURLOPT_SSL_VERIFYPEER");
305 handle_curl_option_return_code(
306 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 2L),
307 "CURLOPT_SSL_VERIFYHOST");
308 } else {
309 /* backward-compatible behaviour, be tolerant in checks
310 * TODO: depending on more options have aspects we want
311 * to be less tolerant about ssl verfications
312 */
313 handle_curl_option_return_code(
314 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 0L),
315 "CURLOPT_SSL_VERIFYPEER");
316 handle_curl_option_return_code(
317 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 0L),
318 "CURLOPT_SSL_VERIFYHOST");
319 }
320
321 /* detect SSL library used by libcurl */
322 curlhelp_ssl_library ssl_library = curlhelp_get_ssl_library();
323
324 /* try hard to get a stack of certificates to verify against */
325 if (check_cert) {
326# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1)
327 /* inform curl to report back certificates */
328 switch (ssl_library) {
329 case CURLHELP_SSL_LIBRARY_OPENSSL:
330 case CURLHELP_SSL_LIBRARY_LIBRESSL:
331 /* set callback to extract certificate with OpenSSL context function (works with
332 * OpenSSL-style libraries only!) */
333# ifdef USE_OPENSSL
334 /* libcurl and monitoring plugins built with OpenSSL, good */
335 add_sslctx_verify_fun = true;
336 is_openssl_callback = true;
337# endif /* USE_OPENSSL */
338 /* libcurl is built with OpenSSL, monitoring plugins, so falling
339 * back to manually extracting certificate information */
340 handle_curl_option_return_code(
341 curl_easy_setopt(result.curl_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
342 break;
343
344 case CURLHELP_SSL_LIBRARY_NSS:
345# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
346 /* NSS: support for CERTINFO is implemented since 7.34.0 */
347 handle_curl_option_return_code(
348 curl_easy_setopt(result.curl_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
349# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
350 die(STATE_CRITICAL,
351 "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library "
352 "'%s' is too old)\n",
353 curlhelp_get_ssl_library_string(ssl_library));
354# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
355 break;
356
357 case CURLHELP_SSL_LIBRARY_GNUTLS:
358# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0)
359 /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */
360 handle_curl_option_return_code(
361 curl_easy_setopt(result.curl_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
362# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
363 die(STATE_CRITICAL,
364 "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library "
365 "'%s' is too old)\n",
366 curlhelp_get_ssl_library_string(ssl_library));
367# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
368 break;
369
370 case CURLHELP_SSL_LIBRARY_UNKNOWN:
371 default:
372 die(STATE_CRITICAL,
373 "HTTP CRITICAL - Cannot retrieve certificates (unknown SSL library '%s', must "
374 "implement first)\n",
375 curlhelp_get_ssl_library_string(ssl_library));
376 break;
377 }
378# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
379 /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */
380 if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL ||
381 ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL) {
382 add_sslctx_verify_fun = true;
383 } else {
384 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no "
385 "CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library or libcurl "
386 "too old and has no CURLOPT_CERTINFO)\n");
387 }
388# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
389 }
390
391# if LIBCURL_VERSION_NUM >= \
392 MAKE_LIBCURL_VERSION(7, 10, 6) /* required for CURLOPT_SSL_CTX_FUNCTION */
393 // ssl ctx function is not available with all ssl backends
394 if (curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_CTX_FUNCTION, NULL) !=
395 CURLE_UNKNOWN_OPTION) {
396 handle_curl_option_return_code(
397 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun),
398 "CURLOPT_SSL_CTX_FUNCTION");
399 }
400# endif
401#endif /* LIBCURL_FEATURE_SSL */
402
403 /* set default or user-given user agent identification */
404 handle_curl_option_return_code(
405 curl_easy_setopt(result.curl_state.curl, CURLOPT_USERAGENT, config.user_agent),
406 "CURLOPT_USERAGENT");
407
408 /* proxy-authentication */
409 if (strcmp(config.proxy_auth, "")) {
410 handle_curl_option_return_code(
411 curl_easy_setopt(result.curl_state.curl, CURLOPT_PROXYUSERPWD, config.proxy_auth),
412 "CURLOPT_PROXYUSERPWD");
413 }
414
415 /* authentication */
416 if (strcmp(config.user_auth, "")) {
417 handle_curl_option_return_code(
418 curl_easy_setopt(result.curl_state.curl, CURLOPT_USERPWD, config.user_auth),
419 "CURLOPT_USERPWD");
420 }
421 /* TODO: parameter auth method, bitfield of following methods:
422 * CURLAUTH_BASIC (default)
423 * CURLAUTH_DIGEST
424 * CURLAUTH_DIGEST_IE
425 * CURLAUTH_NEGOTIATE
426 * CURLAUTH_NTLM
427 * CURLAUTH_NTLM_WB
428 *
429 * convenience tokens for typical sets of methods:
430 * CURLAUTH_ANYSAFE: most secure, without BASIC
431 * or CURLAUTH_ANY: most secure, even BASIC if necessary
432 *
433 * handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPAUTH,
434 * (long)CURLAUTH_DIGEST ), "CURLOPT_HTTPAUTH");
435 */
436
437 /* handle redirections */
438 if (on_redirect_dependent) {
439 if (follow_method == FOLLOW_LIBCURL) {
440 handle_curl_option_return_code(
441 curl_easy_setopt(result.curl_state.curl, CURLOPT_FOLLOWLOCATION, 1L),
442 "CURLOPT_FOLLOWLOCATION");
443
444 /* default -1 is infinite, not good, could lead to zombie plugins!
445 Setting it to one bigger than maximal limit to handle errors nicely below
446 */
447 handle_curl_option_return_code(
448 curl_easy_setopt(result.curl_state.curl, CURLOPT_MAXREDIRS, max_depth + 1),
449 "CURLOPT_MAXREDIRS");
450
451 /* for now allow only http and https (we are a http(s) check plugin in the end) */
452#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0)
453 handle_curl_option_return_code(
454 curl_easy_setopt(result.curl_state.curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"),
455 "CURLOPT_REDIR_PROTOCOLS_STR");
456#elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4)
457 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl,
458 CURLOPT_REDIR_PROTOCOLS,
459 CURLPROTO_HTTP | CURLPROTO_HTTPS),
460 "CURLOPT_REDIRECT_PROTOCOLS");
461#endif
462
463 /* TODO: handle the following aspects of redirection, make them
464 * command line options too later:
465 CURLOPT_POSTREDIR: method switch
466 CURLINFO_REDIRECT_URL: custom redirect option
467 CURLOPT_REDIRECT_PROTOCOLS: allow people to step outside safe protocols
468 CURLINFO_REDIRECT_COUNT: get the number of redirects, print it, maybe a range
469 option here is nice like for expected page size?
470 */
471 } else {
472 /* old style redirection*/
473 }
474 }
475 /* no-body */
476 if (working_state.no_body) {
477 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_NOBODY, 1L),
478 "CURLOPT_NOBODY");
479 }
480
481 /* IPv4 or IPv6 forced DNS resolution */
482 if (config.sin_family == AF_UNSPEC) {
483 handle_curl_option_return_code(
484 curl_easy_setopt(result.curl_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER),
485 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)");
486 } else if (config.sin_family == AF_INET) {
487 handle_curl_option_return_code(
488 curl_easy_setopt(result.curl_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4),
489 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)");
490 }
491#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
492 else if (config.sin_family == AF_INET6) {
493 handle_curl_option_return_code(
494 curl_easy_setopt(result.curl_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6),
495 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)");
496 }
497#endif
498
499 /* either send http POST data (any data, not only POST)*/
500 if (!strcmp(working_state.http_method, "POST") || !strcmp(working_state.http_method, "PUT")) {
501 /* set content of payload for POST and PUT */
502 if (config.http_content_type) {
503 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s",
504 config.http_content_type);
505 result.curl_state.header_list =
506 curl_slist_append(result.curl_state.header_list, http_header);
507 }
508 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string
509 * in case of no POST/PUT data */
510 if (!working_state.http_post_data) {
511 working_state.http_post_data = "";
512 }
513
514 if (!strcmp(working_state.http_method, "POST")) {
515 /* POST method, set payload with CURLOPT_POSTFIELDS */
516 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl,
517 CURLOPT_POSTFIELDS,
518 working_state.http_post_data),
519 "CURLOPT_POSTFIELDS");
520 } else if (!strcmp(working_state.http_method, "PUT")) {
521 handle_curl_option_return_code(
522 curl_easy_setopt(result.curl_state.curl, CURLOPT_READFUNCTION,
523 (curl_read_callback)curlhelp_buffer_read_callback),
524 "CURLOPT_READFUNCTION");
525 if (curlhelp_initreadbuffer(&result.curl_state.put_buf, working_state.http_post_data,
526 strlen(working_state.http_post_data)) < 0) {
527 die(STATE_UNKNOWN,
528 "HTTP CRITICAL - out of memory allocating read buffer for PUT\n");
529 }
530 result.curl_state.put_buf_initialized = true;
531 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl,
532 CURLOPT_READDATA,
533 (void *)result.curl_state.put_buf),
534 "CURLOPT_READDATA");
535 handle_curl_option_return_code(
536 curl_easy_setopt(result.curl_state.curl, CURLOPT_INFILESIZE,
537 (curl_off_t)strlen(working_state.http_post_data)),
538 "CURLOPT_INFILESIZE");
539 }
540 }
541
542 /* cookie handling */
543 if (config.cookie_jar_file != NULL) {
544 /* enable reading cookies from a file, and if the filename is an empty string, only
545 * enable the curl cookie engine */
546 handle_curl_option_return_code(
547 curl_easy_setopt(result.curl_state.curl, CURLOPT_COOKIEFILE, config.cookie_jar_file),
548 "CURLOPT_COOKIEFILE");
549 /* now enable saving cookies to a file, but only if the filename is not an empty string,
550 * since writing it would fail */
551 if (*config.cookie_jar_file) {
552 handle_curl_option_return_code(
553 curl_easy_setopt(result.curl_state.curl, CURLOPT_COOKIEJAR, config.cookie_jar_file),
554 "CURLOPT_COOKIEJAR");
555 }
556 }
557
558 result.working_state = working_state;
559
560 return result;
561}
562
563void handle_curl_option_return_code(CURLcode res, const char *option) {
564 if (res != CURLE_OK) {
565 die(STATE_CRITICAL, _("Error while setting cURL option '%s': cURL returned %d - %s"),
566 option, res, curl_easy_strerror(res));
567 }
568}
569
570char *get_header_value(const struct phr_header *headers, const size_t nof_headers,
571 const char *header) {
572 for (size_t i = 0; i < nof_headers; i++) {
573 if (headers[i].name != NULL &&
574 strncasecmp(header, headers[i].name, max(headers[i].name_len, 4)) == 0) {
575 return strndup(headers[i].value, headers[i].value_len);
576 }
577 }
578 return NULL;
579}
580
581check_curl_working_state check_curl_working_state_init() {
582 check_curl_working_state result = {
583 .server_address = NULL,
584 .server_url = DEFAULT_SERVER_URL,
585 .host_name = NULL,
586 .http_method = NULL,
587 .http_post_data = NULL,
588 .virtualPort = 0,
589 .serverPort = HTTP_PORT,
590 .use_ssl = false,
591 .no_body = false,
592 };
593 return result;
594}
595
596check_curl_config check_curl_config_init() {
597 check_curl_config tmp = {
598 .initial_config = check_curl_working_state_init(),
599
600 .curl_config =
601 {
602 .automatic_decompression = false,
603 .socket_timeout = DEFAULT_SOCKET_TIMEOUT,
604 .haproxy_protocol = false,
605 .sin_family = AF_UNSPEC,
606 .curl_http_version = CURL_HTTP_VERSION_NONE,
607 .http_opt_headers = NULL,
608 .http_opt_headers_count = 0,
609 .ssl_version = CURL_SSLVERSION_DEFAULT,
610 .client_cert = NULL,
611 .client_privkey = NULL,
612 .ca_cert = NULL,
613 .verify_peer_and_host = false,
614 .user_agent = {'\0'},
615 .proxy_auth = "",
616 .user_auth = "",
617 .http_content_type = NULL,
618 .cookie_jar_file = NULL,
619 },
620 .max_depth = DEFAULT_MAX_REDIRS,
621 .followmethod = FOLLOW_HTTP_CURL,
622 .followsticky = STICKY_NONE,
623
624 .maximum_age = -1,
625 .regexp = {},
626 .compiled_regex = {},
627 .state_regex = STATE_CRITICAL,
628 .invert_regex = false,
629 .check_cert = false,
630 .continue_after_check_cert = false,
631 .days_till_exp_warn = 0,
632 .days_till_exp_crit = 0,
633 .thlds = mp_thresholds_init(),
634 .page_length_limits = mp_range_init(),
635 .page_length_limits_is_set = false,
636 .server_expect =
637 {
638 .string = HTTP_EXPECT,
639 .is_present = false,
640 },
641 .string_expect = "",
642 .header_expect = "",
643 .on_redirect_result_state = STATE_OK,
644 .on_redirect_dependent = false,
645
646 .show_extended_perfdata = false,
647 .show_body = false,
648
649 .output_format_is_set = false,
650 };
651
652 snprintf(tmp.curl_config.user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)",
653 "check_curl", NP_VERSION, VERSION, curl_version());
654
655 return tmp;
656}
657
658/* TODO: is there a better way in libcurl to check for the SSL library? */
659curlhelp_ssl_library curlhelp_get_ssl_library(void) {
660 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
661
662 curl_version_info_data *version_data = curl_version_info(CURLVERSION_NOW);
663 if (version_data == NULL) {
664 return CURLHELP_SSL_LIBRARY_UNKNOWN;
665 }
666
667 char *ssl_version = strdup(version_data->ssl_version);
668 if (ssl_version == NULL) {
669 return CURLHELP_SSL_LIBRARY_UNKNOWN;
670 }
671
672 char *library = strtok(ssl_version, "/");
673 if (library == NULL) {
674 return CURLHELP_SSL_LIBRARY_UNKNOWN;
675 }
676
677 if (strcmp(library, "OpenSSL") == 0) {
678 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL;
679 } else if (strcmp(library, "LibreSSL") == 0) {
680 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL;
681 } else if (strcmp(library, "GnuTLS") == 0) {
682 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS;
683 } else if (strcmp(library, "NSS") == 0) {
684 ssl_library = CURLHELP_SSL_LIBRARY_NSS;
685 }
686
687 if (verbose >= 2) {
688 printf("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library,
689 ssl_library);
690 }
691
692 free(ssl_version);
693
694 return ssl_library;
695}
696
697const char *curlhelp_get_ssl_library_string(const curlhelp_ssl_library ssl_library) {
698 switch (ssl_library) {
699 case CURLHELP_SSL_LIBRARY_OPENSSL:
700 return "OpenSSL";
701 case CURLHELP_SSL_LIBRARY_LIBRESSL:
702 return "LibreSSL";
703 case CURLHELP_SSL_LIBRARY_GNUTLS:
704 return "GnuTLS";
705 case CURLHELP_SSL_LIBRARY_NSS:
706 return "NSS";
707 case CURLHELP_SSL_LIBRARY_UNKNOWN:
708 default:
709 return "unknown";
710 }
711}
712
713size_t get_content_length(const curlhelp_write_curlbuf *header_buf,
714 const curlhelp_write_curlbuf *body_buf) {
715 struct phr_header headers[255];
716 size_t nof_headers = 255;
717 size_t msglen;
718 curlhelp_statusline status_line;
719 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major,
720 &status_line.http_minor, &status_line.http_code, &status_line.msg,
721 &msglen, headers, &nof_headers, 0);
722
723 if (res == -1) {
724 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
725 }
726
727 char *content_length_s = get_header_value(headers, nof_headers, "content-length");
728 if (!content_length_s) {
729 return header_buf->buflen + body_buf->buflen;
730 }
731
732 content_length_s += strspn(content_length_s, " \t");
733 size_t content_length = atoi(content_length_s);
734 if (content_length != body_buf->buflen) {
735 /* TODO: should we warn if the actual and the reported body length don't match? */
736 }
737
738 if (content_length_s) {
739 free(content_length_s);
740 }
741
742 return header_buf->buflen + body_buf->buflen;
743}
744
745mp_subcheck check_document_dates(const curlhelp_write_curlbuf *header_buf, const int maximum_age) {
746 struct phr_header headers[255];
747 size_t nof_headers = 255;
748 curlhelp_statusline status_line;
749 size_t msglen;
750 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major,
751 &status_line.http_minor, &status_line.http_code, &status_line.msg,
752 &msglen, headers, &nof_headers, 0);
753
754 if (res == -1) {
755 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
756 }
757
758 char *server_date = get_header_value(headers, nof_headers, "date");
759 char *document_date = get_header_value(headers, nof_headers, "last-modified");
760
761 mp_subcheck sc_document_dates = mp_subcheck_init();
762 if (!server_date || !*server_date) {
763 xasprintf(&sc_document_dates.output, _("Server date unknown"));
764 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_UNKNOWN);
765 } else if (!document_date || !*document_date) {
766 xasprintf(&sc_document_dates.output, _("Document modification date unknown, "));
767 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL);
768 } else {
769 time_t srv_data = curl_getdate(server_date, NULL);
770 time_t doc_data = curl_getdate(document_date, NULL);
771
772 if (verbose >= 2) {
773 printf("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data,
774 document_date, (int)doc_data);
775 }
776
777 if (srv_data <= 0) {
778 xasprintf(&sc_document_dates.output, _("Server date \"%100s\" unparsable"),
779 server_date);
780 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL);
781 } else if (doc_data <= 0) {
782
783 xasprintf(&sc_document_dates.output, _("Document date \"%100s\" unparsable"),
784 document_date);
785 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL);
786 } else if (doc_data > srv_data + 30) {
787
788 xasprintf(&sc_document_dates.output, _("Document is %d seconds in the future"),
789 (int)doc_data - (int)srv_data);
790
791 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL);
792 } else if (doc_data < srv_data - maximum_age) {
793 time_t last_modified = (srv_data - doc_data);
794 if (last_modified > (60 * 60 * 24 * 2)) { // two days hardcoded?
795 xasprintf(&sc_document_dates.output, _("Last modified %.1f days ago"),
796 ((float)last_modified) / (60 * 60 * 24));
797 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL);
798 } else {
799 xasprintf(&sc_document_dates.output, _("Last modified %lld:%02d:%02d ago"),
800 (long long)last_modified / (60 * 60), (int)(last_modified / 60) % 60,
801 (int)last_modified % 60);
802 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL);
803 }
804 } else {
805 // TODO is this the OK case?
806 time_t last_modified = (srv_data - doc_data);
807 xasprintf(&sc_document_dates.output, _("Last modified %lld:%02d:%02d ago"),
808 (long long)last_modified / (60 * 60), (int)(last_modified / 60) % 60,
809 (int)last_modified % 60);
810 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_OK);
811 }
812 }
813
814 if (server_date) {
815 free(server_date);
816 }
817 if (document_date) {
818 free(document_date);
819 }
820
821 return sc_document_dates;
822}
823
824void curlhelp_free_statusline(curlhelp_statusline *status_line) { free(status_line->first_line); }
825
826int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) {
827 /* find last start of a new header */
828 const char *start = strrstr2(buf, "\r\nHTTP/");
829 if (start != NULL) {
830 start += 2;
831 buf = start;
832 }
833
834 // Accept either LF or CRLF as end of line for the status line
835 // CRLF is the standard (RFC9112), but it is recommended to accept both
836 size_t length_of_first_line = strcspn(buf, "\r\n");
837 const char *first_line_end = &buf[length_of_first_line];
838 if (first_line_end == NULL) {
839 return -1;
840 }
841
842 size_t first_line_len = (size_t)(first_line_end - buf);
843 status_line->first_line = (char *)calloc(first_line_len + 1, sizeof(char));
844 if (status_line->first_line == NULL) {
845 return -1;
846 }
847
848 memcpy(status_line->first_line, buf, first_line_len);
849 status_line->first_line[first_line_len] = '\0';
850 char *first_line_buf = strdup(status_line->first_line);
851
852 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */
853 char *temp_string = strtok(first_line_buf, "/");
854 if (temp_string == NULL) {
855 if (verbose > 1) {
856 printf("%s: no / found\n", __func__);
857 }
858 free(first_line_buf);
859 return -1;
860 }
861
862 if (strcmp(temp_string, "HTTP") != 0) {
863 if (verbose > 1) {
864 printf("%s: string 'HTTP' not found\n", __func__);
865 }
866 free(first_line_buf);
867 return -1;
868 }
869
870 // try to find a space in the remaining string?
871 // the space after HTTP/1.1 probably
872 temp_string = strtok(NULL, " ");
873 if (temp_string == NULL) {
874 if (verbose > 1) {
875 printf("%s: no space after protocol definition\n", __func__);
876 }
877 free(first_line_buf);
878 return -1;
879 }
880
881 char *temp_string_2;
882 if (strchr(temp_string, '.') != NULL) {
883 /* HTTP 1.x case */
884 strtok(temp_string, ".");
885 status_line->http_major = (int)strtol(temp_string, &temp_string_2, 10);
886 if (*temp_string_2 != '\0') {
887 free(first_line_buf);
888 return -1;
889 }
890 strtok(NULL, " ");
891 status_line->http_minor = (int)strtol(temp_string, &temp_string_2, 10);
892 if (*temp_string_2 != '\0') {
893 free(first_line_buf);
894 return -1;
895 }
896 temp_string += 4; /* 1.x SP */
897 } else {
898 /* HTTP 2 case */
899 status_line->http_major = (int)strtol(temp_string, &temp_string_2, 10);
900 status_line->http_minor = 0;
901 temp_string += 2; /* 2 SP */
902 }
903
904 /* status code: "404" or "404.1", then SP */
905 temp_string = strtok(temp_string, " ");
906 if (temp_string == NULL) {
907 free(first_line_buf);
908 return -1;
909 }
910 if (strchr(temp_string, '.') != NULL) {
911 char *ppp;
912 ppp = strtok(temp_string, ".");
913 status_line->http_code = (int)strtol(ppp, &temp_string_2, 10);
914 if (*temp_string_2 != '\0') {
915 free(first_line_buf);
916 return -1;
917 }
918 ppp = strtok(NULL, "");
919 status_line->http_subcode = (int)strtol(ppp, &temp_string_2, 10);
920 if (*temp_string_2 != '\0') {
921 free(first_line_buf);
922 return -1;
923 }
924 temp_string += 6; /* 400.1 SP */
925 } else {
926 status_line->http_code = (int)strtol(temp_string, &temp_string_2, 10);
927 status_line->http_subcode = -1;
928 if (*temp_string_2 != '\0') {
929 free(first_line_buf);
930 return -1;
931 }
932 temp_string += 4; /* 400 SP */
933 }
934
935 /* Human readable message: "Not Found" CRLF */
936
937 temp_string = strtok(temp_string, "");
938 if (temp_string == NULL) {
939 status_line->msg = "";
940 return 0;
941 }
942 status_line->msg = status_line->first_line + (temp_string - first_line_buf);
943 free(first_line_buf);
944
945 return 0;
946}
947
948/* TODO: where to put this, it's actually part of sstrings2 (logically)?
949 */
950const char *strrstr2(const char *haystack, const char *needle) {
951 if (haystack == NULL || needle == NULL) {
952 return NULL;
953 }
954
955 if (haystack[0] == '\0' || needle[0] == '\0') {
956 return NULL;
957 }
958
959 int counter = 0;
960 const char *prev_pos = NULL;
961 const char *pos = haystack;
962 size_t len = strlen(needle);
963 for (;;) {
964 pos = strstr(pos, needle);
965 if (pos == NULL) {
966 if (counter == 0) {
967 return NULL;
968 }
969 return prev_pos;
970 }
971 counter++;
972 prev_pos = pos;
973 pos += len;
974 if (*pos == '\0') {
975 return prev_pos;
976 }
977 }
978}
979
980void curlhelp_freereadbuffer(curlhelp_read_curlbuf *buf) {
981 free(buf->buf);
982 buf->buf = NULL;
983}
984
985void curlhelp_freewritebuffer(curlhelp_write_curlbuf *buf) {
986 free(buf->buf);
987 buf->buf = NULL;
988}
989
990int curlhelp_initreadbuffer(curlhelp_read_curlbuf **buf, const char *data, size_t datalen) {
991 if ((*buf = calloc(1, sizeof(curlhelp_read_curlbuf))) == NULL) {
992 return 1;
993 }
994
995 (*buf)->buflen = datalen;
996 (*buf)->buf = (char *)calloc((*buf)->buflen, sizeof(char));
997 if ((*buf)->buf == NULL) {
998 return -1;
999 }
1000 memcpy((*buf)->buf, data, datalen);
1001 (*buf)->pos = 0;
1002 return 0;
1003}
1004
1005size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
1006 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream;
1007
1008 size_t minimalSize = min(nmemb * size, buf->buflen - buf->pos);
1009
1010 memcpy(buffer, buf->buf + buf->pos, minimalSize);
1011 buf->pos += minimalSize;
1012
1013 return minimalSize;
1014}
1015
1016int curlhelp_initwritebuffer(curlhelp_write_curlbuf **buf) {
1017 if ((*buf = calloc(1, sizeof(curlhelp_write_curlbuf))) == NULL) {
1018 return 1;
1019 }
1020 (*buf)->bufsize = DEFAULT_BUFFER_SIZE * sizeof(char);
1021 (*buf)->buflen = 0;
1022 (*buf)->buf = (char *)calloc((*buf)->bufsize, sizeof(char));
1023 if ((*buf)->buf == NULL) {
1024 return -1;
1025 }
1026 return 0;
1027}
1028
1029size_t curlhelp_buffer_write_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
1030 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream;
1031
1032 while (buf->bufsize < buf->buflen + size * nmemb + 1) {
1033 buf->bufsize = buf->bufsize * 2;
1034 buf->buf = (char *)realloc(buf->buf, buf->bufsize);
1035 if (buf->buf == NULL) {
1036 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno));
1037 return 0;
1038 }
1039 }
1040
1041 memcpy(buf->buf + buf->buflen, buffer, size * nmemb);
1042 buf->buflen += size * nmemb;
1043 buf->buf[buf->buflen] = '\0';
1044
1045 return size * nmemb;
1046}
1047
1048void cleanup(check_curl_global_state global_state) {
1049 if (global_state.status_line_initialized) {
1050 curlhelp_free_statusline(global_state.status_line);
1051 }
1052 global_state.status_line_initialized = false;
1053
1054 if (global_state.curl_easy_initialized) {
1055 curl_easy_cleanup(global_state.curl);
1056 }
1057 global_state.curl_easy_initialized = false;
1058
1059 if (global_state.curl_global_initialized) {
1060 curl_global_cleanup();
1061 }
1062 global_state.curl_global_initialized = false;
1063
1064 if (global_state.body_buf_initialized) {
1065 curlhelp_freewritebuffer(global_state.body_buf);
1066 }
1067 global_state.body_buf_initialized = false;
1068
1069 if (global_state.header_buf_initialized) {
1070 curlhelp_freewritebuffer(global_state.header_buf);
1071 }
1072 global_state.header_buf_initialized = false;
1073
1074 if (global_state.put_buf_initialized) {
1075 curlhelp_freereadbuffer(global_state.put_buf);
1076 }
1077 global_state.put_buf_initialized = false;
1078
1079 if (global_state.header_list) {
1080 curl_slist_free_all(global_state.header_list);
1081 }
1082
1083 if (global_state.host) {
1084 curl_slist_free_all(global_state.host);
1085 }
1086}
1087
1088int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_family) {
1089 struct addrinfo hints = {
1090 .ai_family = addr_family,
1091 .ai_socktype = SOCK_STREAM,
1092 .ai_flags = AI_CANONNAME,
1093 };
1094
1095 struct addrinfo *result;
1096 int errcode = getaddrinfo(host, NULL, &hints, &result);
1097 if (errcode != 0) {
1098 return errcode;
1099 }
1100
1101 strcpy(buf, "");
1102 struct addrinfo *res = result;
1103
1104 size_t buflen_remaining = buflen - 1;
1105 size_t addrstr_len;
1106 char addrstr[100];
1107 void *ptr = {0};
1108 while (res) {
1109 switch (res->ai_family) {
1110 case AF_INET:
1111 ptr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
1112 break;
1113 case AF_INET6:
1114 ptr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
1115 break;
1116 }
1117
1118 inet_ntop(res->ai_family, ptr, addrstr, 100);
1119 if (verbose >= 1) {
1120 printf("* getaddrinfo IPv%d address: %s\n", res->ai_family == PF_INET6 ? 6 : 4,
1121 addrstr);
1122 }
1123
1124 // Append all IPs to buf as a comma-separated string
1125 addrstr_len = strlen(addrstr);
1126 if (buflen_remaining > addrstr_len + 1) {
1127 if (buf[0] != '\0') {
1128 strncat(buf, ",", buflen_remaining);
1129 buflen_remaining -= 1;
1130 }
1131 strncat(buf, addrstr, buflen_remaining);
1132 buflen_remaining -= addrstr_len;
1133 }
1134
1135 res = res->ai_next;
1136 }
1137
1138 freeaddrinfo(result);
1139
1140 return 0;
1141}
1142
1143/* Checks if the server 'reply' is one of the expected 'statuscodes' */
1144bool expected_statuscode(const char *reply, const char *statuscodes) {
1145 char *expected;
1146
1147 if ((expected = strdup(statuscodes)) == NULL) {
1148 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
1149 }
1150
1151 bool result = false;
1152 for (char *code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) {
1153 if (strstr(reply, code) != NULL) {
1154 result = true;
1155 break;
1156 }
1157 }
1158
1159 free(expected);
1160 return result;
1161}
1162
1163/* returns a string "HTTP/1.x" or "HTTP/2" */
1164char *string_statuscode(int major, int minor) {
1165 static char buf[10];
1166
1167 switch (major) {
1168 case 1:
1169 snprintf(buf, sizeof(buf), "HTTP/%d.%d", major, minor);
1170 break;
1171 case 2:
1172 case 3:
1173 snprintf(buf, sizeof(buf), "HTTP/%d", major);
1174 break;
1175 default:
1176 /* assuming here HTTP/N with N>=4 */
1177 snprintf(buf, sizeof(buf), "HTTP/%d", major);
1178 break;
1179 }
1180
1181 return buf;
1182}
1183
1184/* check whether a file exists */
1185void test_file(char *path) {
1186 if (access(path, R_OK) == 0) {
1187 return;
1188 }
1189 usage2(_("file does not exist or is not readable"), path);
1190}
1191
1192mp_subcheck mp_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn,
1193 int days_till_exp_crit);
1194
1195mp_subcheck check_curl_certificate_checks(CURL *curl, X509 *cert, int warn_days_till_exp,
1196 int crit_days_till_exp) {
1197 mp_subcheck sc_cert_result = mp_subcheck_init();
1198 sc_cert_result = mp_set_subcheck_default_state(sc_cert_result, STATE_OK);
1199
1200#ifdef LIBCURL_FEATURE_SSL
1201 if (is_openssl_callback) {
1202# ifdef USE_OPENSSL
1203 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
1204 * and we actually have OpenSSL in the monitoring tools
1205 */
1206 return mp_net_ssl_check_certificate(cert, warn_days_till_exp, crit_days_till_exp);
1207# else /* USE_OPENSSL */
1208 xasprintf(&result.output, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL "
1209 "callback used and not linked against OpenSSL\n");
1210 mp_set_subcheck_state(result, STATE_CRITICAL);
1211# endif /* USE_OPENSSL */
1212 } else {
1213 struct curl_slist *slist;
1214
1215 cert_ptr_union cert_ptr = {0};
1216 cert_ptr.to_info = NULL;
1217 CURLcode res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &cert_ptr.to_info);
1218 if (!res && cert_ptr.to_info) {
1219# ifdef USE_OPENSSL
1220 /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert
1221 * parsing We only check the first certificate and assume it's the one of
1222 * the server
1223 */
1224 char *raw_cert = NULL;
1225 bool got_first_cert = false;
1226 for (int i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) {
1227 if (got_first_cert) {
1228 break;
1229 }
1230
1231 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) {
1232 if (verbose >= 2) {
1233 printf("%d ** %s\n", i, slist->data);
1234 }
1235 if (strncmp(slist->data, "Cert:", 5) == 0) {
1236 raw_cert = &slist->data[5];
1237 got_first_cert = true;
1238 break;
1239 }
1240 }
1241 }
1242
1243 if (!raw_cert) {
1244
1245 xasprintf(&sc_cert_result.output,
1246 _("Cannot retrieve certificates from CERTINFO information - "
1247 "certificate data was empty"));
1248 sc_cert_result = mp_set_subcheck_state(sc_cert_result, STATE_CRITICAL);
1249 return sc_cert_result;
1250 }
1251
1252 BIO *cert_BIO = BIO_new(BIO_s_mem());
1253 BIO_write(cert_BIO, raw_cert, (int)strlen(raw_cert));
1254
1255 cert = PEM_read_bio_X509(cert_BIO, NULL, NULL, NULL);
1256 if (!cert) {
1257 xasprintf(&sc_cert_result.output,
1258 _("Cannot read certificate from CERTINFO information - BIO error"));
1259 sc_cert_result = mp_set_subcheck_state(sc_cert_result, STATE_CRITICAL);
1260 return sc_cert_result;
1261 }
1262
1263 BIO_free(cert_BIO);
1264 return mp_net_ssl_check_certificate(cert, warn_days_till_exp, crit_days_till_exp);
1265# else /* USE_OPENSSL */
1266 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our
1267 * disposal, so we use the libcurl CURLINFO data
1268 */
1269 return net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn,
1270 days_till_exp_crit);
1271# endif /* USE_OPENSSL */
1272 } else {
1273 xasprintf(&sc_cert_result.output,
1274 _("Cannot retrieve certificates - cURL returned %d - %s"), res,
1275 curl_easy_strerror(res));
1276 mp_set_subcheck_state(sc_cert_result, STATE_CRITICAL);
1277 }
1278 }
1279#endif /* LIBCURL_FEATURE_SSL */
1280
1281 return sc_cert_result;
1282}
1283
1284char *fmt_url(check_curl_working_state workingState) {
1285 char *url = calloc(DEFAULT_BUFFER_SIZE, sizeof(char));
1286 if (url == NULL) {
1287 die(STATE_UNKNOWN, "memory allocation failed");
1288 }
1289
1290 snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", workingState.use_ssl ? "https" : "http",
1291 (workingState.use_ssl & (workingState.host_name != NULL))
1292 ? workingState.host_name
1293 : workingState.server_address,
1294 workingState.serverPort, workingState.server_url);
1295
1296 return url;
1297}
diff --git a/plugins/check_curl.d/check_curl_helpers.h b/plugins/check_curl.d/check_curl_helpers.h
new file mode 100644
index 00000000..e77b763b
--- /dev/null
+++ b/plugins/check_curl.d/check_curl_helpers.h
@@ -0,0 +1,128 @@
1#include "./config.h"
2#include <curl/curl.h>
3#include "../picohttpparser/picohttpparser.h"
4#include "output.h"
5
6#if defined(HAVE_SSL) && defined(USE_OPENSSL)
7# include <openssl/opensslv.h>
8#endif
9
10enum {
11 MAX_IPV4_HOSTLENGTH = 255,
12};
13
14/* for buffers for header and body */
15typedef struct {
16 size_t buflen;
17 size_t bufsize;
18 char *buf;
19} curlhelp_write_curlbuf;
20
21/* for buffering the data sent in PUT */
22typedef struct {
23 size_t buflen;
24 off_t pos;
25 char *buf;
26} curlhelp_read_curlbuf;
27
28/* for parsing the HTTP status line */
29typedef struct {
30 int http_major; /* major version of the protocol, always 1 (HTTP/0.9
31 * never reached the big internet most likely) */
32 int http_minor; /* minor version of the protocol, usually 0 or 1 */
33 int http_code; /* HTTP return code as in RFC 2145 */
34 int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see
35 * http://support.microsoft.com/kb/318380/en-us */
36 const char *msg; /* the human readable message */
37 char *first_line; /* a copy of the first line */
38} curlhelp_statusline;
39
40typedef struct {
41 bool curl_global_initialized;
42 bool curl_easy_initialized;
43
44 bool body_buf_initialized;
45 curlhelp_write_curlbuf *body_buf;
46
47 bool header_buf_initialized;
48 curlhelp_write_curlbuf *header_buf;
49
50 bool status_line_initialized;
51 curlhelp_statusline *status_line;
52
53 bool put_buf_initialized;
54 curlhelp_read_curlbuf *put_buf;
55
56 CURL *curl;
57
58 struct curl_slist *header_list;
59 struct curl_slist *host;
60} check_curl_global_state;
61
62/* to know the underlying SSL library used by libcurl */
63typedef enum curlhelp_ssl_library {
64 CURLHELP_SSL_LIBRARY_UNKNOWN,
65 CURLHELP_SSL_LIBRARY_OPENSSL,
66 CURLHELP_SSL_LIBRARY_LIBRESSL,
67 CURLHELP_SSL_LIBRARY_GNUTLS,
68 CURLHELP_SSL_LIBRARY_NSS
69} curlhelp_ssl_library;
70
71#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major) * 0x10000 + (minor) * 0x100 + (patch))
72
73typedef struct {
74 int errorcode;
75 check_curl_global_state curl_state;
76 check_curl_working_state working_state;
77} check_curl_configure_curl_wrapper;
78
79check_curl_configure_curl_wrapper check_curl_configure_curl(check_curl_static_curl_config config,
80 check_curl_working_state working_state,
81 bool check_cert,
82 bool on_redirect_dependent,
83 int follow_method, long max_depth);
84
85void handle_curl_option_return_code(CURLcode res, const char *option);
86
87int curlhelp_initwritebuffer(curlhelp_write_curlbuf **buf);
88size_t curlhelp_buffer_write_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/,
89 void * /*stream*/);
90void curlhelp_freewritebuffer(curlhelp_write_curlbuf * /*buf*/);
91
92int curlhelp_initreadbuffer(curlhelp_read_curlbuf **buf, const char * /*data*/, size_t /*datalen*/);
93size_t curlhelp_buffer_read_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/,
94 void * /*stream*/);
95void curlhelp_freereadbuffer(curlhelp_read_curlbuf * /*buf*/);
96
97curlhelp_ssl_library curlhelp_get_ssl_library(void);
98const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library /*ssl_library*/);
99
100typedef union {
101 struct curl_slist *to_info;
102 struct curl_certinfo *to_certinfo;
103} cert_ptr_union;
104int net_noopenssl_check_certificate(cert_ptr_union *, int, int);
105
106int curlhelp_parse_statusline(const char * /*buf*/, curlhelp_statusline * /*status_line*/);
107void curlhelp_free_statusline(curlhelp_statusline * /*status_line*/);
108
109char *get_header_value(const struct phr_header *headers, size_t nof_headers, const char *header);
110mp_subcheck check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/,
111 int /*maximum_age*/);
112size_t get_content_length(const curlhelp_write_curlbuf *header_buf,
113 const curlhelp_write_curlbuf *body_buf);
114int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_family);
115CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm);
116
117#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN
118const char *strrstr2(const char *haystack, const char *needle);
119
120void cleanup(check_curl_global_state global_state);
121
122bool expected_statuscode(const char *reply, const char *statuscodes);
123char *string_statuscode(int major, int minor);
124
125void test_file(char *path);
126mp_subcheck check_curl_certificate_checks(CURL *curl, X509 *cert, int warn_days_till_exp,
127 int crit_days_till_exp);
128char *fmt_url(check_curl_working_state workingState);
diff --git a/plugins/check_curl.d/config.h b/plugins/check_curl.d/config.h
new file mode 100644
index 00000000..61067d46
--- /dev/null
+++ b/plugins/check_curl.d/config.h
@@ -0,0 +1,116 @@
1#pragma once
2
3#include "../../config.h"
4#include "../common.h"
5#include "../../lib/states.h"
6#include "../../lib/thresholds.h"
7#include <stddef.h>
8#include <string.h>
9#include <sys/socket.h>
10#include "curl/curl.h"
11#include "perfdata.h"
12#include "regex.h"
13
14enum {
15 MAX_RE_SIZE = 1024,
16 HTTP_PORT = 80,
17 HTTPS_PORT = 443,
18 MAX_PORT = 65535,
19 DEFAULT_MAX_REDIRS = 15
20};
21
22enum {
23 FOLLOW_HTTP_CURL = 0,
24 FOLLOW_LIBCURL = 1
25};
26
27enum {
28 STICKY_NONE = 0,
29 STICKY_HOST = 1,
30 STICKY_PORT = 2
31};
32
33#define HTTP_EXPECT "HTTP/"
34#define DEFAULT_BUFFER_SIZE 2048
35#define DEFAULT_SERVER_URL "/"
36
37typedef struct {
38 char *server_address;
39 char *server_url;
40 char *host_name;
41
42 char *http_method;
43
44 char *http_post_data;
45
46 unsigned short virtualPort;
47 unsigned short serverPort;
48
49 bool use_ssl;
50 bool no_body;
51} check_curl_working_state;
52
53check_curl_working_state check_curl_working_state_init();
54
55typedef struct {
56 bool automatic_decompression;
57 bool haproxy_protocol;
58 long socket_timeout;
59 sa_family_t sin_family;
60 long curl_http_version;
61 char **http_opt_headers;
62 size_t http_opt_headers_count;
63 long ssl_version;
64 char *client_cert;
65 char *client_privkey;
66 char *ca_cert;
67 bool verify_peer_and_host;
68 char user_agent[DEFAULT_BUFFER_SIZE];
69 char proxy_auth[MAX_INPUT_BUFFER];
70 char user_auth[MAX_INPUT_BUFFER];
71 char *http_content_type;
72 char *cookie_jar_file;
73} check_curl_static_curl_config;
74
75typedef struct {
76 check_curl_working_state initial_config;
77
78 check_curl_static_curl_config curl_config;
79 long max_depth;
80 int followmethod;
81 int followsticky;
82
83 int maximum_age;
84
85 // the original regex string from the command line
86 char regexp[MAX_RE_SIZE];
87
88 // the compiled regex for usage later
89 regex_t compiled_regex;
90
91 mp_state_enum state_regex;
92 bool invert_regex;
93 bool check_cert;
94 bool continue_after_check_cert;
95 int days_till_exp_warn;
96 int days_till_exp_crit;
97 mp_thresholds thlds;
98 mp_range page_length_limits;
99 bool page_length_limits_is_set;
100 struct {
101 char string[MAX_INPUT_BUFFER];
102 bool is_present;
103 } server_expect;
104 char string_expect[MAX_INPUT_BUFFER];
105 char header_expect[MAX_INPUT_BUFFER];
106 mp_state_enum on_redirect_result_state;
107 bool on_redirect_dependent;
108
109 bool show_extended_perfdata;
110 bool show_body;
111
112 bool output_format_is_set;
113 mp_output_format output_format;
114} check_curl_config;
115
116check_curl_config check_curl_config_init();
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c
index 9efcd1cb..81d92952 100644
--- a/plugins/check_dbi.c
+++ b/plugins/check_dbi.c
@@ -34,6 +34,10 @@ const char *copyright = "2011-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "../lib/monitoringplug.h" 36#include "../lib/monitoringplug.h"
37#include "thresholds.h"
38#include "perfdata.h"
39#include "output.h"
40#include "states.h"
37#include "check_dbi.d/config.h" 41#include "check_dbi.d/config.h"
38#include "common.h" 42#include "common.h"
39#include "utils.h" 43#include "utils.h"
@@ -63,7 +67,6 @@ typedef struct {
63} check_dbi_config_wrapper; 67} check_dbi_config_wrapper;
64 68
65static check_dbi_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); 69static check_dbi_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
66static check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper /*config_wrapper*/);
67void print_usage(void); 70void print_usage(void);
68static void print_help(void); 71static void print_help(void);
69 72
@@ -71,25 +74,18 @@ static double timediff(struct timeval /*start*/, struct timeval /*end*/);
71 74
72static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...); 75static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...);
73 76
74static mp_state_enum do_query(dbi_conn /*conn*/, const char ** /*res_val_str*/, double * /*res_val*/, double * /*res_time*/, mp_dbi_metric /*metric*/, 77typedef struct {
75 mp_dbi_type /*type*/, char * /*np_dbi_query*/); 78 char *result_string;
79 double result_number;
80 double query_duration;
81 int error_code;
82 const char *error_string;
83 mp_state_enum query_processing_status;
84} do_query_result;
85static do_query_result do_query(dbi_conn conn, check_dbi_metric metric, check_dbi_type type,
86 char *query);
76 87
77int main(int argc, char **argv) { 88int main(int argc, char **argv) {
78 int status = STATE_UNKNOWN;
79
80 dbi_driver driver;
81 dbi_conn conn;
82
83 unsigned int server_version;
84
85 struct timeval start_timeval;
86 struct timeval end_timeval;
87 double conn_time = 0.0;
88 double query_time = 0.0;
89
90 const char *query_val_str = NULL;
91 double query_val = 0.0;
92
93 setlocale(LC_ALL, ""); 89 setlocale(LC_ALL, "");
94 bindtextdomain(PACKAGE, LOCALEDIR); 90 bindtextdomain(PACKAGE, LOCALEDIR);
95 textdomain(PACKAGE); 91 textdomain(PACKAGE);
@@ -105,6 +101,10 @@ int main(int argc, char **argv) {
105 101
106 const check_dbi_config config = tmp.config; 102 const check_dbi_config config = tmp.config;
107 103
104 if (config.output_format_is_set) {
105 mp_set_format(config.output_format);
106 }
107
108 /* Set signal handling and alarm */ 108 /* Set signal handling and alarm */
109 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) { 109 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
110 usage4(_("Cannot catch SIGALRM")); 110 usage4(_("Cannot catch SIGALRM"));
@@ -115,63 +115,71 @@ int main(int argc, char **argv) {
115 printf("Initializing DBI\n"); 115 printf("Initializing DBI\n");
116 } 116 }
117 117
118 dbi_inst *instance_p = {0}; 118 dbi_inst instance_p = NULL;
119 119 if (dbi_initialize_r(NULL, &instance_p) < 0) {
120 if (dbi_initialize_r(NULL, instance_p) < 0) { 120 printf("failed to initialize DBI; possibly you don't have any drivers installed.\n");
121 printf("UNKNOWN - failed to initialize DBI; possibly you don't have any drivers installed.\n"); 121 exit(STATE_UNKNOWN);
122 return STATE_UNKNOWN;
123 } 122 }
124 123
124 // Try to prevent libdbi from printing stuff on stderr
125 // Who thought that would be a good idea anyway?
126 dbi_set_verbosity_r(0, instance_p);
127
125 if (instance_p == NULL) { 128 if (instance_p == NULL) {
126 printf("UNKNOWN - failed to initialize DBI.\n"); 129 printf("failed to initialize DBI.\n");
127 return STATE_UNKNOWN; 130 exit(STATE_UNKNOWN);
128 } 131 }
129 132
130 if (verbose) { 133 if (verbose) {
131 printf("Opening DBI driver '%s'\n", config.dbi_driver); 134 printf("Opening DBI driver '%s'\n", config.dbi_driver);
132 } 135 }
133 136
134 driver = dbi_driver_open_r(config.dbi_driver, instance_p); 137 dbi_driver driver = dbi_driver_open_r(config.dbi_driver, instance_p);
135 if (!driver) { 138 if (!driver) {
136 printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", config.dbi_driver); 139 printf("failed to open DBI driver '%s'; possibly it's not installed.\n", config.dbi_driver);
137 140
138 printf("Known drivers:\n"); 141 printf("Known drivers:\n");
139 for (driver = dbi_driver_list_r(NULL, instance_p); driver; driver = dbi_driver_list_r(driver, instance_p)) { 142 for (driver = dbi_driver_list_r(NULL, instance_p); driver;
143 driver = dbi_driver_list_r(driver, instance_p)) {
140 printf(" - %s\n", dbi_driver_get_name(driver)); 144 printf(" - %s\n", dbi_driver_get_name(driver));
141 } 145 }
142 return STATE_UNKNOWN; 146 exit(STATE_UNKNOWN);
143 } 147 }
144 148
145 /* make a connection to the database */ 149 /* make a connection to the database */
150 struct timeval start_timeval;
146 gettimeofday(&start_timeval, NULL); 151 gettimeofday(&start_timeval, NULL);
147 152
148 conn = dbi_conn_open(driver); 153 dbi_conn conn = dbi_conn_open(driver);
149 if (!conn) { 154 if (!conn) {
150 printf("UNKNOWN - failed top open connection object.\n"); 155 printf("UNKNOWN - failed top open connection object.\n");
151 dbi_conn_close(conn); 156 dbi_conn_close(conn);
152 return STATE_UNKNOWN; 157 exit(STATE_UNKNOWN);
153 } 158 }
154 159
155 for (size_t i = 0; i < config.dbi_options_num; ++i) { 160 for (size_t i = 0; i < config.dbi_options_num; ++i) {
156 const char *opt; 161 const char *opt;
157 162
158 if (verbose > 1) { 163 if (verbose > 1) {
159 printf("Setting DBI driver option '%s' to '%s'\n", config.dbi_options[i].key, config.dbi_options[i].value); 164 printf("Setting DBI driver option '%s' to '%s'\n", config.dbi_options[i].key,
165 config.dbi_options[i].value);
160 } 166 }
161 167
162 if (!dbi_conn_set_option(conn, config.dbi_options[i].key, config.dbi_options[i].value)) { 168 if (!dbi_conn_set_option(conn, config.dbi_options[i].key, config.dbi_options[i].value)) {
163 continue; 169 continue;
164 } 170 }
165 /* else: status != 0 */
166 171
167 np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'", config.dbi_options[i].key, config.dbi_options[i].value); 172 // Failing to set option
173 np_dbi_print_error(conn, "failed to set option '%s' to '%s'", config.dbi_options[i].key,
174 config.dbi_options[i].value);
168 printf("Known driver options:\n"); 175 printf("Known driver options:\n");
169 176
170 for (opt = dbi_conn_get_option_list(conn, NULL); opt; opt = dbi_conn_get_option_list(conn, opt)) { 177 for (opt = dbi_conn_get_option_list(conn, NULL); opt;
178 opt = dbi_conn_get_option_list(conn, opt)) {
171 printf(" - %s\n", opt); 179 printf(" - %s\n", opt);
172 } 180 }
173 dbi_conn_close(conn); 181 dbi_conn_close(conn);
174 return STATE_UNKNOWN; 182 exit(STATE_UNKNOWN);
175 } 183 }
176 184
177 if (config.host) { 185 if (config.host) {
@@ -199,78 +207,216 @@ int main(int argc, char **argv) {
199 } 207 }
200 208
201 if (dbi_conn_connect(conn) < 0) { 209 if (dbi_conn_connect(conn) < 0) {
202 np_dbi_print_error(conn, "UNKNOWN - failed to connect to database"); 210 np_dbi_print_error(conn, "failed to connect to database");
203 return STATE_UNKNOWN; 211 exit(STATE_UNKNOWN);
204 } 212 }
205 213
214 struct timeval end_timeval;
206 gettimeofday(&end_timeval, NULL); 215 gettimeofday(&end_timeval, NULL);
207 conn_time = timediff(start_timeval, end_timeval); 216 double conn_time = timediff(start_timeval, end_timeval);
208
209 server_version = dbi_conn_get_engine_version(conn);
210 if (verbose) { 217 if (verbose) {
211 printf("Connected to server version %u\n", server_version); 218 printf("Time elapsed: %f\n", conn_time);
212 } 219 }
213 220
214 if (config.metric == METRIC_SERVER_VERSION) { 221 mp_check overall = mp_check_init();
215 status = get_status(server_version, config.dbi_thresholds); 222
223 mp_subcheck sc_connection_time = mp_subcheck_init();
224 sc_connection_time = mp_set_subcheck_default_state(sc_connection_time, STATE_OK);
225 xasprintf(&sc_connection_time.output, "Connection time: %f", conn_time);
226
227 mp_perfdata pd_conn_duration = perfdata_init();
228 pd_conn_duration.label = "conntime";
229 pd_conn_duration = mp_set_pd_value(pd_conn_duration, conn_time);
230
231 if (config.metric == METRIC_CONN_TIME) {
232 pd_conn_duration = mp_pd_set_thresholds(pd_conn_duration, config.thresholds);
233 mp_state_enum status = mp_get_pd_status(pd_conn_duration);
234 sc_connection_time = mp_set_subcheck_state(sc_connection_time, status);
235 if (status != STATE_OK) {
236 xasprintf(&sc_connection_time.output, "%s violates thresholds",
237 sc_connection_time.output);
238 }
216 } 239 }
217 240
241 mp_add_perfdata_to_subcheck(&sc_connection_time, pd_conn_duration);
242 mp_add_subcheck_to_check(&overall, sc_connection_time);
243
244 unsigned int server_version = dbi_conn_get_engine_version(conn);
218 if (verbose) { 245 if (verbose) {
219 printf("Time elapsed: %f\n", conn_time); 246 printf("Connected to server version %u\n", server_version);
220 } 247 }
221 248
222 if (config.metric == METRIC_CONN_TIME) { 249 mp_subcheck sc_server_version = mp_subcheck_init();
223 status = get_status(conn_time, config.dbi_thresholds); 250 sc_server_version = mp_set_subcheck_default_state(sc_server_version, STATE_OK);
224 } 251 xasprintf(&sc_server_version.output, "Connected to server version %u", server_version);
252
253 if (config.metric == METRIC_SERVER_VERSION) {
254 mp_perfdata pd_server_version = perfdata_init();
255 pd_server_version = mp_set_pd_value(pd_server_version, server_version);
256 pd_server_version = mp_pd_set_thresholds(pd_server_version, config.thresholds);
257 mp_state_enum status = mp_get_pd_status(pd_server_version);
258 mp_add_perfdata_to_subcheck(&sc_server_version, pd_server_version);
259
260 sc_server_version = mp_set_subcheck_state(sc_server_version, status);
261
262 if (status != STATE_OK) {
263 xasprintf(&sc_server_version.output, "%s violates thresholds",
264 sc_server_version.output);
265 }
266 };
267 mp_add_subcheck_to_check(&overall, sc_server_version);
225 268
226 /* select a database */ 269 /* select a database */
227 if (config.dbi_database) { 270 if (config.database) {
228 if (verbose > 1) { 271 if (verbose > 1) {
229 printf("Selecting database '%s'\n", config.dbi_database); 272 printf("Selecting database '%s'\n", config.database);
230 } 273 }
231 274
232 if (dbi_conn_select_db(conn, config.dbi_database)) { 275 mp_subcheck sc_select_db = mp_subcheck_init();
233 np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", config.dbi_database); 276 sc_select_db = mp_set_subcheck_default_state(sc_select_db, STATE_OK);
234 return STATE_UNKNOWN; 277
278 if (dbi_conn_select_db(conn, config.database)) {
279 np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", config.database);
280 exit(STATE_UNKNOWN);
281 } else {
282 mp_add_subcheck_to_check(&overall, sc_select_db);
235 } 283 }
236 } 284 }
237 285
238 if (config.dbi_query) { 286 // Do a query (if configured)
287 if (config.query) {
288 mp_subcheck sc_query = mp_subcheck_init();
289 sc_query = mp_set_subcheck_default_state(sc_query, STATE_UNKNOWN);
290
239 /* execute query */ 291 /* execute query */
240 status = do_query(conn, &query_val_str, &query_val, &query_time, config.metric, config.type, config.dbi_query); 292 do_query_result query_res = do_query(conn, config.metric, config.type, config.query);
241 if (status != STATE_OK) { 293
242 /* do_query prints an error message in this case */ 294 if (query_res.error_code != 0) {
243 return status; 295 xasprintf(&sc_query.output, "Query failed: %s", query_res.error_string);
244 } 296 sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
297 } else if (query_res.query_processing_status != STATE_OK) {
298 if (query_res.error_string) {
299 xasprintf(&sc_query.output, "Failed to process query: %s", query_res.error_string);
300 } else {
301 xasprintf(&sc_query.output, "Failed to process query");
302 }
303 sc_query = mp_set_subcheck_state(sc_query, query_res.query_processing_status);
304 } else {
305 // query succeeded in general
306 xasprintf(&sc_query.output, "Query '%s' succeeded", config.query);
307
308 // that's a OK by default now
309 sc_query = mp_set_subcheck_default_state(sc_query, STATE_OK);
310
311 // query duration first
312 mp_perfdata pd_query_duration = perfdata_init();
313 pd_query_duration = mp_set_pd_value(pd_query_duration, query_res.query_duration);
314 pd_query_duration.label = "querytime";
315 if (config.metric == METRIC_QUERY_TIME) {
316 pd_query_duration = mp_pd_set_thresholds(pd_query_duration, config.thresholds);
317 }
318
319 mp_add_perfdata_to_subcheck(&sc_query, pd_query_duration);
245 320
246 if (config.metric == METRIC_QUERY_RESULT) { 321 if (config.metric == METRIC_QUERY_RESULT) {
247 if (config.expect) { 322 if (config.expect) {
248 if ((!query_val_str) || strcmp(query_val_str, config.expect)) { 323 if ((!query_res.result_string) ||
249 status = STATE_CRITICAL; 324 strcmp(query_res.result_string, config.expect)) {
325 xasprintf(&sc_query.output, "Found string '%s' in query result",
326 config.expect);
327 sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
328 } else {
329 xasprintf(&sc_query.output, "Did not find string '%s' in query result",
330 config.expect);
331 sc_query = mp_set_subcheck_state(sc_query, STATE_OK);
332 }
333 } else if (config.expect_re_str) {
334 int comp_err;
335 regex_t expect_re = {};
336 comp_err = regcomp(&expect_re, config.expect_re_str, config.expect_re_cflags);
337 if (comp_err != 0) {
338 // TODO error, failed to compile regex
339 // TODO move this to config sanitatisation
340 printf("Failed to compile regex from string '%s'", config.expect_re_str);
341 exit(STATE_UNKNOWN);
342 }
343
344 int err =
345 regexec(&expect_re, query_res.result_string, 0, NULL, /* flags = */ 0);
346 if (!err) {
347 sc_query = mp_set_subcheck_state(sc_query, STATE_OK);
348 xasprintf(&sc_query.output, "Found regular expression '%s' in query result",
349 config.expect_re_str);
350 } else if (err == REG_NOMATCH) {
351 sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
352 xasprintf(&sc_query.output,
353 "Did not find regular expression '%s' in query result",
354 config.expect_re_str);
355 } else {
356 char errmsg[1024];
357 regerror(err, &expect_re, errmsg, sizeof(errmsg));
358 xasprintf(&sc_query.output,
359 "ERROR - failed to execute regular expression: %s\n", errmsg);
360 sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
361 }
250 } else { 362 } else {
251 status = STATE_OK; 363 // no string matching
364 if (isnan(query_res.result_number)) {
365 // The query result is not a number, but no string checking was configured
366 // so we expected a number
367 // this is a CRITICAL
368 xasprintf(&sc_query.output, "Query '%s' result is not numeric",
369 config.query);
370 sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
371
372 } else {
373
374 mp_perfdata pd_query_val = perfdata_init();
375 pd_query_val = mp_set_pd_value(pd_query_val, query_res.result_number);
376 pd_query_val.label = "query";
377 pd_query_val = mp_pd_set_thresholds(pd_query_val, config.thresholds);
378
379 mp_add_perfdata_to_subcheck(&sc_query, pd_query_val);
380 mp_state_enum query_numerical_result = mp_get_pd_status(pd_query_val);
381
382 sc_query = mp_set_subcheck_state(sc_query, query_numerical_result);
383 // TODO set pd thresholds
384 // if (config.dbi_thresholds->warning) {
385 // pd_query_val.warn= config.dbi_thresholds->warning
386 // } else {
387 // }
388
389 if (query_numerical_result == STATE_OK) {
390 xasprintf(&sc_query.output,
391 "Query result '%f' is within given thresholds",
392 query_res.result_number);
393 } else {
394 xasprintf(&sc_query.output,
395 "Query result '%f' violates the given thresholds",
396 query_res.result_number);
397 }
398 }
252 } 399 }
253 } else if (config.expect_re_str) { 400 } else if (config.metric == METRIC_QUERY_TIME) {
254 int err; 401 mp_state_enum query_time_status = mp_get_pd_status(pd_query_duration);
255 402 mp_set_subcheck_state(sc_query, query_time_status);
256 regex_t expect_re = {}; 403
257 err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0); 404 if (query_time_status == STATE_OK) {
258 if (!err) { 405 xasprintf(&sc_query.output, "Query duration '%f' is within given thresholds",
259 status = STATE_OK; 406 query_res.query_duration);
260 } else if (err == REG_NOMATCH) {
261 status = STATE_CRITICAL;
262 } else { 407 } else {
263 char errmsg[1024]; 408 xasprintf(&sc_query.output, "Query duration '%f' violates the given thresholds",
264 regerror(err, &expect_re, errmsg, sizeof(errmsg)); 409 query_res.query_duration);
265 printf("ERROR - failed to execute regular expression: %s\n", errmsg);
266 status = STATE_CRITICAL;
267 } 410 }
268 } else { 411 } else {
269 status = get_status(query_val, config.dbi_thresholds); 412 /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error
413 * which should have been reported and handled (abort) before
414 * ... unless we expected a string to be returned */
415 assert((!isnan(query_res.result_number)) || (config.type == TYPE_STRING));
270 } 416 }
271 } else if (config.metric == METRIC_QUERY_TIME) {
272 status = get_status(query_time, config.dbi_thresholds);
273 } 417 }
418
419 mp_add_subcheck_to_check(&overall, sc_query);
274 } 420 }
275 421
276 if (verbose) { 422 if (verbose) {
@@ -278,55 +424,17 @@ int main(int argc, char **argv) {
278 } 424 }
279 dbi_conn_close(conn); 425 dbi_conn_close(conn);
280 426
281 /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error 427 mp_exit(overall);
282 * which should have been reported and handled (abort) before
283 * ... unless we expected a string to be returned */
284 assert((config.metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) || (config.type == TYPE_STRING));
285
286 assert((config.type != TYPE_STRING) || (config.expect || config.expect_re_str));
287
288 printf("%s - connection time: %fs", state_text(status), conn_time);
289 if (config.dbi_query) {
290 if (config.type == TYPE_STRING) {
291 assert(config.expect || config.expect_re_str);
292 printf(", '%s' returned '%s' in %fs", config.dbi_query, query_val_str ? query_val_str : "<nothing>", query_time);
293 if (status != STATE_OK) {
294 if (config.expect) {
295 printf(" (expected '%s')", config.expect);
296 } else if (config.expect_re_str) {
297 printf(" (expected regex /%s/%s)", config.expect_re_str, ((config.expect_re_cflags & REG_ICASE) ? "i" : ""));
298 }
299 }
300 } else if (isnan(query_val)) {
301 printf(", '%s' query execution time: %fs", config.dbi_query, query_time);
302 } else {
303 printf(", '%s' returned %f in %fs", config.dbi_query, query_val, query_time);
304 }
305 }
306
307 printf(" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time,
308 ((config.metric == METRIC_CONN_TIME) && config.warning_range) ? config.warning_range : "",
309 ((config.metric == METRIC_CONN_TIME) && config.critical_range) ? config.critical_range : "", server_version,
310 ((config.metric == METRIC_SERVER_VERSION) && config.warning_range) ? config.warning_range : "",
311 ((config.metric == METRIC_SERVER_VERSION) && config.critical_range) ? config.critical_range : "");
312 if (config.dbi_query) {
313 if (!isnan(query_val)) { /* this is also true when -e is used */
314 printf(" query=%f;%s;%s;;", query_val, ((config.metric == METRIC_QUERY_RESULT) && config.warning_range) ? config.warning_range : "",
315 ((config.metric == METRIC_QUERY_RESULT) && config.critical_range) ? config.critical_range : "");
316 }
317 printf(" querytime=%fs;%s;%s;0;", query_time, ((config.metric == METRIC_QUERY_TIME) && config.warning_range) ? config.warning_range : "",
318 ((config.metric == METRIC_QUERY_TIME) && config.critical_range) ? config.critical_range : "");
319 }
320 printf("\n");
321 return status;
322} 428}
323 429
324/* process command-line arguments */ 430/* process command-line arguments */
325check_dbi_config_wrapper process_arguments(int argc, char **argv) { 431check_dbi_config_wrapper process_arguments(int argc, char **argv) {
432 enum {
433 output_format_index = CHAR_MAX + 1,
434 };
326 435
327 int option = 0; 436 int option = 0;
328 static struct option longopts[] = {STD_LONG_OPTS, 437 static struct option longopts[] = {STD_LONG_OPTS,
329
330 {"expect", required_argument, 0, 'e'}, 438 {"expect", required_argument, 0, 'e'},
331 {"regex", required_argument, 0, 'r'}, 439 {"regex", required_argument, 0, 'r'},
332 {"regexi", required_argument, 0, 'R'}, 440 {"regexi", required_argument, 0, 'R'},
@@ -335,6 +443,7 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) {
335 {"option", required_argument, 0, 'o'}, 443 {"option", required_argument, 0, 'o'},
336 {"query", required_argument, 0, 'q'}, 444 {"query", required_argument, 0, 'q'},
337 {"database", required_argument, 0, 'D'}, 445 {"database", required_argument, 0, 'D'},
446 {"output-format", required_argument, 0, output_format_index},
338 {0, 0, 0, 0}}; 447 {0, 0, 0, 0}};
339 448
340 check_dbi_config_wrapper result = { 449 check_dbi_config_wrapper result = {
@@ -359,14 +468,22 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) {
359 print_revision(progname, NP_VERSION); 468 print_revision(progname, NP_VERSION);
360 exit(STATE_UNKNOWN); 469 exit(STATE_UNKNOWN);
361 470
362 case 'c': /* critical range */ 471 case 'c': /* critical range */ {
363 result.config.critical_range = optarg; 472 mp_range_parsed tmp = mp_parse_range_string(optarg);
473 if (tmp.error != MP_PARSING_SUCCES) {
474 die(STATE_UNKNOWN, "failed to parse critical threshold");
475 }
476 result.config.thresholds = mp_thresholds_set_crit(result.config.thresholds, tmp.range);
364 result.config.type = TYPE_NUMERIC; 477 result.config.type = TYPE_NUMERIC;
365 break; 478 } break;
366 case 'w': /* warning range */ 479 case 'w': /* warning range */ {
367 result.config.warning_range = optarg; 480 mp_range_parsed tmp = mp_parse_range_string(optarg);
481 if (tmp.error != MP_PARSING_SUCCES) {
482 die(STATE_UNKNOWN, "failed to parse warning threshold");
483 }
484 result.config.thresholds = mp_thresholds_set_warn(result.config.thresholds, tmp.range);
368 result.config.type = TYPE_NUMERIC; 485 result.config.type = TYPE_NUMERIC;
369 break; 486 } break;
370 case 'e': 487 case 'e':
371 result.config.expect = optarg; 488 result.config.expect = optarg;
372 result.config.type = TYPE_STRING; 489 result.config.type = TYPE_STRING;
@@ -393,7 +510,6 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) {
393 } 510 }
394 break; 511 break;
395 } 512 }
396
397 case 'm': 513 case 'm':
398 if (!strcasecmp(optarg, "CONN_TIME")) { 514 if (!strcasecmp(optarg, "CONN_TIME")) {
399 result.config.metric = METRIC_CONN_TIME; 515 result.config.metric = METRIC_CONN_TIME;
@@ -413,7 +529,6 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) {
413 } else { 529 } else {
414 timeout_interval = atoi(optarg); 530 timeout_interval = atoi(optarg);
415 } 531 }
416
417 break; 532 break;
418 case 'H': /* host */ 533 case 'H': /* host */
419 if (!is_host(optarg)) { 534 if (!is_host(optarg)) {
@@ -425,7 +540,6 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) {
425 case 'v': 540 case 'v':
426 verbose++; 541 verbose++;
427 break; 542 break;
428
429 case 'd': 543 case 'd':
430 result.config.dbi_driver = optarg; 544 result.config.dbi_driver = optarg;
431 break; 545 break;
@@ -442,7 +556,8 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) {
442 *value = '\0'; 556 *value = '\0';
443 ++value; 557 ++value;
444 558
445 new = realloc(result.config.dbi_options, (result.config.dbi_options_num + 1) * sizeof(*new)); 559 new = realloc(result.config.dbi_options,
560 (result.config.dbi_options_num + 1) * sizeof(*new));
446 if (!new) { 561 if (!new) {
447 printf("UNKNOWN - failed to reallocate memory\n"); 562 printf("UNKNOWN - failed to reallocate memory\n");
448 exit(STATE_UNKNOWN); 563 exit(STATE_UNKNOWN);
@@ -456,52 +571,68 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) {
456 new->value = value; 571 new->value = value;
457 } break; 572 } break;
458 case 'q': 573 case 'q':
459 result.config.dbi_query = optarg; 574 result.config.query = optarg;
460 break; 575 break;
461 case 'D': 576 case 'D':
462 result.config.dbi_database = optarg; 577 result.config.database = optarg;
578 break;
579 case output_format_index: {
580 parsed_output_format parser = mp_parse_output_format(optarg);
581 if (!parser.parsing_success) {
582 // TODO List all available formats here, maybe add anothoer usage function
583 printf("Invalid output format: %s\n", optarg);
584 exit(STATE_UNKNOWN);
585 }
586
587 result.config.output_format_is_set = true;
588 result.config.output_format = parser.output_format;
463 break; 589 break;
464 } 590 }
591 }
465 } 592 }
466 593
467 set_thresholds(&result.config.dbi_thresholds, result.config.warning_range, result.config.critical_range); 594 if (!result.config.dbi_driver) {
468
469 return validate_arguments(result);
470}
471
472check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper config_wrapper) {
473 if (!config_wrapper.config.dbi_driver) {
474 usage("Must specify a DBI driver"); 595 usage("Must specify a DBI driver");
475 } 596 }
476 597
477 if (((config_wrapper.config.metric == METRIC_QUERY_RESULT) || (config_wrapper.config.metric == METRIC_QUERY_TIME)) && 598 if (((result.config.metric == METRIC_QUERY_RESULT) ||
478 (!config_wrapper.config.dbi_query)) { 599 (result.config.metric == METRIC_QUERY_TIME)) &&
600 (!result.config.query)) {
479 usage("Must specify a query to execute (metric == QUERY_RESULT)"); 601 usage("Must specify a query to execute (metric == QUERY_RESULT)");
480 } 602 }
481 603
482 if ((config_wrapper.config.metric != METRIC_CONN_TIME) && (config_wrapper.config.metric != METRIC_SERVER_VERSION) && 604 if ((result.config.metric != METRIC_CONN_TIME) &&
483 (config_wrapper.config.metric != METRIC_QUERY_RESULT) && (config_wrapper.config.metric != METRIC_QUERY_TIME)) { 605 (result.config.metric != METRIC_SERVER_VERSION) &&
606 (result.config.metric != METRIC_QUERY_RESULT) &&
607 (result.config.metric != METRIC_QUERY_TIME)) {
484 usage("Invalid metric specified"); 608 usage("Invalid metric specified");
485 } 609 }
486 610
487 if (config_wrapper.config.expect && (config_wrapper.config.warning_range || config_wrapper.config.critical_range || config_wrapper.config.expect_re_str)) { 611 if (result.config.expect &&
612 (result.config.thresholds.warning_is_set || result.config.thresholds.critical_is_set ||
613 result.config.expect_re_str)) {
488 usage("Do not mix -e and -w/-c/-r/-R"); 614 usage("Do not mix -e and -w/-c/-r/-R");
489 } 615 }
490 616
491 if (config_wrapper.config.expect_re_str && (config_wrapper.config.warning_range || config_wrapper.config.critical_range || config_wrapper.config.expect)) { 617 if (result.config.expect_re_str &&
618 (result.config.thresholds.warning_is_set || result.config.thresholds.critical_is_set ||
619 result.config.expect)) {
492 usage("Do not mix -r/-R and -w/-c/-e"); 620 usage("Do not mix -r/-R and -w/-c/-e");
493 } 621 }
494 622
495 if (config_wrapper.config.expect && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) { 623 if (result.config.expect && (result.config.metric != METRIC_QUERY_RESULT)) {
496 usage("Option -e requires metric QUERY_RESULT"); 624 usage("Option -e requires metric QUERY_RESULT");
497 } 625 }
498 626
499 if (config_wrapper.config.expect_re_str && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) { 627 if (result.config.expect_re_str && (result.config.metric != METRIC_QUERY_RESULT)) {
500 usage("Options -r/-R require metric QUERY_RESULT"); 628 usage("Options -r/-R require metric QUERY_RESULT");
501 } 629 }
502 630
503 config_wrapper.errorcode = OK; 631 if (result.config.type == TYPE_STRING) {
504 return config_wrapper; 632 assert(result.config.expect || result.config.expect_re_str);
633 }
634
635 return result;
505} 636}
506 637
507void print_help(void) { 638void print_help(void) {
@@ -557,6 +688,8 @@ void print_help(void) {
557 688
558 printf(UT_VERBOSE); 689 printf(UT_VERBOSE);
559 690
691 printf(UT_OUTPUT_FORMAT);
692
560 printf("\n"); 693 printf("\n");
561 printf(" %s\n", _("A DBI driver (-d option) is required. If the specified metric operates")); 694 printf(" %s\n", _("A DBI driver (-d option) is required. If the specified metric operates"));
562 printf(" %s\n\n", _("on a query, one has to be specified (-q option).")); 695 printf(" %s\n\n", _("on a query, one has to be specified (-q option)."));
@@ -607,20 +740,12 @@ void print_usage(void) {
607 printf(" [-e <string>] [-r|-R <regex>]\n"); 740 printf(" [-e <string>] [-r|-R <regex>]\n");
608} 741}
609 742
610const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_type, mp_dbi_metric metric, mp_dbi_type type) { 743const char *get_field_str(dbi_result res, check_dbi_metric metric, check_dbi_type type) {
611 const char *str; 744 const char *str = dbi_result_get_string_idx(res, 1);
612
613 if (field_type != DBI_TYPE_STRING) {
614 printf("CRITICAL - result value is not a string\n");
615 return NULL;
616 }
617
618 str = dbi_result_get_string_idx(res, 1);
619 if ((!str) || (strcmp(str, "ERROR") == 0)) { 745 if ((!str) || (strcmp(str, "ERROR") == 0)) {
620 if (metric != METRIC_QUERY_RESULT) { 746 if (metric != METRIC_QUERY_RESULT) {
621 return NULL; 747 return NULL;
622 } 748 }
623 np_dbi_print_error(conn, "CRITICAL - failed to fetch string value");
624 return NULL; 749 return NULL;
625 } 750 }
626 751
@@ -630,35 +755,50 @@ const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_ty
630 return str; 755 return str;
631} 756}
632 757
633double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type, mp_dbi_metric metric, mp_dbi_type type) { 758typedef struct {
634 double val = NAN; 759 double value;
760 int error_code;
761 int dbi_error_code; // not sure if useful
762} get_field_wrapper;
763get_field_wrapper get_field(dbi_result res, check_dbi_metric metric, check_dbi_type type) {
764
765 unsigned short field_type = dbi_result_get_field_type_idx(res, 1);
766 get_field_wrapper result = {
767 .value = NAN,
768 .error_code = OK,
769 };
635 770
636 if (*field_type == DBI_TYPE_INTEGER) { 771 if (field_type == DBI_TYPE_INTEGER) {
637 val = (double)dbi_result_get_longlong_idx(res, 1); 772 result.value = (double)dbi_result_get_longlong_idx(res, 1);
638 } else if (*field_type == DBI_TYPE_DECIMAL) { 773 } else if (field_type == DBI_TYPE_DECIMAL) {
639 val = dbi_result_get_double_idx(res, 1); 774 result.value = dbi_result_get_double_idx(res, 1);
640 } else if (*field_type == DBI_TYPE_STRING) { 775 } else if (field_type == DBI_TYPE_STRING) {
641 const char *val_str; 776 const char *val_str;
642 char *endptr = NULL; 777 char *endptr = NULL;
643 778
644 val_str = get_field_str(conn, res, *field_type, metric, type); 779 val_str = get_field_str(res, metric, type);
645 if (!val_str) { 780 if (!val_str) {
646 if (metric != METRIC_QUERY_RESULT) { 781 result.error_code = ERROR;
647 return NAN; 782 field_type = DBI_TYPE_ERROR;
648 } 783 return result;
649 *field_type = DBI_TYPE_ERROR;
650 return NAN;
651 } 784 }
652 785
653 val = strtod(val_str, &endptr); 786 result.value = strtod(val_str, &endptr);
654 if (endptr == val_str) { 787 if (endptr == val_str) {
655 if (metric != METRIC_QUERY_RESULT) { 788 if (metric != METRIC_QUERY_RESULT) {
656 return NAN; 789 result.error_code = ERROR;
790 return result;
657 } 791 }
658 printf("CRITICAL - result value is not a numeric: %s\n", val_str); 792
659 *field_type = DBI_TYPE_ERROR; 793 if (verbose) {
660 return NAN; 794 printf("CRITICAL - result value is not a numeric: %s\n", val_str);
795 }
796
797 field_type = DBI_TYPE_ERROR;
798 result.error_code = ERROR;
799 return result;
661 } 800 }
801
662 if ((endptr != NULL) && (*endptr != '\0')) { 802 if ((endptr != NULL) && (*endptr != '\0')) {
663 if (verbose) { 803 if (verbose) {
664 printf("Garbage after value: %s\n", endptr); 804 printf("Garbage after value: %s\n", endptr);
@@ -666,122 +806,127 @@ double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type, mp_d
666 } 806 }
667 } else { 807 } else {
668 if (metric != METRIC_QUERY_RESULT) { 808 if (metric != METRIC_QUERY_RESULT) {
669 return NAN; 809 result.error_code = ERROR;
810 return result;
670 } 811 }
671 printf("CRITICAL - cannot parse value of type %s (%i)\n", 812 // printf("CRITICAL - cannot parse value of type %s (%i)\n",
672 (*field_type == DBI_TYPE_BINARY) ? "BINARY" 813 // (*field_type == DBI_TYPE_BINARY) ? "BINARY"
673 : (*field_type == DBI_TYPE_DATETIME) ? "DATETIME" 814 // : (*field_type == DBI_TYPE_DATETIME) ? "DATETIME"
674 : "<unknown>", 815 // : "<unknown>",
675 *field_type); 816 // *field_type);
676 *field_type = DBI_TYPE_ERROR; 817 field_type = DBI_TYPE_ERROR;
677 return NAN; 818 result.error_code = ERROR;
678 } 819 }
679 return val; 820 return result;
680} 821}
681 822
682mp_state_enum get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val, mp_dbi_metric metric, mp_dbi_type type) { 823static do_query_result do_query(dbi_conn conn, check_dbi_metric metric, check_dbi_type type,
683 unsigned short field_type; 824 char *query) {
684 double val = NAN; 825 assert(query);
685
686 if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) {
687 if (metric != METRIC_QUERY_RESULT) {
688 return STATE_OK;
689 }
690 np_dbi_print_error(conn, "CRITICAL - failed to fetch rows");
691 return STATE_CRITICAL;
692 }
693
694 if (dbi_result_get_numrows(res) < 1) {
695 if (metric != METRIC_QUERY_RESULT) {
696 return STATE_OK;
697 }
698 printf("WARNING - no rows returned\n");
699 return STATE_WARNING;
700 }
701 826
702 if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) { 827 if (verbose) {
703 if (metric != METRIC_QUERY_RESULT) { 828 printf("Executing query '%s'\n", query);
704 return STATE_OK;
705 }
706 np_dbi_print_error(conn, "CRITICAL - failed to fetch fields");
707 return STATE_CRITICAL;
708 }
709
710 if (dbi_result_get_numfields(res) < 1) {
711 if (metric != METRIC_QUERY_RESULT) {
712 return STATE_OK;
713 }
714 printf("WARNING - no fields returned\n");
715 return STATE_WARNING;
716 }
717
718 if (dbi_result_first_row(res) != 1) {
719 if (metric != METRIC_QUERY_RESULT) {
720 return STATE_OK;
721 }
722 np_dbi_print_error(conn, "CRITICAL - failed to fetch first row");
723 return STATE_CRITICAL;
724 } 829 }
725 830
726 field_type = dbi_result_get_field_type_idx(res, 1); 831 do_query_result result = {
727 if (field_type != DBI_TYPE_ERROR) { 832 .query_duration = 0,
728 if (type == TYPE_STRING) { 833 .result_string = NULL,
729 /* the value will be freed in dbi_result_free */ 834 .result_number = 0,
730 *res_val_str = strdup(get_field_str(conn, res, field_type, metric, type)); 835 .error_code = 0,
731 } else { 836 .query_processing_status = STATE_UNKNOWN,
732 val = get_field(conn, res, &field_type, metric, type); 837 };
733 }
734 }
735 838
736 *res_val = val; 839 struct timeval timeval_start;
840 gettimeofday(&timeval_start, NULL);
737 841
738 if (field_type == DBI_TYPE_ERROR) { 842 dbi_result res = dbi_conn_query(conn, query);
739 if (metric != METRIC_QUERY_RESULT) { 843 if (!res) {
740 return STATE_OK; 844 dbi_conn_error(conn, &result.error_string);
741 } 845 result.error_code = 1;
742 np_dbi_print_error(conn, "CRITICAL - failed to fetch data"); 846 return result;
743 return STATE_CRITICAL;
744 } 847 }
745 848
746 dbi_result_free(res);
747 return STATE_OK;
748}
749
750mp_state_enum do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *res_time, mp_dbi_metric metric, mp_dbi_type type,
751 char *np_dbi_query) {
752 dbi_result res;
753
754 struct timeval timeval_start;
755 struct timeval timeval_end; 849 struct timeval timeval_end;
756 mp_state_enum status = STATE_OK; 850 gettimeofday(&timeval_end, NULL);
757 851 result.query_duration = timediff(timeval_start, timeval_end);
758 assert(np_dbi_query);
759 852
760 if (verbose) { 853 if (verbose) {
761 printf("Executing query '%s'\n", np_dbi_query); 854 printf("Query duration: %f\n", result.query_duration);
762 } 855 }
763 856
764 gettimeofday(&timeval_start, NULL); 857 // Default state is OK, all error will be set explicitly
858 mp_state_enum query_processing_state = STATE_OK;
859 {
765 860
766 res = dbi_conn_query(conn, np_dbi_query); 861 if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) {
767 if (!res) { 862 if (metric != METRIC_QUERY_RESULT) {
768 np_dbi_print_error(conn, "CRITICAL - failed to execute query '%s'", np_dbi_query); 863 query_processing_state = STATE_OK;
769 return STATE_CRITICAL; 864 } else {
865 dbi_conn_error(conn, &result.error_string);
866 query_processing_state = STATE_CRITICAL;
867 }
868 } else if (dbi_result_get_numrows(res) < 1) {
869 if (metric != METRIC_QUERY_RESULT) {
870 query_processing_state = STATE_OK;
871 } else {
872 result.error_string = "no rows returned";
873 // printf("WARNING - no rows returned\n");
874 query_processing_state = STATE_WARNING;
875 }
876 } else if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) {
877 if (metric != METRIC_QUERY_RESULT) {
878 query_processing_state = STATE_OK;
879 } else {
880 dbi_conn_error(conn, &result.error_string);
881 // np_dbi_print_error(conn, "CRITICAL - failed to fetch fields");
882 query_processing_state = STATE_CRITICAL;
883 }
884 } else if (dbi_result_get_numfields(res) < 1) {
885 if (metric != METRIC_QUERY_RESULT) {
886 query_processing_state = STATE_OK;
887 } else {
888 result.error_string = "no fields returned";
889 // printf("WARNING - no fields returned\n");
890 query_processing_state = STATE_WARNING;
891 }
892 } else if (dbi_result_first_row(res) != 1) {
893 if (metric != METRIC_QUERY_RESULT) {
894 query_processing_state = STATE_OK;
895 } else {
896 dbi_conn_error(conn, &result.error_string);
897 // np_dbi_print_error(conn, "CRITICAL - failed to fetch first row");
898 query_processing_state = STATE_CRITICAL;
899 }
900 } else {
901 unsigned short field_type = dbi_result_get_field_type_idx(res, 1);
902 if (field_type != DBI_TYPE_ERROR) {
903 if (type == TYPE_STRING) {
904 result.result_string = strdup(get_field_str(res, metric, type));
905 } else {
906 get_field_wrapper gfw = get_field(res, metric, type);
907 result.result_number = gfw.value;
908 }
909 } else {
910 // Error when retrieving the field, that is OK if the Query result is not of
911 // interest
912 if (metric != METRIC_QUERY_RESULT) {
913 query_processing_state = STATE_OK;
914 } else {
915 dbi_conn_error(conn, &result.error_string);
916 // np_dbi_print_error(conn, "CRITICAL - failed to fetch data");
917 query_processing_state = STATE_CRITICAL;
918 }
919 }
920 }
770 } 921 }
922 dbi_result_free(res);
771 923
772 status = get_query_result(conn, res, res_val_str, res_val, metric, type); 924 result.query_processing_status = query_processing_state;
773
774 gettimeofday(&timeval_end, NULL);
775 *res_time = timediff(timeval_start, timeval_end);
776
777 if (verbose) {
778 printf("Time elapsed: %f\n", *res_time);
779 }
780 925
781 return status; 926 return result;
782} 927}
783 928
784double timediff(struct timeval start, struct timeval end) { 929static double timediff(struct timeval start, struct timeval end) {
785 double diff; 930 double diff;
786 931
787 while (start.tv_usec > end.tv_usec) { 932 while (start.tv_usec > end.tv_usec) {
@@ -792,7 +937,7 @@ double timediff(struct timeval start, struct timeval end) {
792 return diff; 937 return diff;
793} 938}
794 939
795void np_dbi_print_error(dbi_conn conn, char *fmt, ...) { 940static void np_dbi_print_error(dbi_conn conn, char *fmt, ...) {
796 const char *errmsg = NULL; 941 const char *errmsg = NULL;
797 va_list ap; 942 va_list ap;
798 943
diff --git a/plugins/check_dbi.d/config.h b/plugins/check_dbi.d/config.h
index f6f0d7b3..25d74a12 100644
--- a/plugins/check_dbi.d/config.h
+++ b/plugins/check_dbi.d/config.h
@@ -3,18 +3,19 @@
3#include "../../config.h" 3#include "../../config.h"
4#include <stddef.h> 4#include <stddef.h>
5#include "../../lib/monitoringplug.h" 5#include "../../lib/monitoringplug.h"
6#include "thresholds.h"
6 7
7typedef enum { 8typedef enum {
8 METRIC_CONN_TIME, 9 METRIC_CONN_TIME,
9 METRIC_SERVER_VERSION, 10 METRIC_SERVER_VERSION,
10 METRIC_QUERY_RESULT, 11 METRIC_QUERY_RESULT,
11 METRIC_QUERY_TIME, 12 METRIC_QUERY_TIME,
12} mp_dbi_metric; 13} check_dbi_metric;
13 14
14typedef enum { 15typedef enum {
15 TYPE_NUMERIC, 16 TYPE_NUMERIC,
16 TYPE_STRING, 17 TYPE_STRING,
17} mp_dbi_type; 18} check_dbi_type;
18 19
19typedef struct { 20typedef struct {
20 char *key; 21 char *key;
@@ -24,20 +25,22 @@ typedef struct {
24typedef struct { 25typedef struct {
25 char *dbi_driver; 26 char *dbi_driver;
26 char *host; 27 char *host;
28
27 driver_option_t *dbi_options; 29 driver_option_t *dbi_options;
28 size_t dbi_options_num; 30 size_t dbi_options_num;
29 char *dbi_database; 31
30 char *dbi_query; 32 char *database;
33 char *query;
31 34
32 char *expect; 35 char *expect;
33 char *expect_re_str; 36 char *expect_re_str;
34 int expect_re_cflags; 37 int expect_re_cflags;
35 mp_dbi_metric metric; 38 check_dbi_metric metric;
36 mp_dbi_type type; 39 check_dbi_type type;
37 char *warning_range; 40 mp_thresholds thresholds;
38 char *critical_range;
39 thresholds *dbi_thresholds;
40 41
42 bool output_format_is_set;
43 mp_output_format output_format;
41} check_dbi_config; 44} check_dbi_config;
42 45
43check_dbi_config check_dbi_config_init() { 46check_dbi_config check_dbi_config_init() {
@@ -46,8 +49,8 @@ check_dbi_config check_dbi_config_init() {
46 .host = NULL, 49 .host = NULL,
47 .dbi_options = NULL, 50 .dbi_options = NULL,
48 .dbi_options_num = 0, 51 .dbi_options_num = 0,
49 .dbi_database = NULL, 52 .database = NULL,
50 .dbi_query = NULL, 53 .query = NULL,
51 54
52 .expect = NULL, 55 .expect = NULL,
53 .expect_re_str = NULL, 56 .expect_re_str = NULL,
@@ -55,9 +58,9 @@ check_dbi_config check_dbi_config_init() {
55 .metric = METRIC_QUERY_RESULT, 58 .metric = METRIC_QUERY_RESULT,
56 .type = TYPE_NUMERIC, 59 .type = TYPE_NUMERIC,
57 60
58 .warning_range = NULL, 61 .thresholds = mp_thresholds_init(),
59 .critical_range = NULL, 62
60 .dbi_thresholds = NULL, 63 .output_format_is_set = false,
61 }; 64 };
62 return tmp; 65 return tmp;
63} 66}
diff --git a/plugins/check_dig.c b/plugins/check_dig.c
index d0903be2..9ea19e6a 100644
--- a/plugins/check_dig.c
+++ b/plugins/check_dig.c
@@ -3,7 +3,7 @@
3 * Monitoring check_dig plugin 3 * Monitoring check_dig plugin
4 * 4 *
5 * License: GPL 5 * License: GPL
6 * Copyright (c) 2002-2024 Monitoring Plugins Development Team 6 * Copyright (c) 2002-2025 Monitoring Plugins Development Team
7 * 7 *
8 * Description: 8 * Description:
9 * 9 *
@@ -33,9 +33,10 @@
33 * because on some architectures those strings are in non-writable memory */ 33 * because on some architectures those strings are in non-writable memory */
34 34
35const char *progname = "check_dig"; 35const char *progname = "check_dig";
36const char *copyright = "2002-2024"; 36const char *copyright = "2002-2025";
37const char *email = "devel@monitoring-plugins.org"; 37const char *email = "devel@monitoring-plugins.org";
38 38
39#include <ctype.h>
39#include "common.h" 40#include "common.h"
40#include "netutils.h" 41#include "netutils.h"
41#include "utils.h" 42#include "utils.h"
@@ -56,6 +57,12 @@ void print_usage(void);
56 57
57static int verbose = 0; 58static int verbose = 0;
58 59
60/* helpers for flag parsing */
61static flag_list parse_flags_line(const char *line);
62static flag_list split_csv_trim(const char *csv);
63static bool flag_list_contains(const flag_list *list, const char *needle);
64static void free_flag_list(flag_list *list);
65
59int main(int argc, char **argv) { 66int main(int argc, char **argv) {
60 setlocale(LC_ALL, ""); 67 setlocale(LC_ALL, "");
61 bindtextdomain(PACKAGE, LOCALEDIR); 68 bindtextdomain(PACKAGE, LOCALEDIR);
@@ -81,8 +88,9 @@ int main(int argc, char **argv) {
81 88
82 char *command_line; 89 char *command_line;
83 /* get the command to run */ 90 /* get the command to run */
84 xasprintf(&command_line, "%s %s %s -p %d @%s %s %s +retry=%d +time=%d", PATH_TO_DIG, config.dig_args, config.query_transport, 91 xasprintf(&command_line, "%s %s %s -p %d @%s %s %s +retry=%d +time=%d", PATH_TO_DIG,
85 config.server_port, config.dns_server, config.query_address, config.record_type, config.number_tries, timeout_interval_dig); 92 config.dig_args, config.query_transport, config.server_port, config.dns_server,
93 config.query_address, config.record_type, config.number_tries, timeout_interval_dig);
86 94
87 alarm(timeout_interval); 95 alarm(timeout_interval);
88 struct timeval start_time; 96 struct timeval start_time;
@@ -100,13 +108,35 @@ int main(int argc, char **argv) {
100 output chld_out; 108 output chld_out;
101 output chld_err; 109 output chld_err;
102 char *msg = NULL; 110 char *msg = NULL;
111 flag_list dig_flags = {.items = NULL, .count = 0};
103 mp_state_enum result = STATE_UNKNOWN; 112 mp_state_enum result = STATE_UNKNOWN;
113
104 /* run the command */ 114 /* run the command */
105 if (np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) { 115 if (np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) {
106 result = STATE_WARNING; 116 result = STATE_WARNING;
107 msg = (char *)_("dig returned an error status"); 117 msg = (char *)_("dig returned an error status");
108 } 118 }
109 119
120 /* extract ';; flags: ...' from stdout (first occurrence) */
121 for (size_t i = 0; i < chld_out.lines; i++) {
122 if (strstr(chld_out.line[i], "flags:")) {
123 if (verbose) {
124 printf("Raw flags line: %s\n", chld_out.line[i]);
125 }
126
127 dig_flags = parse_flags_line(chld_out.line[i]);
128
129 if (verbose && dig_flags.count > 0) {
130 printf(_("Parsed flags:"));
131 for (size_t k = 0; k < dig_flags.count; k++) {
132 printf(" %s", dig_flags.items[k]);
133 }
134 printf("\n");
135 }
136 break;
137 }
138 }
139
110 for (size_t i = 0; i < chld_out.lines; i++) { 140 for (size_t i = 0; i < chld_out.lines; i++) {
111 /* the server is responding, we just got the host name... */ 141 /* the server is responding, we just got the host name... */
112 if (strstr(chld_out.line[i], ";; ANSWER SECTION:")) { 142 if (strstr(chld_out.line[i], ";; ANSWER SECTION:")) {
@@ -118,8 +148,9 @@ int main(int argc, char **argv) {
118 printf("%s\n", chld_out.line[i]); 148 printf("%s\n", chld_out.line[i]);
119 } 149 }
120 150
121 if (strcasestr(chld_out.line[i], (config.expected_address == NULL ? config.query_address : config.expected_address)) != 151 if (strcasestr(chld_out.line[i], (config.expected_address == NULL
122 NULL) { 152 ? config.query_address
153 : config.expected_address)) != NULL) {
123 msg = chld_out.line[i]; 154 msg = chld_out.line[i];
124 result = STATE_OK; 155 result = STATE_OK;
125 156
@@ -172,10 +203,49 @@ int main(int argc, char **argv) {
172 result = STATE_WARNING; 203 result = STATE_WARNING;
173 } 204 }
174 205
206 /* Optional: evaluate dig flags only if -E/-X were provided */
207 if ((config.require_flags.count > 0) || (config.forbid_flags.count > 0)) {
208 if (dig_flags.count > 0) {
209 for (size_t r = 0; r < config.require_flags.count; r++) {
210 if (!flag_list_contains(&dig_flags, config.require_flags.items[r])) {
211 result = STATE_CRITICAL;
212 if (!msg) {
213 xasprintf(&msg, _("Missing required DNS flag: %s"),
214 config.require_flags.items[r]);
215 } else {
216 char *newmsg = NULL;
217 xasprintf(&newmsg, _("%s; missing required DNS flag: %s"), msg,
218 config.require_flags.items[r]);
219 msg = newmsg;
220 }
221 }
222 }
223
224 for (size_t r = 0; r < config.forbid_flags.count; r++) {
225 if (flag_list_contains(&dig_flags, config.forbid_flags.items[r])) {
226 result = STATE_CRITICAL;
227 if (!msg) {
228 xasprintf(&msg, _("Forbidden DNS flag present: %s"),
229 config.forbid_flags.items[r]);
230 } else {
231 char *newmsg = NULL;
232 xasprintf(&newmsg, _("%s; forbidden DNS flag present: %s"), msg,
233 config.forbid_flags.items[r]);
234 msg = newmsg;
235 }
236 }
237 }
238 }
239 }
240
241 /* cleanup flags buffer */
242 free_flag_list(&dig_flags);
243
175 printf("DNS %s - %.3f seconds response time (%s)|%s\n", state_text(result), elapsed_time, 244 printf("DNS %s - %.3f seconds response time (%s)|%s\n", state_text(result), elapsed_time,
176 msg ? msg : _("Probably a non-existent host/domain"), 245 msg ? msg : _("Probably a non-existent host/domain"),
177 fperfdata("time", elapsed_time, "s", (config.warning_interval > UNDEFINED), config.warning_interval, 246 fperfdata("time", elapsed_time, "s", (config.warning_interval > UNDEFINED),
178 (config.critical_interval > UNDEFINED), config.critical_interval, true, 0, false, 0)); 247 config.warning_interval, (config.critical_interval > UNDEFINED),
248 config.critical_interval, true, 0, false, 0));
179 exit(result); 249 exit(result);
180} 250}
181 251
@@ -187,6 +257,8 @@ check_dig_config_wrapper process_arguments(int argc, char **argv) {
187 {"critical", required_argument, 0, 'c'}, 257 {"critical", required_argument, 0, 'c'},
188 {"timeout", required_argument, 0, 't'}, 258 {"timeout", required_argument, 0, 't'},
189 {"dig-arguments", required_argument, 0, 'A'}, 259 {"dig-arguments", required_argument, 0, 'A'},
260 {"require-flags", required_argument, 0, 'E'},
261 {"forbid-flags", required_argument, 0, 'X'},
190 {"verbose", no_argument, 0, 'v'}, 262 {"verbose", no_argument, 0, 'v'},
191 {"version", no_argument, 0, 'V'}, 263 {"version", no_argument, 0, 'V'},
192 {"help", no_argument, 0, 'h'}, 264 {"help", no_argument, 0, 'h'},
@@ -209,7 +281,8 @@ check_dig_config_wrapper process_arguments(int argc, char **argv) {
209 281
210 int option = 0; 282 int option = 0;
211 while (true) { 283 while (true) {
212 int option_index = getopt_long(argc, argv, "hVvt:l:H:w:c:T:p:a:A:46", longopts, &option); 284 int option_index =
285 getopt_long(argc, argv, "hVvt:l:H:w:c:T:p:a:A:E:X:46", longopts, &option);
213 286
214 if (option_index == -1 || option_index == EOF) { 287 if (option_index == -1 || option_index == EOF) {
215 break; 288 break;
@@ -260,6 +333,12 @@ check_dig_config_wrapper process_arguments(int argc, char **argv) {
260 case 'A': /* dig arguments */ 333 case 'A': /* dig arguments */
261 result.config.dig_args = strdup(optarg); 334 result.config.dig_args = strdup(optarg);
262 break; 335 break;
336 case 'E': /* require flags */
337 result.config.require_flags = split_csv_trim(optarg);
338 break;
339 case 'X': /* forbid flags */
340 result.config.forbid_flags = split_csv_trim(optarg);
341 break;
263 case 'v': /* verbose */ 342 case 'v': /* verbose */
264 verbose++; 343 verbose++;
265 break; 344 break;
@@ -335,10 +414,15 @@ void print_help(void) {
335 printf(" %s\n", "-T, --record_type=STRING"); 414 printf(" %s\n", "-T, --record_type=STRING");
336 printf(" %s\n", _("Record type to lookup (default: A)")); 415 printf(" %s\n", _("Record type to lookup (default: A)"));
337 printf(" %s\n", "-a, --expected_address=STRING"); 416 printf(" %s\n", "-a, --expected_address=STRING");
338 printf(" %s\n", _("An address expected to be in the answer section. If not set, uses whatever")); 417 printf(" %s\n",
418 _("An address expected to be in the answer section. If not set, uses whatever"));
339 printf(" %s\n", _("was in -l")); 419 printf(" %s\n", _("was in -l"));
340 printf(" %s\n", "-A, --dig-arguments=STRING"); 420 printf(" %s\n", "-A, --dig-arguments=STRING");
341 printf(" %s\n", _("Pass STRING as argument(s) to dig")); 421 printf(" %s\n", _("Pass STRING as argument(s) to dig"));
422 printf(" %s\n", "-E, --require-flags=LIST");
423 printf(" %s\n", _("Comma-separated dig flags that must be present (e.g. 'aa,qr')"));
424 printf(" %s\n", "-X, --forbid-flags=LIST");
425 printf(" %s\n", _("Comma-separated dig flags that must NOT be present"));
342 printf(UT_WARN_CRIT); 426 printf(UT_WARN_CRIT);
343 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 427 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
344 printf(UT_VERBOSE); 428 printf(UT_VERBOSE);
@@ -355,5 +439,185 @@ void print_usage(void) {
355 printf("%s\n", _("Usage:")); 439 printf("%s\n", _("Usage:"));
356 printf("%s -l <query_address> [-H <host>] [-p <server port>]\n", progname); 440 printf("%s -l <query_address> [-H <host>] [-p <server port>]\n", progname);
357 printf(" [-T <query type>] [-w <warning interval>] [-c <critical interval>]\n"); 441 printf(" [-T <query type>] [-w <warning interval>] [-c <critical interval>]\n");
358 printf(" [-t <timeout>] [-a <expected answer address>] [-v]\n"); 442 printf(" [-t <timeout>] [-a <expected answer address>] [-E <flags>] [-X <flags>] [-v]\n");
443}
444
445/* helpers */
446
447/**
448 * parse_flags_line - Parse a dig output line and extract DNS header flags.
449 *
450 * Input:
451 * line - NUL terminated dig output line, e.g. ";; flags: qr rd ra; ..."
452 *
453 * Returns:
454 * flag_list where:
455 * - items: array of NUL terminated flag strings (heap allocated)
456 * - count: number of entries in items
457 * On parse failure or if no flags were found, count is 0 and items is NULL.
458 */
459static flag_list parse_flags_line(const char *line) {
460 flag_list result = {.items = NULL, .count = 0};
461
462 if (!line) {
463 return result;
464 }
465
466 /* Locate start of DNS header flags in dig output */
467 const char *p = strstr(line, "flags:");
468 if (!p) {
469 return result;
470 }
471 p += 6; /* skip literal "flags:" */
472
473 /* Skip whitespace after "flags:" */
474 while (*p && isspace((unsigned char)*p)) {
475 p++;
476 }
477
478 /* Flags are terminated by the next semicolon e.g. "qr rd ra;" */
479 const char *q = strchr(p, ';');
480 if (!q) {
481 return result;
482 }
483
484 /* Extract substring containing the flag block */
485 size_t len = (size_t)(q - p);
486 if (len == 0) {
487 return result;
488 }
489
490 char *buf = (char *)malloc(len + 1);
491 if (!buf) {
492 return result;
493 }
494 memcpy(buf, p, len);
495 buf[len] = '\0';
496
497 /* Tokenize flags separated by whitespace */
498 char **arr = NULL;
499 size_t cnt = 0;
500 char *saveptr = NULL;
501 char *tok = strtok_r(buf, " \t", &saveptr);
502
503 while (tok) {
504 /* Expand array for the next flag token */
505 char **tmp = (char **)realloc(arr, (cnt + 1) * sizeof(char *));
506 if (!tmp) {
507 /* On allocation failure keep what we have and return it */
508 break;
509 }
510 arr = tmp;
511 arr[cnt++] = strdup(tok);
512 tok = strtok_r(NULL, " \t", &saveptr);
513 }
514
515 free(buf);
516
517 result.items = arr;
518 result.count = cnt;
519 return result;
520}
521
522/**
523 * split_csv_trim - Split a comma separated string into trimmed tokens.
524 *
525 * Input:
526 * csv - NUL terminated string, e.g. "aa, qr , rd"
527 *
528 * Returns:
529 * flag_list where:
530 * - items: array of NUL terminated tokens (heap allocated, whitespace trimmed)
531 * - count: number of tokens
532 * On empty input, count is 0 and items is NULL
533 */
534static flag_list split_csv_trim(const char *csv) {
535 flag_list result = {.items = NULL, .count = 0};
536
537 if (!csv || !*csv) {
538 return result;
539 }
540
541 char *tmp = strdup(csv);
542 if (!tmp) {
543 return result;
544 }
545
546 char *s = tmp;
547 char *token = NULL;
548
549 /* Split CSV by commas, trimming whitespace on each token */
550 while ((token = strsep(&s, ",")) != NULL) {
551 /* trim leading whitespace */
552 while (*token && isspace((unsigned char)*token)) {
553 token++;
554 }
555
556 /* trim trailing whitespace */
557 char *end = token + strlen(token);
558 while (end > token && isspace((unsigned char)end[-1])) {
559 *--end = '\0';
560 }
561
562 if (*token) {
563 /* Expand the items array and append the token */
564 char **arr = (char **)realloc(result.items, (result.count + 1) * sizeof(char *));
565 if (!arr) {
566 /* Allocation failed, stop and return what we have */
567 break;
568 }
569 result.items = arr;
570 result.items[result.count++] = strdup(token);
571 }
572 }
573
574 free(tmp);
575 return result;
576}
577
578/**
579 * flag_list_contains - Case-insensitive membership test in a flag_list.
580 *
581 * Input:
582 * list - pointer to a flag_list
583 * needle - NUL terminated string to search for
584 *
585 * Returns:
586 * true if needle is contained in list (strcasecmp)
587 * false otherwise
588 */
589static bool flag_list_contains(const flag_list *list, const char *needle) {
590 if (!list || !needle || !*needle) {
591 return false;
592 }
593
594 for (size_t i = 0; i < list->count; i++) {
595 if (strcasecmp(list->items[i], needle) == 0) {
596 return true;
597 }
598 }
599 return false;
600}
601
602/**
603 * free_flag_list - Release all heap allocations held by a flag_list.
604 *
605 * Input:
606 * list - pointer to a flag_list whose items were allocated by
607 * parse_flags_line() or split_csv_trim().
608 *
609 * After this call list->items is NULL and list->count is 0.
610 */
611static void free_flag_list(flag_list *list) {
612 if (!list || !list->items) {
613 return;
614 }
615
616 for (size_t i = 0; i < list->count; i++) {
617 free(list->items[i]);
618 }
619 free(list->items);
620
621 list->items = NULL;
622 list->count = 0;
359} 623}
diff --git a/plugins/check_dig.d/config.h b/plugins/check_dig.d/config.h
index a570b633..dd1f58b5 100644
--- a/plugins/check_dig.d/config.h
+++ b/plugins/check_dig.d/config.h
@@ -8,6 +8,11 @@
8#define DEFAULT_TRIES 2 8#define DEFAULT_TRIES 2
9 9
10typedef struct { 10typedef struct {
11 char **items;
12 size_t count;
13} flag_list;
14
15typedef struct {
11 char *query_address; 16 char *query_address;
12 char *record_type; 17 char *record_type;
13 char *expected_address; 18 char *expected_address;
@@ -19,6 +24,8 @@ typedef struct {
19 24
20 double warning_interval; 25 double warning_interval;
21 double critical_interval; 26 double critical_interval;
27 flag_list require_flags;
28 flag_list forbid_flags;
22} check_dig_config; 29} check_dig_config;
23 30
24check_dig_config check_dig_config_init() { 31check_dig_config check_dig_config_init() {
@@ -34,7 +41,8 @@ check_dig_config check_dig_config_init() {
34 41
35 .warning_interval = UNDEFINED, 42 .warning_interval = UNDEFINED,
36 .critical_interval = UNDEFINED, 43 .critical_interval = UNDEFINED,
37 44 .require_flags = {.count = 0, .items = NULL},
45 .forbid_flags = {.count = 0, .items = NULL},
38 }; 46 };
39 return tmp; 47 return tmp;
40} 48}
diff --git a/plugins/check_disk.c b/plugins/check_disk.c
index 037a6f7a..d42b5486 100644
--- a/plugins/check_disk.c
+++ b/plugins/check_disk.c
@@ -31,24 +31,35 @@ const char *program_name = "check_disk"; /* Required for coreutils libs */
31const char *copyright = "1999-2024"; 31const char *copyright = "1999-2024";
32const char *email = "devel@monitoring-plugins.org"; 32const char *email = "devel@monitoring-plugins.org";
33 33
34#include "states.h"
34#include "common.h" 35#include "common.h"
36#include "output.h"
37#include "perfdata.h"
38#include "utils_base.h"
39#include "lib/thresholds.h"
40
35#ifdef HAVE_SYS_STAT_H 41#ifdef HAVE_SYS_STAT_H
36# include <sys/stat.h> 42# include <sys/stat.h>
37#endif 43#endif
44
38#if HAVE_INTTYPES_H 45#if HAVE_INTTYPES_H
39# include <inttypes.h> 46# include <inttypes.h>
40#endif 47#endif
48
41#include <assert.h> 49#include <assert.h>
42#include "popen.h"
43#include "utils.h"
44#include "utils_disk.h"
45#include <stdarg.h> 50#include <stdarg.h>
46#include "fsusage.h" 51#include <stdint.h>
47#include "mountlist.h"
48#include <float.h> 52#include <float.h>
53#include "./popen.h"
54#include "./utils.h"
55#include "../gl/fsusage.h"
56#include "../gl/mountlist.h"
57#include "./check_disk.d/utils_disk.h"
58
49#if HAVE_LIMITS_H 59#if HAVE_LIMITS_H
50# include <limits.h> 60# include <limits.h>
51#endif 61#endif
62
52#include "regex.h" 63#include "regex.h"
53 64
54#ifdef __CYGWIN__ 65#ifdef __CYGWIN__
@@ -57,424 +68,322 @@ const char *email = "devel@monitoring-plugins.org";
57# define ERROR -1 68# define ERROR -1
58#endif 69#endif
59 70
60/* If nonzero, show even filesystems with zero size or
61 uninteresting types. */
62static int show_all_fs = 1;
63
64/* If nonzero, show only local filesystems. */
65static int show_local_fs = 0;
66
67/* If nonzero, show only local filesystems but call stat() on remote ones. */
68static int stat_remote_fs = 0;
69
70/* If positive, the units to use when printing sizes;
71 if negative, the human-readable base. */
72/* static int output_block_size; */
73
74/* If nonzero, invoke the `sync' system call before getting any usage data.
75 Using this option can make df very slow, especially with many or very
76 busy disks. Note that this may make a difference on some systems --
77 SunOs4.1.3, for one. It is *not* necessary on Linux. */
78/* static int require_sync = 0; */
79
80/* Linked list of filesystem types to display.
81 If `fs_select_list' is NULL, list all types.
82 This table is generated dynamically from command-line options,
83 rather than hardcoding into the program what it thinks are the
84 valid filesystem types; let the user specify any filesystem type
85 they want to, and if there are any filesystems of that type, they
86 will be shown.
87
88 Some filesystem types:
89 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
90
91/* static struct parameter_list *fs_select_list; */
92
93/* Linked list of filesystem types to omit.
94 If the list is empty, don't exclude any types. */
95static struct regex_list *fs_exclude_list = NULL;
96
97/* Linked list of filesystem types to check.
98 If the list is empty, include all types. */
99static struct regex_list *fs_include_list;
100
101static struct name_list *dp_exclude_list;
102
103static struct parameter_list *path_select_list = NULL;
104
105/* Linked list of mounted filesystems. */
106static struct mount_entry *mount_list;
107
108/* For long options that have no equivalent short option, use a
109 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
110enum {
111 SYNC_OPTION = CHAR_MAX + 1,
112 NO_SYNC_OPTION,
113 BLOCK_SIZE_OPTION
114};
115
116#ifdef _AIX 71#ifdef _AIX
117# pragma alloca 72# pragma alloca
118#endif 73#endif
119 74
120static int process_arguments(int /*argc*/, char ** /*argv*/); 75typedef struct {
121static void set_all_thresholds(struct parameter_list *path); 76 int errorcode;
122static void print_help(void); 77 check_disk_config config;
78} check_disk_config_wrapper;
79static check_disk_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
80
81static void set_all_thresholds(parameter_list_elem *path, char *warn_freespace_units,
82 char *crit_freespace_units, char *warn_freespace_percent,
83 char *crit_freespace_percent, char *warn_freeinodes_percent,
84 char *crit_freeinodes_percent);
85static double calculate_percent(uintmax_t /*value*/, uintmax_t /*total*/);
86static bool stat_path(parameter_list_elem * /*parameters*/, bool /*ignore_missing*/);
87
88/*
89 * Puts the values from a struct fs_usage into a parameter_list with an additional flag to control
90 * how reserved and inodes should be judged (ignored or not)
91 */
92static parameter_list_elem get_path_stats(parameter_list_elem parameters, struct fs_usage fsp,
93 bool freespace_ignore_reserved);
94static mp_subcheck evaluate_filesystem(measurement_unit measurement_unit,
95 bool display_inodes_perfdata, byte_unit unit);
96
123void print_usage(void); 97void print_usage(void);
124static double calculate_percent(uintmax_t, uintmax_t); 98static void print_help(void);
125static bool stat_path(struct parameter_list *p);
126static void get_stats(struct parameter_list *p, struct fs_usage *fsp);
127static void get_path_stats(struct parameter_list *p, struct fs_usage *fsp);
128 99
129static char *units;
130static uintmax_t mult = 1024 * 1024;
131static int verbose = 0; 100static int verbose = 0;
132static bool erronly = false;
133static bool display_mntp = false;
134static bool exact_match = false;
135static bool ignore_missing = false;
136static bool freespace_ignore_reserved = false;
137static bool display_inodes_perfdata = false;
138static char *warn_freespace_units = NULL;
139static char *crit_freespace_units = NULL;
140static char *warn_freespace_percent = NULL;
141static char *crit_freespace_percent = NULL;
142static char *warn_usedspace_units = NULL;
143static char *crit_usedspace_units = NULL;
144static char *warn_usedspace_percent = NULL;
145static char *crit_usedspace_percent = NULL;
146static char *warn_usedinodes_percent = NULL;
147static char *crit_usedinodes_percent = NULL;
148static char *warn_freeinodes_percent = NULL;
149static char *crit_freeinodes_percent = NULL;
150static bool path_selected = false;
151static bool path_ignored = false;
152static char *group = NULL;
153static struct stat *stat_buf;
154static struct name_list *seen = NULL;
155 101
156int main(int argc, char **argv) { 102// This would not be necessary in C23!!
157 int result = STATE_UNKNOWN; 103const byte_unit Bytes_Factor = 1;
158 int disk_result = STATE_UNKNOWN; 104const byte_unit KibiBytes_factor = 1024;
159 char *output = NULL; 105const byte_unit MebiBytes_factor = 1048576;
160 char *ignored = NULL; 106const byte_unit GibiBytes_factor = 1073741824;
161 char *details = NULL; 107const byte_unit TebiBytes_factor = 1099511627776;
162 char *perf = NULL; 108const byte_unit PebiBytes_factor = 1125899906842624;
163 char *perf_ilabel = NULL; 109const byte_unit ExbiBytes_factor = 1152921504606846976;
164 char *preamble = " - free space:"; 110const byte_unit KiloBytes_factor = 1000;
165 char *ignored_preamble = " - ignored paths:"; 111const byte_unit MegaBytes_factor = 1000000;
166 char *flag_header = NULL; 112const byte_unit GigaBytes_factor = 1000000000;
167 int temp_result = STATE_UNKNOWN; 113const byte_unit TeraBytes_factor = 1000000000000;
168 114const byte_unit PetaBytes_factor = 1000000000000000;
169 struct mount_entry *me = NULL; 115const byte_unit ExaBytes_factor = 1000000000000000000;
170 struct fs_usage fsp = {0};
171 struct parameter_list *temp_list = NULL;
172 struct parameter_list *path = NULL;
173
174#ifdef __CYGWIN__
175 char mountdir[32];
176#endif
177
178 output = strdup("");
179 ignored = strdup("");
180 details = strdup("");
181 perf = strdup("");
182 perf_ilabel = strdup("");
183 stat_buf = malloc(sizeof *stat_buf);
184 116
117int main(int argc, char **argv) {
185 setlocale(LC_ALL, ""); 118 setlocale(LC_ALL, "");
186 bindtextdomain(PACKAGE, LOCALEDIR); 119 bindtextdomain(PACKAGE, LOCALEDIR);
187 textdomain(PACKAGE); 120 textdomain(PACKAGE);
188 121
189 mount_list = read_file_system_list(0); 122#ifdef __CYGWIN__
123 char mountdir[32];
124#endif
190 125
191 /* Parse extra opts if any */ 126 // Parse extra opts if any
192 argv = np_extra_opts(&argc, argv, progname); 127 argv = np_extra_opts(&argc, argv, progname);
193 128
194 if (process_arguments(argc, argv) == ERROR) 129 check_disk_config_wrapper tmp_config = process_arguments(argc, argv);
130 if (tmp_config.errorcode == ERROR) {
195 usage4(_("Could not parse arguments")); 131 usage4(_("Could not parse arguments"));
132 }
196 133
197 /* If a list of paths has not been selected, find entire 134 check_disk_config config = tmp_config.config;
198 mount list and create list of paths 135
199 */ 136 if (config.output_format_is_set) {
200 if (path_selected == false && path_ignored == false) { 137 mp_set_format(config.output_format);
201 for (me = mount_list; me; me = me->me_next) {
202 if (!(path = np_find_parameter(path_select_list, me->me_mountdir))) {
203 path = np_add_parameter(&path_select_list, me->me_mountdir);
204 }
205 path->best_match = me;
206 path->group = group;
207 set_all_thresholds(path);
208 }
209 } 138 }
210 139
211 if (path_ignored == false) { 140 if (config.erronly) {
212 np_set_best_match(path_select_list, mount_list, exact_match); 141 mp_set_level_of_detail(MP_DETAIL_NON_OK_ONLY);
213 } 142 }
214 143
215 /* Error if no match found for specified paths */ 144 if (!config.path_ignored) {
216 temp_list = path_select_list; 145 mp_int_fs_list_set_best_match(config.path_select_list, config.mount_list,
146 config.exact_match);
147 }
217 148
218 while (path_select_list) { 149 // Error if no match found for specified paths
219 if (!path_select_list->best_match && ignore_missing == true) { 150 for (parameter_list_elem *elem = config.path_select_list.first; elem;) {
220 /* If the first element will be deleted, the temp_list must be updated with the new start address as well */ 151 if (!elem->best_match && config.ignore_missing) {
221 if (path_select_list == temp_list) {
222 temp_list = path_select_list->name_next;
223 }
224 /* Add path argument to list of ignored paths to inform about missing paths being ignored and not alerted */
225 xasprintf(&ignored, "%s %s;", ignored, path_select_list->name);
226 /* Delete the path from the list so that it is not stat-checked later in the code. */ 152 /* Delete the path from the list so that it is not stat-checked later in the code. */
227 path_select_list = np_del_parameter(path_select_list, path_select_list->name_prev); 153 elem = mp_int_fs_list_del(&config.path_select_list, elem);
228 } else if (!path_select_list->best_match) { 154 continue;
155 }
156 if (!elem->best_match) {
229 /* Without --ignore-missing option, exit with Critical state. */ 157 /* Without --ignore-missing option, exit with Critical state. */
230 die(STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), path_select_list->name); 158 die(STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), elem->name);
231 } else {
232 /* Continue jumping through the list */
233 path_select_list = path_select_list->name_next;
234 } 159 }
235 }
236 160
237 path_select_list = temp_list; 161 elem = mp_int_fs_list_get_next(elem);
162 }
238 163
239 if (!path_select_list && ignore_missing == true) { 164 mp_check overall = mp_check_init();
240 result = STATE_OK; 165 if (config.path_select_list.length == 0) {
241 if (verbose >= 2) { 166 mp_subcheck none_sc = mp_subcheck_init();
242 printf("None of the provided paths were found\n"); 167 xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
168 if (config.ignore_missing) {
169 none_sc = mp_set_subcheck_state(none_sc, STATE_OK);
170 } else {
171 none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN);
172 if (verbose >= 2) {
173 printf("None of the provided paths were found\n");
174 }
243 } 175 }
176 mp_add_subcheck_to_check(&overall, none_sc);
177 mp_exit(overall);
244 } 178 }
245 179
246 /* Process for every path in list */ 180 // Filter list first
247 for (path = path_select_list; path; path = path->name_next) { 181 for (parameter_list_elem *path = config.path_select_list.first; path;) {
248 if (verbose >= 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL) 182 if (!path->best_match) {
249 printf("Thresholds(pct) for %s warn: %f crit %f\n", path->name, path->freespace_percent->warning->end, 183 path = mp_int_fs_list_del(&config.path_select_list, path);
250 path->freespace_percent->critical->end);
251
252 if (verbose >= 3 && path->group != NULL)
253 printf("Group of %s: %s\n", path->name, path->group);
254
255 /* reset disk result */
256 disk_result = STATE_UNKNOWN;
257
258 me = path->best_match;
259
260 if (!me) {
261 continue; 184 continue;
262 } 185 }
263 186
187 struct mount_entry *mount_entry = path->best_match;
188
264#ifdef __CYGWIN__ 189#ifdef __CYGWIN__
265 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) 190 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) {
191 path = mp_int_fs_list_del(&config.path_select_list, path);
266 continue; 192 continue;
193 }
194
195 char *mountdir = NULL;
267 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10); 196 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10);
268 if (GetDriveType(mountdir) != DRIVE_FIXED) 197 if (GetDriveType(mountdir) != DRIVE_FIXED) {
269 me->me_remote = 1; 198 mount_entry->me_remote = 1;
199 }
270#endif 200#endif
271 /* Filters */
272 201
273 /* Remove filesystems already seen */ 202 /* Remove filesystems already seen */
274 if (np_seen_name(seen, me->me_mountdir)) { 203 if (np_seen_name(config.seen, mount_entry->me_mountdir)) {
204 path = mp_int_fs_list_del(&config.path_select_list, path);
275 continue; 205 continue;
276 } 206 }
277 np_add_name(&seen, me->me_mountdir);
278 207
279 if (path->group == NULL) { 208 if (path->group == NULL) {
280 /* Skip remote filesystems if we're not interested in them */ 209 if (config.fs_exclude_list &&
281 if (me->me_remote && show_local_fs) { 210 np_find_regmatch(config.fs_exclude_list, mount_entry->me_type)) {
282 if (stat_remote_fs) { 211 // Skip excluded fs's
283 if (!stat_path(path) && ignore_missing == true) { 212 path = mp_int_fs_list_del(&config.path_select_list, path);
284 result = STATE_OK;
285 xasprintf(&ignored, "%s %s;", ignored, path->name);
286 }
287 }
288 continue; 213 continue;
289 /* Skip pseudo fs's if we haven't asked for all fs's */
290 } 214 }
291 if (me->me_dummy && !show_all_fs) { 215
292 continue; 216 if (config.device_path_exclude_list &&
293 /* Skip excluded fstypes */ 217 (np_find_name(config.device_path_exclude_list, mount_entry->me_devname) ||
294 } 218 np_find_name(config.device_path_exclude_list, mount_entry->me_mountdir))) {
295 if (fs_exclude_list && np_find_regmatch(fs_exclude_list, me->me_type)) { 219 // Skip excluded device or mount paths
220 path = mp_int_fs_list_del(&config.path_select_list, path);
296 continue; 221 continue;
297 /* Skip excluded fs's */
298 } 222 }
299 if (dp_exclude_list && (np_find_name(dp_exclude_list, me->me_devname) || np_find_name(dp_exclude_list, me->me_mountdir))) { 223
224 if (config.fs_include_list &&
225 !np_find_regmatch(config.fs_include_list, mount_entry->me_type)) {
226 // Skip not included fstypes
227 path = mp_int_fs_list_del(&config.path_select_list, path);
300 continue; 228 continue;
301 /* Skip not included fstypes */
302 } 229 }
303 if (fs_include_list && !np_find_regmatch(fs_include_list, me->me_type)) { 230
231 /* Skip remote filesystems if we're not interested in them */
232 if (mount_entry->me_remote && config.show_local_fs) {
233 if (config.stat_remote_fs) {
234 // TODO Stat here
235 if (!stat_path(path, config.ignore_missing) && config.ignore_missing) {
236 }
237 }
304 continue; 238 continue;
305 } 239 }
306 }
307 240
308 if (!stat_path(path)) { 241 // TODO why stat here? remove unstatable fs?
309 if (ignore_missing == true) { 242 if (!stat_path(path, config.ignore_missing)) {
310 result = STATE_OK; 243 // if (config.ignore_missing) {
311 xasprintf(&ignored, "%s %s;", ignored, path->name); 244 // xasprintf(&ignored, "%s %s;", ignored, path->name);
245 // }
246 // not accessible, remove from list
247 path = mp_int_fs_list_del(&config.path_select_list, path);
248 continue;
312 } 249 }
313 continue;
314 } 250 }
315 get_fs_usage(me->me_mountdir, me->me_devname, &fsp);
316
317 if (fsp.fsu_blocks && strcmp("none", me->me_mountdir)) {
318 get_stats(path, &fsp);
319
320 if (verbose >= 3) {
321 printf("For %s, used_pct=%f free_pct=%f used_units=%lu free_units=%lu total_units=%lu used_inodes_pct=%f "
322 "free_inodes_pct=%f fsp.fsu_blocksize=%lu mult=%lu\n",
323 me->me_mountdir, path->dused_pct, path->dfree_pct, path->dused_units, path->dfree_units, path->dtotal_units,
324 path->dused_inodes_percent, path->dfree_inodes_percent, fsp.fsu_blocksize, mult);
325 }
326
327 /* Threshold comparisons */
328
329 temp_result = get_status(path->dfree_units, path->freespace_units);
330 if (verbose >= 3)
331 printf("Freespace_units result=%d\n", temp_result);
332 disk_result = max_state(disk_result, temp_result);
333
334 temp_result = get_status(path->dfree_pct, path->freespace_percent);
335 if (verbose >= 3)
336 printf("Freespace%% result=%d\n", temp_result);
337 disk_result = max_state(disk_result, temp_result);
338 251
339 temp_result = get_status(path->dused_units, path->usedspace_units); 252 path = mp_int_fs_list_get_next(path);
340 if (verbose >= 3) 253 }
341 printf("Usedspace_units result=%d\n", temp_result);
342 disk_result = max_state(disk_result, temp_result);
343
344 temp_result = get_status(path->dused_pct, path->usedspace_percent);
345 if (verbose >= 3)
346 printf("Usedspace_percent result=%d\n", temp_result);
347 disk_result = max_state(disk_result, temp_result);
348
349 temp_result = get_status(path->dused_inodes_percent, path->usedinodes_percent);
350 if (verbose >= 3)
351 printf("Usedinodes_percent result=%d\n", temp_result);
352 disk_result = max_state(disk_result, temp_result);
353
354 temp_result = get_status(path->dfree_inodes_percent, path->freeinodes_percent);
355 if (verbose >= 3)
356 printf("Freeinodes_percent result=%d\n", temp_result);
357 disk_result = max_state(disk_result, temp_result);
358
359 result = max_state(result, disk_result);
360
361 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
362 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
363 data. Assumption that start=0. Roll on new syntax...
364 */
365
366 /* *_high_tide must be reinitialized at each run */
367 uint64_t warning_high_tide = UINT64_MAX;
368 254
369 if (path->freespace_units->warning != NULL) { 255 // now get the actual measurements
370 warning_high_tide = (path->dtotal_units - path->freespace_units->warning->end) * mult; 256 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;) {
371 } 257 // Get actual metrics here
372 if (path->freespace_percent->warning != NULL) { 258 struct mount_entry *mount_entry = filesystem->best_match;
373 warning_high_tide = 259 struct fs_usage fsp = {0};
374 min(warning_high_tide, (uint64_t)((1.0 - path->freespace_percent->warning->end / 100) * (path->dtotal_units * mult))); 260 get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp);
375 }
376 261
377 uint64_t critical_high_tide = UINT64_MAX; 262 if (fsp.fsu_blocks != 0 && strcmp("none", mount_entry->me_mountdir) != 0) {
263 *filesystem = get_path_stats(*filesystem, fsp, config.freespace_ignore_reserved);
378 264
379 if (path->freespace_units->critical != NULL) { 265 if (verbose >= 3) {
380 critical_high_tide = (path->dtotal_units - path->freespace_units->critical->end) * mult; 266 printf("For %s, used_units=%lu free_units=%lu total_units=%lu "
381 } 267 "fsp.fsu_blocksize=%lu\n",
382 if (path->freespace_percent->critical != NULL) { 268 mount_entry->me_mountdir, filesystem->used_bytes, filesystem->free_bytes,
383 critical_high_tide = 269 filesystem->total_bytes, fsp.fsu_blocksize);
384 min(critical_high_tide, (uint64_t)((1.0 - path->freespace_percent->critical->end / 100) * (path->dtotal_units * mult)));
385 } 270 }
271 } else {
272 // failed to retrieve file system data or not mounted?
273 filesystem = mp_int_fs_list_del(&config.path_select_list, filesystem);
274 continue;
275 }
276 filesystem = mp_int_fs_list_get_next(filesystem);
277 }
386 278
387 /* Nb: *_high_tide are unset when == UINT64_MAX */ 279 if (verbose > 2) {
388 xasprintf(&perf, "%s %s", perf, 280 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;
389 perfdata_uint64((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir, 281 filesystem = mp_int_fs_list_get_next(filesystem)) {
390 path->dused_units * mult, "B", (warning_high_tide == UINT64_MAX ? false : true), warning_high_tide, 282 assert(filesystem->best_match != NULL);
391 (critical_high_tide == UINT64_MAX ? false : true), critical_high_tide, true, 0, true, 283 if (filesystem->best_match == NULL) {
392 path->dtotal_units * mult)); 284 printf("Filesystem path %s has no mount_entry!\n", filesystem->name);
393 285 } else {
394 if (display_inodes_perfdata) { 286 // printf("Filesystem path %s has a mount_entry!\n", filesystem->name);
395 /* *_high_tide must be reinitialized at each run */
396 warning_high_tide = UINT64_MAX;
397 critical_high_tide = UINT64_MAX;
398
399 if (path->freeinodes_percent->warning != NULL) {
400 warning_high_tide = (uint64_t)fabs(
401 min((double)warning_high_tide, (double)(1.0 - path->freeinodes_percent->warning->end / 100) * path->inodes_total));
402 }
403 if (path->freeinodes_percent->critical != NULL) {
404 critical_high_tide = (uint64_t)fabs(min(
405 (double)critical_high_tide, (double)(1.0 - path->freeinodes_percent->critical->end / 100) * path->inodes_total));
406 }
407
408 xasprintf(&perf_ilabel, "%s (inodes)",
409 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir);
410 /* Nb: *_high_tide are unset when == UINT64_MAX */
411 xasprintf(&perf, "%s %s", perf,
412 perfdata_uint64(perf_ilabel, path->inodes_used, "", (warning_high_tide != UINT64_MAX ? true : false),
413 warning_high_tide, (critical_high_tide != UINT64_MAX ? true : false), critical_high_tide, true, 0,
414 true, path->inodes_total));
415 } 287 }
288 }
289 }
416 290
417 if (disk_result == STATE_OK && erronly && !verbose) 291 measurement_unit_list *measurements = NULL;
418 continue; 292 measurement_unit_list *current = NULL;
419 293 // create measuring units, because of groups
420 if (disk_result && verbose >= 1) { 294 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;
421 xasprintf(&flag_header, " %s [", state_text(disk_result)); 295 filesystem = mp_int_fs_list_get_next(filesystem)) {
296 assert(filesystem->best_match != NULL);
297
298 if (filesystem->group == NULL) {
299 // create a measurement unit for the fs
300 measurement_unit unit =
301 create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
302 if (measurements == NULL) {
303 measurements = current = add_measurement_list(NULL, unit);
422 } else { 304 } else {
423 xasprintf(&flag_header, ""); 305 current = add_measurement_list(measurements, unit);
424 } 306 }
425 xasprintf(&output, "%s%s %s %llu%s (%.1f%%", output, flag_header, 307 } else {
426 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir, path->dfree_units, units, 308 // Grouped elements are consecutive
427 path->dfree_pct); 309 if (measurements == NULL) {
428 if (path->dused_inodes_percent < 0) { 310 // first entry
429 xasprintf(&output, "%s inode=-)%s;", output, (disk_result ? "]" : "")); 311 measurement_unit unit =
312 create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
313 unit.name = strdup(filesystem->group);
314 measurements = current = add_measurement_list(NULL, unit);
430 } else { 315 } else {
431 xasprintf(&output, "%s inode=%.0f%%)%s;", output, path->dfree_inodes_percent, ((disk_result && verbose >= 1) ? "]" : "")); 316 // if this is the first element of a group, the name of the previous entry is
317 // different
318 if (strcmp(filesystem->group, current->unit.name) != 0) {
319 // so, this must be the first element of a group
320 measurement_unit unit =
321 create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
322 unit.name = filesystem->group;
323 current = add_measurement_list(measurements, unit);
324
325 } else {
326 // NOT the first entry of a group, add info to the other one
327 current->unit = add_filesystem_to_measurement_unit(current->unit, *filesystem);
328 }
432 } 329 }
433 free(flag_header);
434 } 330 }
435 } 331 }
436 332
437 if (verbose >= 2) 333 /* Process for every path in list */
438 xasprintf(&output, "%s%s", output, details); 334 if (measurements != NULL) {
335 for (measurement_unit_list *unit = measurements; unit; unit = unit->next) {
336 mp_subcheck unit_sc = evaluate_filesystem(unit->unit, config.display_inodes_perfdata,
337 config.display_unit);
338 mp_add_subcheck_to_check(&overall, unit_sc);
339 }
340 } else {
341 // Apparently no machting fs found
342 mp_subcheck none_sc = mp_subcheck_init();
343 xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
439 344
440 if (strcmp(output, "") == 0 && !erronly) { 345 if (config.ignore_missing) {
441 preamble = ""; 346 none_sc = mp_set_subcheck_state(none_sc, STATE_OK);
442 xasprintf(&output, " - No disks were found for provided parameters"); 347 } else {
348 none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN);
349 }
350 mp_add_subcheck_to_check(&overall, none_sc);
443 } 351 }
444 352
445 printf("DISK %s%s%s%s%s|%s\n", state_text(result), ((erronly && result == STATE_OK)) ? "" : preamble, output, 353 mp_exit(overall);
446 (strcmp(ignored, "") == 0) ? "" : ignored_preamble, ignored, perf);
447 return result;
448} 354}
449 355
450double calculate_percent(uintmax_t value, uintmax_t total) { 356double calculate_percent(uintmax_t value, uintmax_t total) {
451 double pct = -1; 357 double pct = -1;
452 if (value <= DBL_MAX && total != 0) { 358 if (value <= DBL_MAX && total != 0) {
453 pct = (double)value / total * 100.0; 359 pct = (double)value / (double)total * 100.0;
454 } 360 }
361
455 return pct; 362 return pct;
456} 363}
457 364
458/* process command-line arguments */ 365/* process command-line arguments */
459int process_arguments(int argc, char **argv) { 366check_disk_config_wrapper process_arguments(int argc, char **argv) {
460 int c; 367
461 int err; 368 check_disk_config_wrapper result = {
462 struct parameter_list *se; 369 .errorcode = OK,
463 struct parameter_list *temp_list = NULL; 370 .config = check_disk_config_init(),
464 struct parameter_list *previous = NULL; 371 };
465 struct mount_entry *me; 372
466 regex_t re; 373 if (argc < 2) {
467 int cflags = REG_NOSUB | REG_EXTENDED; 374 result.errorcode = ERROR;
468 int default_cflags = cflags; 375 return result;
469 char errbuf[MAX_INPUT_BUFFER]; 376 }
470 int fnd = 0; 377
378 enum {
379 output_format_index = CHAR_MAX + 1,
380 display_unit_index,
381 };
471 382
472 int option = 0;
473 static struct option longopts[] = {{"timeout", required_argument, 0, 't'}, 383 static struct option longopts[] = {{"timeout", required_argument, 0, 't'},
474 {"warning", required_argument, 0, 'w'}, 384 {"warning", required_argument, 0, 'w'},
475 {"critical", required_argument, 0, 'c'}, 385 {"critical", required_argument, 0, 'c'},
476 {"iwarning", required_argument, 0, 'W'}, 386 {"iwarning", required_argument, 0, 'W'},
477 /* Dang, -C is taken. We might want to reshuffle this. */
478 {"icritical", required_argument, 0, 'K'}, 387 {"icritical", required_argument, 0, 'K'},
479 {"kilobytes", no_argument, 0, 'k'}, 388 {"kilobytes", no_argument, 0, 'k'},
480 {"megabytes", no_argument, 0, 'm'}, 389 {"megabytes", no_argument, 0, 'm'},
@@ -507,24 +416,43 @@ int process_arguments(int argc, char **argv) {
507 {"clear", no_argument, 0, 'C'}, 416 {"clear", no_argument, 0, 'C'},
508 {"version", no_argument, 0, 'V'}, 417 {"version", no_argument, 0, 'V'},
509 {"help", no_argument, 0, 'h'}, 418 {"help", no_argument, 0, 'h'},
419 {"output-format", required_argument, 0, output_format_index},
420 {"display-unit", required_argument, 0, display_unit_index},
510 {0, 0, 0, 0}}; 421 {0, 0, 0, 0}};
511 422
512 if (argc < 2) 423 for (int index = 1; index < argc; index++) {
513 return ERROR; 424 if (strcmp("-to", argv[index]) == 0) {
425 strcpy(argv[index], "-t");
426 }
427 }
428
429 int cflags = REG_NOSUB | REG_EXTENDED;
430 int default_cflags = cflags;
431 char *warn_freespace_units = NULL;
432 char *crit_freespace_units = NULL;
433 char *warn_freespace_percent = NULL;
434 char *crit_freespace_percent = NULL;
435 char *warn_freeinodes_percent = NULL;
436 char *crit_freeinodes_percent = NULL;
514 437
515 np_add_regex(&fs_exclude_list, "iso9660", REG_EXTENDED); 438 bool path_selected = false;
439 char *group = NULL;
440 byte_unit unit = MebiBytes_factor;
516 441
517 for (c = 1; c < argc; c++) 442 result.config.mount_list = read_file_system_list(false);
518 if (strcmp("-to", argv[c]) == 0)
519 strcpy(argv[c], "-t");
520 443
521 while (1) { 444 np_add_regex(&result.config.fs_exclude_list, "iso9660", REG_EXTENDED);
522 c = getopt_long(argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEAn", longopts, &option);
523 445
524 if (c == -1 || c == EOF) 446 while (true) {
447 int option = 0;
448 int option_index = getopt_long(
449 argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEAn", longopts, &option);
450
451 if (option_index == -1 || option_index == EOF) {
525 break; 452 break;
453 }
526 454
527 switch (c) { 455 switch (option_index) {
528 case 't': /* timeout period */ 456 case 't': /* timeout period */
529 if (is_integer(optarg)) { 457 if (is_integer(optarg)) {
530 timeout_interval = atoi(optarg); 458 timeout_interval = atoi(optarg);
@@ -555,10 +483,10 @@ int process_arguments(int argc, char **argv) {
555 break; 483 break;
556 484
557 /* Awful mistake where the range values do not make sense. Normally, 485 /* Awful mistake where the range values do not make sense. Normally,
558 you alert if the value is within the range, but since we are using 486 * you alert if the value is within the range, but since we are using
559 freespace, we have to alert if outside the range. Thus we artificially 487 * freespace, we have to alert if outside the range. Thus we artificially
560 force @ at the beginning of the range, so that it is backwards compatible 488 * force @ at the beginning of the range, so that it is backwards compatible
561 */ 489 */
562 case 'c': /* critical threshold */ 490 case 'c': /* critical threshold */
563 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) { 491 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) {
564 die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg); 492 die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg);
@@ -594,181 +522,193 @@ int process_arguments(int argc, char **argv) {
594 } 522 }
595 break; 523 break;
596 case 'u': 524 case 'u':
597 if (units)
598 free(units);
599 if (!strcasecmp(optarg, "bytes")) { 525 if (!strcasecmp(optarg, "bytes")) {
600 mult = (uintmax_t)1; 526 unit = Bytes_Factor;
601 units = strdup("B");
602 } else if (!strcmp(optarg, "KiB")) { 527 } else if (!strcmp(optarg, "KiB")) {
603 mult = (uintmax_t)1024; 528 unit = KibiBytes_factor;
604 units = strdup("KiB");
605 } else if (!strcmp(optarg, "kB")) { 529 } else if (!strcmp(optarg, "kB")) {
606 mult = (uintmax_t)1000; 530 unit = KiloBytes_factor;
607 units = strdup("kB");
608 } else if (!strcmp(optarg, "MiB")) { 531 } else if (!strcmp(optarg, "MiB")) {
609 mult = (uintmax_t)1024 * 1024; 532 unit = MebiBytes_factor;
610 units = strdup("MiB");
611 } else if (!strcmp(optarg, "MB")) { 533 } else if (!strcmp(optarg, "MB")) {
612 mult = (uintmax_t)1000 * 1000; 534 unit = MegaBytes_factor;
613 units = strdup("MB");
614 } else if (!strcmp(optarg, "GiB")) { 535 } else if (!strcmp(optarg, "GiB")) {
615 mult = (uintmax_t)1024 * 1024 * 1024; 536 unit = GibiBytes_factor;
616 units = strdup("GiB");
617 } else if (!strcmp(optarg, "GB")) { 537 } else if (!strcmp(optarg, "GB")) {
618 mult = (uintmax_t)1000 * 1000 * 1000; 538 unit = GigaBytes_factor;
619 units = strdup("GB");
620 } else if (!strcmp(optarg, "TiB")) { 539 } else if (!strcmp(optarg, "TiB")) {
621 mult = (uintmax_t)1024 * 1024 * 1024 * 1024; 540 unit = TebiBytes_factor;
622 units = strdup("TiB");
623 } else if (!strcmp(optarg, "TB")) { 541 } else if (!strcmp(optarg, "TB")) {
624 mult = (uintmax_t)1000 * 1000 * 1000 * 1000; 542 unit = TeraBytes_factor;
625 units = strdup("TB");
626 } else if (!strcmp(optarg, "PiB")) { 543 } else if (!strcmp(optarg, "PiB")) {
627 mult = (uintmax_t)1024 * 1024 * 1024 * 1024 * 1024; 544 unit = PebiBytes_factor;
628 units = strdup("PiB");
629 } else if (!strcmp(optarg, "PB")) { 545 } else if (!strcmp(optarg, "PB")) {
630 mult = (uintmax_t)1000 * 1000 * 1000 * 1000 * 1000; 546 unit = PetaBytes_factor;
631 units = strdup("PB");
632 } else { 547 } else {
633 die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg); 548 die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
634 } 549 }
635 if (units == NULL)
636 die(STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
637 break; 550 break;
638 case 'k': /* display mountpoint */ 551 case 'k':
639 mult = 1024; 552 unit = KibiBytes_factor;
640 if (units)
641 free(units);
642 units = strdup("kiB");
643 break; 553 break;
644 case 'm': /* display mountpoint */ 554 case 'm':
645 mult = 1024 * 1024; 555 unit = MebiBytes_factor;
646 if (units) 556 break;
647 free(units); 557 case display_unit_index:
648 units = strdup("MiB"); 558 if (!strcasecmp(optarg, "bytes")) {
559 result.config.display_unit = Bytes;
560 } else if (!strcmp(optarg, "KiB")) {
561 result.config.display_unit = KibiBytes;
562 } else if (!strcmp(optarg, "kB")) {
563 result.config.display_unit = KiloBytes;
564 } else if (!strcmp(optarg, "MiB")) {
565 result.config.display_unit = MebiBytes;
566 } else if (!strcmp(optarg, "MB")) {
567 result.config.display_unit = MegaBytes;
568 } else if (!strcmp(optarg, "GiB")) {
569 result.config.display_unit = GibiBytes;
570 } else if (!strcmp(optarg, "GB")) {
571 result.config.display_unit = GigaBytes;
572 } else if (!strcmp(optarg, "TiB")) {
573 result.config.display_unit = TebiBytes;
574 } else if (!strcmp(optarg, "TB")) {
575 result.config.display_unit = TeraBytes;
576 } else if (!strcmp(optarg, "PiB")) {
577 result.config.display_unit = PebiBytes;
578 } else if (!strcmp(optarg, "PB")) {
579 result.config.display_unit = PetaBytes;
580 } else {
581 die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
582 }
649 break; 583 break;
650 case 'L': 584 case 'L':
651 stat_remote_fs = 1; 585 result.config.stat_remote_fs = true;
652 /* fallthrough */ 586 /* fallthrough */
653 case 'l': 587 case 'l':
654 show_local_fs = 1; 588 result.config.show_local_fs = true;
655 break; 589 break;
656 case 'P': 590 case 'P':
657 display_inodes_perfdata = 1; 591 result.config.display_inodes_perfdata = true;
658 break; 592 break;
659 case 'p': /* select path */ 593 case 'p': /* select path */ {
660 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent || 594 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
661 warn_usedspace_units || crit_usedspace_units || warn_usedspace_percent || crit_usedspace_percent || 595 crit_freespace_percent || warn_freeinodes_percent || crit_freeinodes_percent)) {
662 warn_usedinodes_percent || crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent)) { 596 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
663 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n")); 597 _("Must set a threshold value before using -p\n"));
664 } 598 }
665 599
666 /* add parameter if not found. overwrite thresholds if path has already been added */ 600 /* add parameter if not found. overwrite thresholds if path has already been added */
667 if (!(se = np_find_parameter(path_select_list, optarg))) { 601 parameter_list_elem *search_entry;
668 se = np_add_parameter(&path_select_list, optarg); 602 if (!(search_entry = mp_int_fs_list_find(result.config.path_select_list, optarg))) {
669 603 search_entry = mp_int_fs_list_append(&result.config.path_select_list, optarg);
670 if (stat(optarg, &stat_buf[0]) && ignore_missing == true) { 604
671 path_ignored = true; 605 // struct stat stat_buf = {};
672 break; 606 // if (stat(optarg, &stat_buf) && result.config.ignore_missing) {
673 } 607 // result.config.path_ignored = true;
608 // break;
609 // }
674 } 610 }
675 se->group = group; 611 search_entry->group = group;
676 set_all_thresholds(se); 612 set_all_thresholds(search_entry, warn_freespace_units, crit_freespace_units,
613 warn_freespace_percent, crit_freespace_percent,
614
615 warn_freeinodes_percent, crit_freeinodes_percent);
677 616
678 /* With autofs, it is required to stat() the path before re-populating the mount_list */ 617 /* With autofs, it is required to stat() the path before re-populating the mount_list */
679 if (!stat_path(se)) { 618 // if (!stat_path(se, result.config.ignore_missing)) {
680 break; 619 // break;
681 } 620 // }
682 /* NB: We can't free the old mount_list "just like that": both list pointers and struct 621 mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list,
683 * pointers are copied around. One of the reason it wasn't done yet is that other parts 622 result.config.exact_match);
684 * of check_disk need the same kind of cleanup so it'd better be done as a whole */
685 mount_list = read_file_system_list(0);
686 np_set_best_match(se, mount_list, exact_match);
687 623
688 path_selected = true; 624 path_selected = true;
689 break; 625 } break;
690 case 'x': /* exclude path or partition */ 626 case 'x': /* exclude path or partition */
691 np_add_name(&dp_exclude_list, optarg); 627 np_add_name(&result.config.device_path_exclude_list, optarg);
692 break; 628 break;
693 case 'X': /* exclude file system type */ 629 case 'X': /* exclude file system type */ {
694 err = np_add_regex(&fs_exclude_list, optarg, REG_EXTENDED); 630 int err = np_add_regex(&result.config.fs_exclude_list, optarg, REG_EXTENDED);
695 if (err != 0) { 631 if (err != 0) {
696 regerror(err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER); 632 char errbuf[MAX_INPUT_BUFFER];
697 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf); 633 regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
634 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"),
635 _("Could not compile regular expression"), errbuf);
698 } 636 }
699 break; 637 break;
700 case 'N': /* include file system type */ 638 case 'N': /* include file system type */
701 err = np_add_regex(&fs_include_list, optarg, REG_EXTENDED); 639 err = np_add_regex(&result.config.fs_include_list, optarg, REG_EXTENDED);
702 if (err != 0) { 640 if (err != 0) {
703 regerror(err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER); 641 char errbuf[MAX_INPUT_BUFFER];
704 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf); 642 regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
643 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"),
644 _("Could not compile regular expression"), errbuf);
705 } 645 }
706 break; 646 } break;
707 case 'v': /* verbose */ 647 case 'v': /* verbose */
708 verbose++; 648 verbose++;
709 break; 649 break;
710 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */ 650 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
711 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */ 651 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
712 erronly = true; 652 result.config.erronly = true;
713 break; 653 break;
714 case 'e': 654 case 'e':
715 erronly = true; 655 result.config.erronly = true;
716 break; 656 break;
717 case 'E': 657 case 'E':
718 if (path_selected) 658 if (path_selected) {
719 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n")); 659 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
720 exact_match = true; 660 _("Must set -E before selecting paths\n"));
661 }
662 result.config.exact_match = true;
721 break; 663 break;
722 case 'f': 664 case 'f':
723 freespace_ignore_reserved = true; 665 result.config.freespace_ignore_reserved = true;
724 break; 666 break;
725 case 'g': 667 case 'g':
726 if (path_selected) 668 if (path_selected) {
727 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n")); 669 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
670 _("Must set group value before selecting paths\n"));
671 }
728 group = optarg; 672 group = optarg;
729 break; 673 break;
730 case 'I': 674 case 'I':
731 cflags |= REG_ICASE; 675 cflags |= REG_ICASE;
732 // Intentional fallthrough 676 // Intentional fallthrough
733 case 'i': 677 case 'i': {
734 if (!path_selected) 678 if (!path_selected) {
735 die(STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), 679 die(STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"),
736 _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly")); 680 _("Paths need to be selected before using -i/-I. Use -A to select all paths "
737 err = regcomp(&re, optarg, cflags); 681 "explicitly"));
682 }
683 regex_t regex;
684 int err = regcomp(&regex, optarg, cflags);
738 if (err != 0) { 685 if (err != 0) {
739 regerror(err, &re, errbuf, MAX_INPUT_BUFFER); 686 char errbuf[MAX_INPUT_BUFFER];
740 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf); 687 regerror(err, &regex, errbuf, MAX_INPUT_BUFFER);
688 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"),
689 _("Could not compile regular expression"), errbuf);
741 } 690 }
742 691
743 temp_list = path_select_list; 692 for (parameter_list_elem *elem = result.config.path_select_list.first; elem;) {
693 if (elem->best_match) {
694 if (np_regex_match_mount_entry(elem->best_match, &regex)) {
744 695
745 previous = NULL; 696 if (verbose >= 3) {
746 while (temp_list) { 697 printf("ignoring %s matching regex\n", elem->name);
747 if (temp_list->best_match) { 698 }
748 if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
749 699
750 if (verbose >= 3) 700 elem = mp_int_fs_list_del(&result.config.path_select_list, elem);
751 printf("ignoring %s matching regex\n", temp_list->name); 701 continue;
752
753 temp_list = np_del_parameter(temp_list, previous);
754 /* pointer to first element needs to be updated if first item gets deleted */
755 if (previous == NULL)
756 path_select_list = temp_list;
757 } else {
758 previous = temp_list;
759 temp_list = temp_list->name_next;
760 } 702 }
761 } else {
762 previous = temp_list;
763 temp_list = temp_list->name_next;
764 } 703 }
704
705 elem = mp_int_fs_list_get_next(elem);
765 } 706 }
766 707
767 cflags = default_cflags; 708 cflags = default_cflags;
768 break; 709 } break;
769
770 case 'n': 710 case 'n':
771 ignore_missing = true; 711 result.config.ignore_missing = true;
772 break; 712 break;
773 case 'A': 713 case 'A':
774 optarg = strdup(".*"); 714 optarg = strdup(".*");
@@ -776,80 +716,96 @@ int process_arguments(int argc, char **argv) {
776 case 'R': 716 case 'R':
777 cflags |= REG_ICASE; 717 cflags |= REG_ICASE;
778 // Intentional fallthrough 718 // Intentional fallthrough
779 case 'r': 719 case 'r': {
780 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent || 720 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
781 warn_usedspace_units || crit_usedspace_units || warn_usedspace_percent || crit_usedspace_percent || 721 crit_freespace_percent || warn_freeinodes_percent || crit_freeinodes_percent)) {
782 warn_usedinodes_percent || crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent)) {
783 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), 722 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
784 _("Must set a threshold value before using -r/-R/-A (--ereg-path/--eregi-path/--all)\n")); 723 _("Must set a threshold value before using -r/-R/-A "
724 "(--ereg-path/--eregi-path/--all)\n"));
785 } 725 }
786 726
787 err = regcomp(&re, optarg, cflags); 727 regex_t regex;
728 int err = regcomp(&regex, optarg, cflags);
788 if (err != 0) { 729 if (err != 0) {
789 regerror(err, &re, errbuf, MAX_INPUT_BUFFER); 730 char errbuf[MAX_INPUT_BUFFER];
790 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf); 731 regerror(err, &regex, errbuf, MAX_INPUT_BUFFER);
732 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"),
733 _("Could not compile regular expression"), errbuf);
791 } 734 }
792 735
793 for (me = mount_list; me; me = me->me_next) { 736 bool found = false;
794 if (np_regex_match_mount_entry(me, &re)) { 737 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
795 fnd = true; 738 if (np_regex_match_mount_entry(me, &regex)) {
796 if (verbose >= 3) 739 found = true;
797 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg); 740 if (verbose >= 3) {
741 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir,
742 optarg);
743 }
798 744
799 /* add parameter if not found. overwrite thresholds if path has already been added */ 745 /* add parameter if not found. overwrite thresholds if path has already been
800 if (!(se = np_find_parameter(path_select_list, me->me_mountdir))) { 746 * added */
801 se = np_add_parameter(&path_select_list, me->me_mountdir); 747 parameter_list_elem *se = NULL;
748 if (!(se = mp_int_fs_list_find(result.config.path_select_list,
749 me->me_mountdir))) {
750 se =
751 mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
802 } 752 }
803 se->group = group; 753 se->group = group;
804 set_all_thresholds(se); 754 set_all_thresholds(se, warn_freespace_units, crit_freespace_units,
755 warn_freespace_percent, crit_freespace_percent,
756 warn_freeinodes_percent, crit_freeinodes_percent);
805 } 757 }
806 } 758 }
807 759
808 if (!fnd && ignore_missing == true) { 760 if (!found) {
809 path_ignored = true; 761 if (result.config.ignore_missing) {
810 path_selected = true; 762 result.config.path_ignored = true;
811 break; 763 path_selected = true;
764 break;
765 }
766
767 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"),
768 _("Regular expression did not match any path or disk"), optarg);
812 } 769 }
813 if (!fnd)
814 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Regular expression did not match any path or disk"), optarg);
815 770
816 fnd = false;
817 path_selected = true; 771 path_selected = true;
818 np_set_best_match(path_select_list, mount_list, exact_match); 772 mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list,
773 result.config.exact_match);
819 cflags = default_cflags; 774 cflags = default_cflags;
820 775
821 break; 776 } break;
822 case 'M': /* display mountpoint */ 777 case 'M': /* display mountpoint */
823 display_mntp = true; 778 result.config.display_mntp = true;
824 break; 779 break;
825 case 'C': 780 case 'C': {
826 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */ 781 /* add all mount entries to path_select list if no partitions have been explicitly
827 if (path_selected == false) { 782 * defined using -p */
828 struct parameter_list *path; 783 if (!path_selected) {
829 for (me = mount_list; me; me = me->me_next) { 784 parameter_list_elem *path;
830 if (!(path = np_find_parameter(path_select_list, me->me_mountdir))) 785 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
831 path = np_add_parameter(&path_select_list, me->me_mountdir); 786 if (!(path = mp_int_fs_list_find(result.config.path_select_list,
787 me->me_mountdir))) {
788 path =
789 mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
790 }
832 path->best_match = me; 791 path->best_match = me;
833 path->group = group; 792 path->group = group;
834 set_all_thresholds(path); 793 set_all_thresholds(path, warn_freespace_units, crit_freespace_units,
794 warn_freespace_percent, crit_freespace_percent,
795 warn_freeinodes_percent, crit_freeinodes_percent);
835 } 796 }
836 } 797 }
798
837 warn_freespace_units = NULL; 799 warn_freespace_units = NULL;
838 crit_freespace_units = NULL; 800 crit_freespace_units = NULL;
839 warn_usedspace_units = NULL;
840 crit_usedspace_units = NULL;
841 warn_freespace_percent = NULL; 801 warn_freespace_percent = NULL;
842 crit_freespace_percent = NULL; 802 crit_freespace_percent = NULL;
843 warn_usedspace_percent = NULL;
844 crit_usedspace_percent = NULL;
845 warn_usedinodes_percent = NULL;
846 crit_usedinodes_percent = NULL;
847 warn_freeinodes_percent = NULL; 803 warn_freeinodes_percent = NULL;
848 crit_freeinodes_percent = NULL; 804 crit_freeinodes_percent = NULL;
849 805
850 path_selected = false; 806 path_selected = false;
851 group = NULL; 807 group = NULL;
852 break; 808 } break;
853 case 'V': /* version */ 809 case 'V': /* version */
854 print_revision(progname, NP_VERSION); 810 print_revision(progname, NP_VERSION);
855 exit(STATE_UNKNOWN); 811 exit(STATE_UNKNOWN);
@@ -858,50 +814,152 @@ int process_arguments(int argc, char **argv) {
858 exit(STATE_UNKNOWN); 814 exit(STATE_UNKNOWN);
859 case '?': /* help */ 815 case '?': /* help */
860 usage(_("Unknown argument")); 816 usage(_("Unknown argument"));
817 case output_format_index: {
818 parsed_output_format parser = mp_parse_output_format(optarg);
819 if (!parser.parsing_success) {
820 // TODO List all available formats here, maybe add anothoer usage function
821 printf("Invalid output format: %s\n", optarg);
822 exit(STATE_UNKNOWN);
823 }
824
825 result.config.output_format_is_set = true;
826 result.config.output_format = parser.output_format;
827 break;
828 }
861 } 829 }
862 } 830 }
863 831
864 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */ 832 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
865 c = optind; 833 int index = optind;
866 if (warn_usedspace_percent == NULL && argc > c && is_intnonneg(argv[c])) 834
867 warn_usedspace_percent = argv[c++]; 835 if (argc > index && is_intnonneg(argv[index])) {
836 if (verbose > 0) {
837 printf("Got an positional warn threshold: %s\n", argv[index]);
838 }
839 char *range = argv[index++];
840 mp_range_parsed tmp = mp_parse_range_string(range);
841 if (tmp.error != MP_PARSING_SUCCES) {
842 die(STATE_UNKNOWN, "failed to parse warning threshold");
843 }
844
845 mp_range tmp_range = tmp.range;
846 // Invert range to use it for free instead of used
847 // tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
868 848
869 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg(argv[c])) 849 warn_freespace_percent = mp_range_to_string(tmp_range);
870 crit_usedspace_percent = argv[c++];
871 850
872 if (argc > c) { 851 if (verbose > 0) {
873 se = np_add_parameter(&path_select_list, strdup(argv[c++])); 852 printf("Positional warning threshold transformed to: %s\n", warn_freespace_percent);
853 }
854 }
855
856 if (argc > index && is_intnonneg(argv[index])) {
857 if (verbose > 0) {
858 printf("Got an positional crit threshold: %s\n", argv[index]);
859 }
860 char *range = argv[index++];
861 mp_range_parsed tmp = mp_parse_range_string(range);
862 if (tmp.error != MP_PARSING_SUCCES) {
863 die(STATE_UNKNOWN, "failed to parse warning threshold");
864 }
865
866 mp_range tmp_range = tmp.range;
867 // Invert range to use it for free instead of used
868 // tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
869
870 crit_freespace_percent = mp_range_to_string(tmp_range);
871
872 if (verbose > 0) {
873 printf("Positional critical threshold transformed to: %s\n", crit_freespace_percent);
874 }
875 }
876
877 if (argc > index) {
878 if (verbose > 0) {
879 printf("Got an positional filesystem: %s\n", argv[index]);
880 }
881 struct parameter_list *se =
882 mp_int_fs_list_append(&result.config.path_select_list, strdup(argv[index++]));
874 path_selected = true; 883 path_selected = true;
875 set_all_thresholds(se); 884 set_all_thresholds(se, warn_freespace_units, crit_freespace_units, warn_freespace_percent,
885 crit_freespace_percent, warn_freeinodes_percent,
886 crit_freeinodes_percent);
876 } 887 }
877 888
878 if (units == NULL) { 889 // If a list of paths has not been explicitly selected, find entire
879 units = strdup("MiB"); 890 // mount list and create list of paths
880 mult = (uintmax_t)1024 * 1024; 891 if (!path_selected && !result.config.path_ignored) {
892 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
893 if (me->me_dummy != 0) {
894 // just do not add dummy filesystems
895 continue;
896 }
897
898 parameter_list_elem *path = NULL;
899 if (!(path = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
900 path = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
901 }
902 path->best_match = me;
903 path->group = group;
904 set_all_thresholds(path, warn_freespace_units, crit_freespace_units,
905 warn_freespace_percent, crit_freespace_percent,
906 warn_freeinodes_percent, crit_freeinodes_percent);
907 }
881 } 908 }
882 909
883 return true; 910 // Set thresholds to the appropriate unit
911 for (parameter_list_elem *tmp = result.config.path_select_list.first; tmp;
912 tmp = mp_int_fs_list_get_next(tmp)) {
913
914 mp_perfdata_value factor = mp_create_pd_value(unit);
915
916 if (tmp->freespace_units.critical_is_set) {
917 tmp->freespace_units.critical =
918 mp_range_multiply(tmp->freespace_units.critical, factor);
919 }
920 if (tmp->freespace_units.warning_is_set) {
921 tmp->freespace_units.warning = mp_range_multiply(tmp->freespace_units.warning, factor);
922 }
923 }
924
925 return result;
884} 926}
885 927
886void set_all_thresholds(struct parameter_list *path) { 928void set_all_thresholds(parameter_list_elem *path, char *warn_freespace_units,
887 if (path->freespace_units != NULL) 929 char *crit_freespace_units, char *warn_freespace_percent,
888 free(path->freespace_units); 930 char *crit_freespace_percent, char *warn_freeinodes_percent,
889 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units); 931 char *crit_freeinodes_percent) {
890 if (path->freespace_percent != NULL) 932 mp_range_parsed tmp;
891 free(path->freespace_percent); 933
892 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent); 934 if (warn_freespace_units) {
893 if (path->usedspace_units != NULL) 935 tmp = mp_parse_range_string(warn_freespace_units);
894 free(path->usedspace_units); 936 path->freespace_units = mp_thresholds_set_warn(path->freespace_units, tmp.range);
895 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units); 937 }
896 if (path->usedspace_percent != NULL) 938
897 free(path->usedspace_percent); 939 if (crit_freespace_units) {
898 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent); 940 tmp = mp_parse_range_string(crit_freespace_units);
899 if (path->usedinodes_percent != NULL) 941 path->freespace_units = mp_thresholds_set_crit(path->freespace_units, tmp.range);
900 free(path->usedinodes_percent); 942 }
901 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent); 943
902 if (path->freeinodes_percent != NULL) 944 if (warn_freespace_percent) {
903 free(path->freeinodes_percent); 945 tmp = mp_parse_range_string(warn_freespace_percent);
904 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent); 946 path->freespace_percent = mp_thresholds_set_warn(path->freespace_percent, tmp.range);
947 }
948
949 if (crit_freespace_percent) {
950 tmp = mp_parse_range_string(crit_freespace_percent);
951 path->freespace_percent = mp_thresholds_set_crit(path->freespace_percent, tmp.range);
952 }
953
954 if (warn_freeinodes_percent) {
955 tmp = mp_parse_range_string(warn_freeinodes_percent);
956 path->freeinodes_percent = mp_thresholds_set_warn(path->freeinodes_percent, tmp.range);
957 }
958
959 if (crit_freeinodes_percent) {
960 tmp = mp_parse_range_string(crit_freeinodes_percent);
961 path->freeinodes_percent = mp_thresholds_set_crit(path->freeinodes_percent, tmp.range);
962 }
905} 963}
906 964
907void print_help(void) { 965void print_help(void) {
@@ -911,7 +969,8 @@ void print_help(void) {
911 printf(COPYRIGHT, copyright, email); 969 printf(COPYRIGHT, copyright, email);
912 970
913 printf("%s\n", _("This plugin checks the amount of used disk space on a mounted file system")); 971 printf("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
914 printf("%s\n", _("and generates an alert if free space is less than one of the threshold values")); 972 printf("%s\n",
973 _("and generates an alert if free space is less than one of the threshold values"));
915 974
916 printf("\n\n"); 975 printf("\n\n");
917 976
@@ -933,7 +992,8 @@ void print_help(void) {
933 printf(" %s\n", "-K, --icritical=PERCENT%"); 992 printf(" %s\n", "-K, --icritical=PERCENT%");
934 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free")); 993 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
935 printf(" %s\n", "-p, --path=PATH, --partition=PARTITION"); 994 printf(" %s\n", "-p, --path=PATH, --partition=PARTITION");
936 printf(" %s\n", _("Mount point or block device as emitted by the mount(8) command (may be repeated)")); 995 printf(" %s\n",
996 _("Mount point or block device as emitted by the mount(8) command (may be repeated)"));
937 printf(" %s\n", "-x, --exclude_device=PATH <STRING>"); 997 printf(" %s\n", "-x, --exclude_device=PATH <STRING>");
938 printf(" %s\n", _("Ignore device (only works if -p unspecified)")); 998 printf(" %s\n", _("Ignore device (only works if -p unspecified)"));
939 printf(" %s\n", "-C, --clear"); 999 printf(" %s\n", "-C, --clear");
@@ -947,167 +1007,298 @@ void print_help(void) {
947 printf(" %s\n", "-P, --iperfdata"); 1007 printf(" %s\n", "-P, --iperfdata");
948 printf(" %s\n", _("Display inode usage in perfdata")); 1008 printf(" %s\n", _("Display inode usage in perfdata"));
949 printf(" %s\n", "-g, --group=NAME"); 1009 printf(" %s\n", "-g, --group=NAME");
950 printf(" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together")); 1010 printf(" %s\n",
951 printf(" %s\n", "-k, --kilobytes"); 1011 _("Group paths. Thresholds apply to (free-)space of all partitions together"));
952 printf(" %s\n", _("Same as '--units kB'"));
953 printf(" %s\n", "-l, --local"); 1012 printf(" %s\n", "-l, --local");
954 printf(" %s\n", _("Only check local filesystems")); 1013 printf(" %s\n", _("Only check local filesystems"));
955 printf(" %s\n", "-L, --stat-remote-fs"); 1014 printf(" %s\n", "-L, --stat-remote-fs");
956 printf(" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems")); 1015 printf(
1016 " %s\n",
1017 _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
957 printf(" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)")); 1018 printf(" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
958 printf(" %s\n", "-M, --mountpoint"); 1019 printf(" %s\n", "-M, --mountpoint");
959 printf(" %s\n", _("Display the (block) device instead of the mount point")); 1020 printf(" %s\n", _("Display the (block) device instead of the mount point"));
960 printf(" %s\n", "-m, --megabytes");
961 printf(" %s\n", _("Same as '--units MB'"));
962 printf(" %s\n", "-A, --all"); 1021 printf(" %s\n", "-A, --all");
963 printf(" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'")); 1022 printf(" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
964 printf(" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION"); 1023 printf(" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
965 printf(" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)")); 1024 printf(" %s\n",
1025 _("Case insensitive regular expression for path/partition (may be repeated)"));
966 printf(" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION"); 1026 printf(" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
967 printf(" %s\n", _("Regular expression for path or partition (may be repeated)")); 1027 printf(" %s\n", _("Regular expression for path or partition (may be repeated)"));
968 printf(" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION"); 1028 printf(" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
969 printf(" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)")); 1029 printf(" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) "
1030 "(may be repeated)"));
970 printf(" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION"); 1031 printf(" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
971 printf(" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)")); 1032 printf(" %s\n",
1033 _("Regular expression to ignore selected path or partition (may be repeated)"));
972 printf(" %s\n", "-n, --ignore-missing"); 1034 printf(" %s\n", "-n, --ignore-missing");
973 printf(" %s\n", _("Return OK if no filesystem matches, filesystem does not exist or is inaccessible.")); 1035 printf(" %s\n",
1036 _("Return OK if no filesystem matches, filesystem does not exist or is inaccessible."));
974 printf(" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)")); 1037 printf(" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)"));
975 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 1038 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
976 printf(" %s\n", "-u, --units=STRING"); 1039 printf(" %s\n", "-u, --units=STRING");
977 printf(" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)")); 1040 printf(" %s\n", _("Select the unit used for the absolute value thresholds"));
1041 printf(" %s\n", _("Choose one of \"bytes\", \"KiB\", \"kB\", \"MiB\", \"MB\", \"GiB\", "
1042 "\"GB\", \"TiB\", \"TB\", \"PiB\", \"PB\" (default: MiB)"));
1043 printf(" %s\n", "-k, --kilobytes");
1044 printf(" %s\n", _("Same as '--units kB'"));
1045 printf(" %s\n", "--display-unit");
1046 printf(" %s\n", _("Select the unit used for in the output"));
1047 printf(" %s\n", _("Choose one of \"bytes\", \"KiB\", \"kB\", \"MiB\", \"MB\", \"GiB\", "
1048 "\"GB\", \"TiB\", \"TB\", \"PiB\", \"PB\" (default: MiB)"));
1049 printf(" %s\n", "-m, --megabytes");
1050 printf(" %s\n", _("Same as '--units MB'"));
978 printf(UT_VERBOSE); 1051 printf(UT_VERBOSE);
979 printf(" %s\n", "-X, --exclude-type=TYPE_REGEX"); 1052 printf(" %s\n", "-X, --exclude-type=TYPE_REGEX");
980 printf(" %s\n", _("Ignore all filesystems of types matching given regex(7) (may be repeated)")); 1053 printf(" %s\n",
1054 _("Ignore all filesystems of types matching given regex(7) (may be repeated)"));
981 printf(" %s\n", "-N, --include-type=TYPE_REGEX"); 1055 printf(" %s\n", "-N, --include-type=TYPE_REGEX");
982 printf(" %s\n", _("Check only filesystems where the type matches this given regex(7) (may be repeated)")); 1056 printf(
1057 " %s\n",
1058 _("Check only filesystems where the type matches this given regex(7) (may be repeated)"));
1059 printf(UT_OUTPUT_FORMAT);
983 1060
984 printf("\n"); 1061 printf("\n");
985 printf("%s\n", _("General usage hints:")); 1062 printf("%s\n", _("General usage hints:"));
986 printf(" %s\n", _("- Arguments are positional! \"-w 5 -c 1 -p /foo -w6 -c2 -p /bar\" is not the same as")); 1063 printf(
1064 " %s\n",
1065 _("- Arguments are positional! \"-w 5 -c 1 -p /foo -w6 -c2 -p /bar\" is not the same as"));
987 printf(" %s\n", _("\"-w 5 -c 1 -p /bar w6 -c2 -p /foo\".")); 1066 printf(" %s\n", _("\"-w 5 -c 1 -p /bar w6 -c2 -p /foo\"."));
988 printf(" %s\n", _("- The syntax is broadly: \"{thresholds a} {paths a} -C {thresholds b} {thresholds b} ...\"")); 1067 printf(" %s\n", _("- The syntax is broadly: \"{thresholds a} {paths a} -C {thresholds b} "
1068 "{thresholds b} ...\""));
989 1069
990 printf("\n"); 1070 printf("\n");
991 printf("%s\n", _("Examples:")); 1071 printf("%s\n", _("Examples:"));
992 printf(" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /"); 1072 printf(" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
993 printf(" %s\n\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB")); 1073 printf(" %s\n\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
994 printf(" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'"); 1074 printf(" %s\n",
995 printf(" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex")); 1075 "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'");
996 printf(" %s\n\n", _("are grouped which means the freespace thresholds are applied to all disks together")); 1076 printf(
1077 " %s\n",
1078 _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
1079 printf(" %s\n\n",
1080 _("are grouped which means the freespace thresholds are applied to all disks together"));
997 printf(" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar"); 1081 printf(" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar");
998 printf(" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M")); 1082 printf(" %s\n",
1083 _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
999 1084
1000 printf(UT_SUPPORT); 1085 printf(UT_SUPPORT);
1001} 1086}
1002 1087
1003void print_usage(void) { 1088void print_usage(void) {
1004 printf("%s\n", _("Usage:")); 1089 printf("%s\n", _("Usage:"));
1005 printf(" %s {-w absolute_limit |-w percentage_limit%% | -W inode_percentage_limit } {-c absolute_limit|-c percentage_limit%% | -K " 1090 printf(" %s {-w absolute_limit |-w percentage_limit%% | -W inode_percentage_limit } {-c "
1091 "absolute_limit|-c percentage_limit%% | -K "
1006 "inode_percentage_limit } {-p path | -x device}\n", 1092 "inode_percentage_limit } {-p path | -x device}\n",
1007 progname); 1093 progname);
1008 printf("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n"); 1094 printf("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
1009 printf("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n"); 1095 printf("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n");
1010} 1096}
1011 1097
1012bool stat_path(struct parameter_list *p) { 1098bool stat_path(parameter_list_elem *parameters, bool ignore_missing) {
1013 /* Stat entry to check that dir exists and is accessible */ 1099 /* Stat entry to check that dir exists and is accessible */
1014 if (verbose >= 3) 1100 if (verbose >= 3) {
1015 printf("calling stat on %s\n", p->name); 1101 printf("calling stat on %s\n", parameters->name);
1016 if (stat(p->name, &stat_buf[0])) { 1102 }
1017 if (verbose >= 3) 1103
1018 printf("stat failed on %s\n", p->name); 1104 struct stat stat_buf = {0};
1019 if (ignore_missing == true) { 1105 if (stat(parameters->name, &stat_buf)) {
1106 if (verbose >= 3) {
1107 printf("stat failed on %s\n", parameters->name);
1108 }
1109 if (ignore_missing) {
1020 return false; 1110 return false;
1021 } 1111 }
1022 printf("DISK %s - ", _("CRITICAL")); 1112 printf("DISK %s - ", _("CRITICAL"));
1023 die(STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno)); 1113 die(STATE_CRITICAL, _("%s %s: %s\n"), parameters->name, _("is not accessible"),
1114 strerror(errno));
1024 } 1115 }
1116
1025 return true; 1117 return true;
1026} 1118}
1027 1119
1028void get_stats(struct parameter_list *p, struct fs_usage *fsp) { 1120static parameter_list_elem get_path_stats(parameter_list_elem parameters, const struct fs_usage fsp,
1029 struct parameter_list *p_list; 1121 bool freespace_ignore_reserved) {
1030 struct fs_usage tmpfsp; 1122 uintmax_t available = fsp.fsu_bavail;
1031 int first = 1; 1123 uintmax_t available_to_root = fsp.fsu_bfree;
1124 uintmax_t used = fsp.fsu_blocks - fsp.fsu_bfree;
1125 uintmax_t total;
1032 1126
1033 if (p->group == NULL) {
1034 get_path_stats(p, fsp);
1035 } else {
1036 /* find all group members */
1037 for (p_list = path_select_list; p_list; p_list = p_list->name_next) {
1038#ifdef __CYGWIN__
1039 if (strncmp(p_list->name, "/cygdrive/", 10) != 0)
1040 continue;
1041#endif
1042 if (p_list->group && !(strcmp(p_list->group, p->group))) {
1043 if (!stat_path(p_list))
1044 continue;
1045 get_fs_usage(p_list->best_match->me_mountdir, p_list->best_match->me_devname, &tmpfsp);
1046 get_path_stats(p_list, &tmpfsp);
1047 if (verbose >= 3)
1048 printf("Group %s: adding %lu blocks sized %lu, (%s) used_units=%lu free_units=%lu total_units=%lu mult=%lu\n",
1049 p_list->group, tmpfsp.fsu_blocks, tmpfsp.fsu_blocksize, p_list->best_match->me_mountdir, p_list->dused_units,
1050 p_list->dfree_units, p_list->dtotal_units, mult);
1051
1052 /* prevent counting the first FS of a group twice since its parameter_list entry
1053 * is used to carry the information of all file systems of the entire group */
1054 if (!first) {
1055 p->total += p_list->total;
1056 p->available += p_list->available;
1057 p->available_to_root += p_list->available_to_root;
1058 p->used += p_list->used;
1059
1060 p->dused_units += p_list->dused_units;
1061 p->dfree_units += p_list->dfree_units;
1062 p->dtotal_units += p_list->dtotal_units;
1063 p->inodes_total += p_list->inodes_total;
1064 p->inodes_free += p_list->inodes_free;
1065 p->inodes_free_to_root += p_list->inodes_free_to_root;
1066 p->inodes_used += p_list->inodes_used;
1067 }
1068 first = 0;
1069 }
1070 if (verbose >= 3)
1071 printf("Group %s now has: used_units=%lu free_units=%lu total_units=%lu fsu_blocksize=%lu mult=%lu\n", p->group,
1072 p->dused_units, p->dfree_units, p->dtotal_units, tmpfsp.fsu_blocksize, mult);
1073 }
1074 /* modify devname and mountdir for output */
1075 p->best_match->me_mountdir = p->best_match->me_devname = p->group;
1076 }
1077 /* finally calculate percentages for either plain FS or summed up group */
1078 p->dused_pct = calculate_percent(p->used, p->used + p->available); /* used + available can never be > uintmax */
1079 p->dfree_pct = 100.0 - p->dused_pct;
1080 p->dused_inodes_percent = calculate_percent(p->inodes_total - p->inodes_free, p->inodes_total);
1081 p->dfree_inodes_percent = 100 - p->dused_inodes_percent;
1082}
1083
1084void get_path_stats(struct parameter_list *p, struct fs_usage *fsp) {
1085 p->available = fsp->fsu_bavail;
1086 p->available_to_root = fsp->fsu_bfree;
1087 p->used = fsp->fsu_blocks - fsp->fsu_bfree;
1088 if (freespace_ignore_reserved) { 1127 if (freespace_ignore_reserved) {
1089 /* option activated : we subtract the root-reserved space from the total */ 1128 /* option activated : we subtract the root-reserved space from the total */
1090 p->total = fsp->fsu_blocks - p->available_to_root + p->available; 1129 total = fsp.fsu_blocks - available_to_root + available;
1091 } else { 1130 } else {
1092 /* default behaviour : take all the blocks into account */ 1131 /* default behaviour : take all the blocks into account */
1093 p->total = fsp->fsu_blocks; 1132 total = fsp.fsu_blocks;
1094 } 1133 }
1095 1134
1096 p->dused_units = p->used * fsp->fsu_blocksize / mult; 1135 parameters.used_bytes = used * fsp.fsu_blocksize;
1097 p->dfree_units = p->available * fsp->fsu_blocksize / mult; 1136 parameters.free_bytes = available * fsp.fsu_blocksize;
1098 p->dtotal_units = p->total * fsp->fsu_blocksize / mult; 1137 parameters.total_bytes = total * fsp.fsu_blocksize;
1138
1099 /* Free file nodes. Not sure the workaround is required, but in case...*/ 1139 /* Free file nodes. Not sure the workaround is required, but in case...*/
1100 p->inodes_free = fsp->fsu_ffree; 1140 parameters.inodes_free = fsp.fsu_ffree;
1101 p->inodes_free_to_root = fsp->fsu_ffree; /* Free file nodes for root. */ 1141 parameters.inodes_free_to_root = fsp.fsu_ffree; /* Free file nodes for root. */
1102 p->inodes_used = fsp->fsu_files - fsp->fsu_ffree; 1142 parameters.inodes_used = fsp.fsu_files - fsp.fsu_ffree;
1143
1103 if (freespace_ignore_reserved) { 1144 if (freespace_ignore_reserved) {
1104 /* option activated : we subtract the root-reserved inodes from the total */ 1145 /* option activated : we subtract the root-reserved inodes from the total */
1105 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */ 1146 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */
1106 /* for others, fsp->fsu_ffree == fsp->fsu_favail */ 1147 /* for others, fsp->fsu_ffree == fsp->fsu_favail */
1107 p->inodes_total = fsp->fsu_files - p->inodes_free_to_root + p->inodes_free; 1148 parameters.inodes_total =
1149 fsp.fsu_files - parameters.inodes_free_to_root + parameters.inodes_free;
1108 } else { 1150 } else {
1109 /* default behaviour : take all the inodes into account */ 1151 /* default behaviour : take all the inodes into account */
1110 p->inodes_total = fsp->fsu_files; 1152 parameters.inodes_total = fsp.fsu_files;
1111 } 1153 }
1112 np_add_name(&seen, p->best_match->me_mountdir); 1154
1155 return parameters;
1156}
1157
1158mp_subcheck evaluate_filesystem(measurement_unit measurement_unit, bool display_inodes_perfdata,
1159 byte_unit unit) {
1160 mp_subcheck result = mp_subcheck_init();
1161 result = mp_set_subcheck_default_state(result, STATE_UNKNOWN);
1162 xasprintf(&result.output, "%s", measurement_unit.name);
1163
1164 if (!measurement_unit.is_group && measurement_unit.filesystem_type) {
1165 xasprintf(&result.output, "%s (%s)", result.output, measurement_unit.filesystem_type);
1166 }
1167
1168 /* Threshold comparisons */
1169
1170 // ===============================
1171 // Free space absolute values test
1172 mp_subcheck freespace_bytes_sc = mp_subcheck_init();
1173 freespace_bytes_sc = mp_set_subcheck_default_state(freespace_bytes_sc, STATE_OK);
1174
1175 if (unit != Humanized) {
1176 xasprintf(&freespace_bytes_sc.output, "Free space absolute: %ju%s (of %ju%s)",
1177 (uintmax_t)(measurement_unit.free_bytes / unit), get_unit_string(unit),
1178 (uintmax_t)(measurement_unit.total_bytes / unit), get_unit_string(unit));
1179 } else {
1180 xasprintf(&freespace_bytes_sc.output, "Free space absolute: %s (of %s)",
1181 humanize_byte_value(measurement_unit.free_bytes, false),
1182 humanize_byte_value((unsigned long long)measurement_unit.total_bytes, false));
1183 }
1184
1185 mp_perfdata used_space = perfdata_init();
1186 used_space.label = measurement_unit.name;
1187 used_space.value = mp_create_pd_value(measurement_unit.free_bytes);
1188 used_space = mp_set_pd_max_value(used_space, mp_create_pd_value(measurement_unit.total_bytes));
1189 used_space = mp_set_pd_min_value(used_space, mp_create_pd_value(0));
1190 used_space.uom = "B";
1191 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1192 freespace_bytes_sc = mp_set_subcheck_state(freespace_bytes_sc, mp_get_pd_status(used_space));
1193
1194 // special case for absolute space thresholds here:
1195 // if absolute values are not set, compute the thresholds from percentage thresholds
1196 mp_thresholds temp_thlds = measurement_unit.freespace_bytes_thresholds;
1197 if (!temp_thlds.critical_is_set &&
1198 measurement_unit.freespace_percent_thresholds.critical_is_set) {
1199 mp_range tmp_range = measurement_unit.freespace_percent_thresholds.critical;
1200
1201 if (!tmp_range.end_infinity) {
1202 tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 *
1203 measurement_unit.total_bytes);
1204 }
1205
1206 if (!tmp_range.start_infinity) {
1207 tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 *
1208 measurement_unit.total_bytes);
1209 }
1210 measurement_unit.freespace_bytes_thresholds =
1211 mp_thresholds_set_crit(measurement_unit.freespace_bytes_thresholds, tmp_range);
1212 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1213 }
1214
1215 if (!temp_thlds.warning_is_set &&
1216 measurement_unit.freespace_percent_thresholds.warning_is_set) {
1217 mp_range tmp_range = measurement_unit.freespace_percent_thresholds.warning;
1218 if (!tmp_range.end_infinity) {
1219 tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 *
1220 measurement_unit.total_bytes);
1221 }
1222 if (!tmp_range.start_infinity) {
1223 tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 *
1224 measurement_unit.total_bytes);
1225 }
1226 measurement_unit.freespace_bytes_thresholds =
1227 mp_thresholds_set_warn(measurement_unit.freespace_bytes_thresholds, tmp_range);
1228 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1229 }
1230
1231 mp_add_perfdata_to_subcheck(&freespace_bytes_sc, used_space);
1232 mp_add_subcheck_to_subcheck(&result, freespace_bytes_sc);
1233
1234 // ==========================
1235 // Free space percentage test
1236 mp_subcheck freespace_percent_sc = mp_subcheck_init();
1237 freespace_percent_sc = mp_set_subcheck_default_state(freespace_percent_sc, STATE_OK);
1238
1239 double free_percentage =
1240 calculate_percent(measurement_unit.free_bytes, measurement_unit.total_bytes);
1241 xasprintf(&freespace_percent_sc.output, "Free space percentage: %g%%", free_percentage);
1242
1243 // Using perfdata here just to get to the test result
1244 mp_perfdata free_space_percent_pd = perfdata_init();
1245 free_space_percent_pd.value = mp_create_pd_value(free_percentage);
1246 free_space_percent_pd =
1247 mp_pd_set_thresholds(free_space_percent_pd, measurement_unit.freespace_percent_thresholds);
1248
1249 freespace_percent_sc =
1250 mp_set_subcheck_state(freespace_percent_sc, mp_get_pd_status(free_space_percent_pd));
1251 mp_add_subcheck_to_subcheck(&result, freespace_percent_sc);
1252
1253 // ================
1254 // Free inodes test
1255 // Only ever useful if the number of inodes is static (e.g. ext4),
1256 // not when it is dynamic (e.g btrfs)
1257 // Assumption: if the total number of inodes == 0, we have such a case and just skip the test
1258 if (measurement_unit.inodes_total > 0) {
1259 mp_subcheck freeindodes_percent_sc = mp_subcheck_init();
1260 freeindodes_percent_sc = mp_set_subcheck_default_state(freeindodes_percent_sc, STATE_OK);
1261
1262 double free_inode_percentage =
1263 calculate_percent(measurement_unit.inodes_free, measurement_unit.inodes_total);
1264
1265 if (verbose > 0) {
1266 printf("free inode percentage computed: %g\n", free_inode_percentage);
1267 }
1268
1269 xasprintf(&freeindodes_percent_sc.output, "Inodes free: %g%% (%ju of %ju)",
1270 free_inode_percentage, measurement_unit.inodes_free,
1271 measurement_unit.inodes_total);
1272
1273 mp_perfdata inodes_pd = perfdata_init();
1274 xasprintf(&inodes_pd.label, "%s (inodes)", measurement_unit.name);
1275 inodes_pd = mp_set_pd_value(inodes_pd, measurement_unit.inodes_used);
1276 inodes_pd =
1277 mp_set_pd_max_value(inodes_pd, mp_create_pd_value(measurement_unit.inodes_total));
1278 inodes_pd = mp_set_pd_min_value(inodes_pd, mp_create_pd_value(0));
1279
1280 mp_thresholds absolut_inode_thresholds = measurement_unit.freeinodes_percent_thresholds;
1281
1282 if (absolut_inode_thresholds.critical_is_set) {
1283 absolut_inode_thresholds.critical =
1284 mp_range_multiply(absolut_inode_thresholds.critical,
1285 mp_create_pd_value(measurement_unit.inodes_total / 100));
1286 }
1287 if (absolut_inode_thresholds.warning_is_set) {
1288 absolut_inode_thresholds.warning =
1289 mp_range_multiply(absolut_inode_thresholds.warning,
1290 mp_create_pd_value(measurement_unit.inodes_total / 100));
1291 }
1292
1293 inodes_pd = mp_pd_set_thresholds(inodes_pd, absolut_inode_thresholds);
1294
1295 freeindodes_percent_sc =
1296 mp_set_subcheck_state(freeindodes_percent_sc, mp_get_pd_status(inodes_pd));
1297 if (display_inodes_perfdata) {
1298 mp_add_perfdata_to_subcheck(&freeindodes_percent_sc, inodes_pd);
1299 }
1300 mp_add_subcheck_to_subcheck(&result, freeindodes_percent_sc);
1301 }
1302
1303 return result;
1113} 1304}
diff --git a/plugins/check_disk.d/utils_disk.c b/plugins/check_disk.d/utils_disk.c
new file mode 100644
index 00000000..0b89018d
--- /dev/null
+++ b/plugins/check_disk.d/utils_disk.c
@@ -0,0 +1,528 @@
1/*****************************************************************************
2 *
3 * Library for check_disk
4 *
5 * License: GPL
6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7 *
8 * Description:
9 *
10 * This file contains utilities for check_disk. These are tested by libtap
11 *
12 *
13 * This program is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 *
26 *
27 *****************************************************************************/
28
29#include "../common.h"
30#include "utils_disk.h"
31#include "../../gl/fsusage.h"
32#include "../../lib/thresholds.h"
33#include "../../lib/states.h"
34#include <stdint.h>
35#include <stdio.h>
36#include <string.h>
37#include <assert.h>
38
39void np_add_name(struct name_list **list, const char *name) {
40 struct name_list *new_entry;
41 new_entry = (struct name_list *)malloc(sizeof *new_entry);
42 new_entry->name = (char *)name;
43 new_entry->next = *list;
44 *list = new_entry;
45}
46
47/* @brief Initialises a new regex at the begin of list via regcomp(3)
48 *
49 * @details if the regex fails to compile the error code of regcomp(3) is returned
50 * and list is not modified, otherwise list is modified to point to the new
51 * element
52 * @param list Pointer to a linked list of regex_list elements
53 * @param regex the string containing the regex which should be inserted into the list
54 * @param clags the cflags parameter for regcomp(3)
55 */
56int np_add_regex(struct regex_list **list, const char *regex, int cflags) {
57 struct regex_list *new_entry = (struct regex_list *)malloc(sizeof *new_entry);
58
59 if (new_entry == NULL) {
60 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
61 }
62
63 int regcomp_result = regcomp(&new_entry->regex, regex, cflags);
64
65 if (!regcomp_result) {
66 // regcomp succeeded
67 new_entry->next = *list;
68 *list = new_entry;
69
70 return 0;
71 }
72 // regcomp failed
73 free(new_entry);
74
75 return regcomp_result;
76}
77
78parameter_list_elem parameter_list_init(const char *name) {
79 parameter_list_elem result = {
80 .name = strdup(name),
81 .best_match = NULL,
82
83 .freespace_units = mp_thresholds_init(),
84 .freespace_percent = mp_thresholds_init(),
85 .freeinodes_percent = mp_thresholds_init(),
86
87 .group = NULL,
88
89 .inodes_total = 0,
90 .inodes_free = 0,
91 .inodes_free_to_root = 0,
92 .inodes_used = 0,
93
94 .used_bytes = 0,
95 .free_bytes = 0,
96 .total_bytes = 0,
97
98 .next = NULL,
99 .prev = NULL,
100 };
101 return result;
102}
103
104/* Returns true if name is in list */
105bool np_find_name(struct name_list *list, const char *name) {
106 if (list == NULL || name == NULL) {
107 return false;
108 }
109 for (struct name_list *iterator = list; iterator; iterator = iterator->next) {
110 if (!strcmp(name, iterator->name)) {
111 return true;
112 }
113 }
114 return false;
115}
116
117/* Returns true if name is in list */
118bool np_find_regmatch(struct regex_list *list, const char *name) {
119 if (name == NULL) {
120 return false;
121 }
122
123 size_t len = strlen(name);
124
125 for (; list; list = list->next) {
126 /* Emulate a full match as if surrounded with ^( )$
127 by checking whether the match spans the whole name */
128 regmatch_t dummy_match;
129 if (!regexec(&list->regex, name, 1, &dummy_match, 0) && dummy_match.rm_so == 0 &&
130 dummy_match.rm_eo == len) {
131 return true;
132 }
133 }
134
135 return false;
136}
137
138bool np_seen_name(struct name_list *list, const char *name) {
139 for (struct name_list *iterator = list; iterator; iterator = iterator->next) {
140 if (!strcmp(iterator->name, name)) {
141 return true;
142 }
143 }
144 return false;
145}
146
147bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re) {
148 return ((regexec(re, me->me_devname, (size_t)0, NULL, 0) == 0) ||
149 (regexec(re, me->me_mountdir, (size_t)0, NULL, 0) == 0));
150}
151
152check_disk_config check_disk_config_init() {
153 check_disk_config tmp = {
154 .erronly = false,
155 .display_mntp = false,
156 .show_local_fs = false,
157 .stat_remote_fs = false,
158 .display_inodes_perfdata = false,
159
160 .exact_match = false,
161 .freespace_ignore_reserved = false,
162
163 .ignore_missing = false,
164 .path_ignored = false,
165
166 // FS Filters
167 .fs_exclude_list = NULL,
168 .fs_include_list = NULL,
169 .device_path_exclude_list = NULL,
170
171 // Actual filesystems paths to investigate
172 .path_select_list = filesystem_list_init(),
173
174 .mount_list = NULL,
175 .seen = NULL,
176
177 .display_unit = Humanized,
178 // .unit = MebiBytes,
179
180 .output_format_is_set = false,
181 };
182 return tmp;
183}
184
185char *get_unit_string(byte_unit_enum unit) {
186 switch (unit) {
187 case Bytes:
188 return "Bytes";
189 case KibiBytes:
190 return "KiB";
191 case MebiBytes:
192 return "MiB";
193 case GibiBytes:
194 return "GiB";
195 case TebiBytes:
196 return "TiB";
197 case PebiBytes:
198 return "PiB";
199 case ExbiBytes:
200 return "EiB";
201 case KiloBytes:
202 return "KB";
203 case MegaBytes:
204 return "MB";
205 case GigaBytes:
206 return "GB";
207 case TeraBytes:
208 return "TB";
209 case PetaBytes:
210 return "PB";
211 case ExaBytes:
212 return "EB";
213 default:
214 assert(false);
215 }
216}
217
218measurement_unit measurement_unit_init() {
219 measurement_unit tmp = {
220 .name = NULL,
221 .filesystem_type = NULL,
222 .is_group = false,
223
224 .freeinodes_percent_thresholds = mp_thresholds_init(),
225 .freespace_percent_thresholds = mp_thresholds_init(),
226 .freespace_bytes_thresholds = mp_thresholds_init(),
227
228 .free_bytes = 0,
229 .used_bytes = 0,
230 .total_bytes = 0,
231
232 .inodes_total = 0,
233 .inodes_free = 0,
234 .inodes_free_to_root = 0,
235 .inodes_used = 0,
236 };
237 return tmp;
238}
239
240// Add a given element to the list, memory for the new element is freshly allocated
241// Returns a pointer to new element
242measurement_unit_list *add_measurement_list(measurement_unit_list *list, measurement_unit elem) {
243 // find last element
244 measurement_unit_list *new = NULL;
245 if (list == NULL) {
246 new = calloc(1, sizeof(measurement_unit_list));
247 if (new == NULL) {
248 die(STATE_UNKNOWN, _("allocation failed"));
249 }
250 } else {
251 measurement_unit_list *list_elem = list;
252 while (list_elem->next != NULL) {
253 list_elem = list_elem->next;
254 }
255
256 new = calloc(1, sizeof(measurement_unit_list));
257 if (new == NULL) {
258 die(STATE_UNKNOWN, _("allocation failed"));
259 }
260
261 list_elem->next = new;
262 }
263
264 new->unit = elem;
265 new->next = NULL;
266 return new;
267}
268
269measurement_unit add_filesystem_to_measurement_unit(measurement_unit unit,
270 parameter_list_elem filesystem) {
271
272 unit.free_bytes += filesystem.free_bytes;
273 unit.used_bytes += filesystem.used_bytes;
274 unit.total_bytes += filesystem.total_bytes;
275
276 unit.inodes_total += filesystem.inodes_total;
277 unit.inodes_free += filesystem.inodes_free;
278 unit.inodes_free_to_root += filesystem.inodes_free_to_root;
279 unit.inodes_used += filesystem.inodes_used;
280 return unit;
281}
282
283measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem filesystem,
284 bool display_mntp) {
285 measurement_unit result = measurement_unit_init();
286 if (!display_mntp) {
287 result.name = strdup(filesystem.best_match->me_mountdir);
288 } else {
289 result.name = strdup(filesystem.best_match->me_devname);
290 }
291
292 if (filesystem.group) {
293 result.is_group = true;
294 } else {
295 result.is_group = false;
296 if (filesystem.best_match) {
297 result.filesystem_type = filesystem.best_match->me_type;
298 }
299 }
300
301 result.freeinodes_percent_thresholds = filesystem.freeinodes_percent;
302 result.freespace_percent_thresholds = filesystem.freespace_percent;
303 result.freespace_bytes_thresholds = filesystem.freespace_units;
304 result.free_bytes = filesystem.free_bytes;
305 result.total_bytes = filesystem.total_bytes;
306 result.used_bytes = filesystem.used_bytes;
307 result.inodes_total = filesystem.inodes_total;
308 result.inodes_used = filesystem.inodes_used;
309 result.inodes_free = filesystem.inodes_free;
310 result.inodes_free_to_root = filesystem.inodes_free_to_root;
311 return result;
312}
313
314#define RANDOM_STRING_LENGTH 64
315
316char *humanize_byte_value(unsigned long long value, bool use_si_units) {
317 // Idea: A reasonable output should have at most 3 orders of magnitude
318 // before the decimal separator
319 // 353GiB is ok, 2444 GiB should be 2.386 TiB
320 char *result = calloc(RANDOM_STRING_LENGTH, sizeof(char));
321 if (result == NULL) {
322 die(STATE_UNKNOWN, _("allocation failed"));
323 }
324 const byte_unit KibiBytes_factor = 1024;
325 const byte_unit MebiBytes_factor = 1048576;
326 const byte_unit GibiBytes_factor = 1073741824;
327 const byte_unit TebiBytes_factor = 1099511627776;
328 const byte_unit PebiBytes_factor = 1125899906842624;
329 const byte_unit ExbiBytes_factor = 1152921504606846976;
330 const byte_unit KiloBytes_factor = 1000;
331 const byte_unit MegaBytes_factor = 1000000;
332 const byte_unit GigaBytes_factor = 1000000000;
333 const byte_unit TeraBytes_factor = 1000000000000;
334 const byte_unit PetaBytes_factor = 1000000000000000;
335 const byte_unit ExaBytes_factor = 1000000000000000000;
336
337 if (use_si_units) {
338 // SI units, powers of 10
339 if (value < KiloBytes_factor) {
340 snprintf(result, RANDOM_STRING_LENGTH, "%llu B", value);
341 } else if (value < MegaBytes_factor) {
342 snprintf(result, RANDOM_STRING_LENGTH, "%llu KB", value / KiloBytes_factor);
343 } else if (value < GigaBytes_factor) {
344 snprintf(result, RANDOM_STRING_LENGTH, "%llu MB", value / MegaBytes_factor);
345 } else if (value < TeraBytes_factor) {
346 snprintf(result, RANDOM_STRING_LENGTH, "%llu GB", value / GigaBytes_factor);
347 } else if (value < PetaBytes_factor) {
348 snprintf(result, RANDOM_STRING_LENGTH, "%llu TB", value / TeraBytes_factor);
349 } else if (value < ExaBytes_factor) {
350 snprintf(result, RANDOM_STRING_LENGTH, "%llu PB", value / PetaBytes_factor);
351 } else {
352 snprintf(result, RANDOM_STRING_LENGTH, "%llu EB", value / ExaBytes_factor);
353 }
354 } else {
355 // IEC units, powers of 2 ^ 10
356 if (value < KibiBytes_factor) {
357 snprintf(result, RANDOM_STRING_LENGTH, "%llu B", value);
358 } else if (value < MebiBytes_factor) {
359 snprintf(result, RANDOM_STRING_LENGTH, "%llu KiB", value / KibiBytes_factor);
360 } else if (value < GibiBytes_factor) {
361 snprintf(result, RANDOM_STRING_LENGTH, "%llu MiB", value / MebiBytes_factor);
362 } else if (value < TebiBytes_factor) {
363 snprintf(result, RANDOM_STRING_LENGTH, "%llu GiB", value / GibiBytes_factor);
364 } else if (value < PebiBytes_factor) {
365 snprintf(result, RANDOM_STRING_LENGTH, "%llu TiB", value / TebiBytes_factor);
366 } else if (value < ExbiBytes_factor) {
367 snprintf(result, RANDOM_STRING_LENGTH, "%llu PiB", value / PebiBytes_factor);
368 } else {
369 snprintf(result, RANDOM_STRING_LENGTH, "%llu EiB", value / ExbiBytes_factor);
370 }
371 }
372
373 return result;
374}
375
376filesystem_list filesystem_list_init() {
377 filesystem_list tmp = {
378 .length = 0,
379 .first = NULL,
380 };
381 return tmp;
382}
383
384parameter_list_elem *mp_int_fs_list_append(filesystem_list *list, const char *name) {
385 parameter_list_elem *current = list->first;
386 parameter_list_elem *new_path = (struct parameter_list *)malloc(sizeof *new_path);
387 *new_path = parameter_list_init(name);
388
389 if (current == NULL) {
390 list->first = new_path;
391 new_path->prev = NULL;
392 list->length = 1;
393 } else {
394 while (current->next) {
395 current = current->next;
396 }
397 current->next = new_path;
398 new_path->prev = current;
399 list->length++;
400 }
401 return new_path;
402}
403
404parameter_list_elem *mp_int_fs_list_find(filesystem_list list, const char *name) {
405 if (list.length == 0) {
406 return NULL;
407 }
408
409 for (parameter_list_elem *temp_list = list.first; temp_list; temp_list = temp_list->next) {
410 if (!strcmp(temp_list->name, name)) {
411 return temp_list;
412 }
413 }
414
415 return NULL;
416}
417
418parameter_list_elem *mp_int_fs_list_del(filesystem_list *list, parameter_list_elem *item) {
419 if (list->length == 0) {
420 return NULL;
421 }
422
423 if (item == NULL) {
424 // Got NULL for item, interpret this as "delete first element"
425 // as a kind of compatibility to the old function
426 item = list->first;
427 }
428
429 if (list->first == item) {
430 list->length--;
431
432 list->first = item->next;
433 if (list->first) {
434 list->first->prev = NULL;
435 }
436 return list->first;
437 }
438
439 // Was not the first element, continue
440 parameter_list_elem *prev = list->first;
441 parameter_list_elem *current = list->first->next;
442
443 while (current != item && current != NULL) {
444 prev = current;
445 current = current->next;
446 }
447
448 if (current == NULL) {
449 // didn't find that element ....
450 return NULL;
451 }
452
453 // remove the element
454 parameter_list_elem *next = current->next;
455 prev->next = next;
456 list->length--;
457 if (next) {
458 next->prev = prev;
459 }
460
461 if (item->name) {
462 free(item->name);
463 }
464 free(item);
465
466 return next;
467}
468
469parameter_list_elem *mp_int_fs_list_get_next(parameter_list_elem *current) {
470 if (!current) {
471 return NULL;
472 }
473 return current->next;
474}
475
476void mp_int_fs_list_set_best_match(filesystem_list list, struct mount_entry *mount_list,
477 bool exact) {
478 for (parameter_list_elem *elem = list.first; elem; elem = mp_int_fs_list_get_next(elem)) {
479 if (!elem->best_match) {
480 size_t name_len = strlen(elem->name);
481 struct mount_entry *best_match = NULL;
482
483 /* set best match if path name exactly matches a mounted device name */
484 for (struct mount_entry *mount_entry = mount_list; mount_entry;
485 mount_entry = mount_entry->me_next) {
486 if (strcmp(mount_entry->me_devname, elem->name) == 0) {
487 struct fs_usage fsp;
488 if (get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp) >=
489 0) {
490 best_match = mount_entry;
491 }
492 }
493 }
494
495 /* set best match by directory name if no match was found by devname */
496 if (!best_match) {
497 size_t best_match_len = 0;
498 for (struct mount_entry *mount_entry = mount_list; mount_entry;
499 mount_entry = mount_entry->me_next) {
500 size_t len = strlen(mount_entry->me_mountdir);
501
502 if ((!exact &&
503 (best_match_len <= len && len <= name_len &&
504 (len == 1 || strncmp(mount_entry->me_mountdir, elem->name, len) == 0))) ||
505 (exact && strcmp(mount_entry->me_mountdir, elem->name) == 0)) {
506 struct fs_usage fsp;
507
508 if (get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp) >=
509 0) {
510 best_match = mount_entry;
511 best_match_len = len;
512 }
513 }
514 }
515 }
516
517 if (best_match) {
518 elem->best_match = best_match;
519 } else {
520 elem->best_match =
521 NULL; /* Not sure why this is needed as it should be null on initialisation */
522 }
523
524 // No filesystem without a mount_entry!
525 // assert(elem->best_match != NULL);
526 }
527 }
528}
diff --git a/plugins/check_disk.d/utils_disk.h b/plugins/check_disk.d/utils_disk.h
new file mode 100644
index 00000000..c96d4296
--- /dev/null
+++ b/plugins/check_disk.d/utils_disk.h
@@ -0,0 +1,160 @@
1#pragma once
2/* Header file for utils_disk */
3
4#include "../../config.h"
5#include "../../gl/mountlist.h"
6#include "../../lib/utils_base.h"
7#include "../../lib/output.h"
8#include "regex.h"
9#include <stdint.h>
10
11typedef unsigned long long byte_unit;
12
13typedef enum {
14 Humanized,
15 Bytes,
16 KibiBytes,
17 MebiBytes,
18 GibiBytes,
19 TebiBytes,
20 PebiBytes,
21 ExbiBytes,
22 KiloBytes,
23 MegaBytes,
24 GigaBytes,
25 TeraBytes,
26 PetaBytes,
27 ExaBytes,
28} byte_unit_enum;
29
30typedef struct name_list string_list;
31struct name_list {
32 char *name;
33 string_list *next;
34};
35
36struct regex_list {
37 regex_t regex;
38 struct regex_list *next;
39};
40
41typedef struct parameter_list parameter_list_elem;
42struct parameter_list {
43 char *name;
44 char *group;
45
46 mp_thresholds freespace_units;
47 mp_thresholds freespace_percent;
48 mp_thresholds freeinodes_percent;
49
50 struct mount_entry *best_match;
51
52 uintmax_t inodes_free_to_root;
53 uintmax_t inodes_free;
54 uintmax_t inodes_used;
55 uintmax_t inodes_total;
56
57 uint64_t used_bytes;
58 uint64_t free_bytes;
59 uint64_t total_bytes;
60
61 parameter_list_elem *next;
62 parameter_list_elem *prev;
63};
64
65typedef struct {
66 size_t length;
67 parameter_list_elem *first;
68} filesystem_list;
69
70filesystem_list filesystem_list_init();
71
72typedef struct {
73 char *name;
74 char *filesystem_type;
75 bool is_group;
76
77 mp_thresholds freespace_bytes_thresholds;
78 mp_thresholds freespace_percent_thresholds;
79 mp_thresholds freeinodes_percent_thresholds;
80
81 uintmax_t inodes_free_to_root;
82 uintmax_t inodes_free;
83 uintmax_t inodes_used;
84 uintmax_t inodes_total;
85
86 uintmax_t used_bytes;
87 uintmax_t free_bytes;
88 uintmax_t total_bytes;
89} measurement_unit;
90
91typedef struct measurement_unit_list measurement_unit_list;
92struct measurement_unit_list {
93 measurement_unit unit;
94 measurement_unit_list *next;
95};
96
97typedef struct {
98 // Output options
99 bool erronly;
100 bool display_mntp;
101 /* show only local filesystems. */
102 bool show_local_fs;
103 /* show only local filesystems but call stat() on remote ones. */
104 bool stat_remote_fs;
105 bool display_inodes_perfdata;
106
107 bool exact_match;
108 bool freespace_ignore_reserved;
109
110 bool ignore_missing;
111 bool path_ignored;
112
113 /* Linked list of filesystem types to omit.
114 If the list is empty, don't exclude any types. */
115 struct regex_list *fs_exclude_list;
116 /* Linked list of filesystem types to check.
117 If the list is empty, include all types. */
118 struct regex_list *fs_include_list;
119 struct name_list *device_path_exclude_list;
120 filesystem_list path_select_list;
121 /* Linked list of mounted filesystems. */
122 struct mount_entry *mount_list;
123 struct name_list *seen;
124
125 byte_unit_enum display_unit;
126 // byte_unit unit;
127
128 bool output_format_is_set;
129 mp_output_format output_format;
130} check_disk_config;
131
132void np_add_name(struct name_list **list, const char *name);
133bool np_find_name(struct name_list *list, const char *name);
134bool np_seen_name(struct name_list *list, const char *name);
135int np_add_regex(struct regex_list **list, const char *regex, int cflags);
136bool np_find_regmatch(struct regex_list *list, const char *name);
137
138parameter_list_elem parameter_list_init(const char *);
139
140parameter_list_elem *mp_int_fs_list_append(filesystem_list *list, const char *name);
141parameter_list_elem *mp_int_fs_list_find(filesystem_list list, const char *name);
142parameter_list_elem *mp_int_fs_list_del(filesystem_list *list, parameter_list_elem *item);
143parameter_list_elem *mp_int_fs_list_get_next(parameter_list_elem *current);
144void mp_int_fs_list_set_best_match(filesystem_list list, struct mount_entry *mount_list,
145 bool exact);
146
147measurement_unit measurement_unit_init();
148measurement_unit_list *add_measurement_list(measurement_unit_list *list, measurement_unit elem);
149measurement_unit add_filesystem_to_measurement_unit(measurement_unit unit,
150 parameter_list_elem filesystem);
151measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem filesystem,
152 bool display_mntp);
153
154int search_parameter_list(parameter_list_elem *list, const char *name);
155bool np_regex_match_mount_entry(struct mount_entry *, regex_t *);
156
157char *get_unit_string(byte_unit_enum);
158check_disk_config check_disk_config_init();
159
160char *humanize_byte_value(unsigned long long value, bool use_si_units);
diff --git a/plugins/check_dns.c b/plugins/check_dns.c
index 95f33083..56f91dae 100644
--- a/plugins/check_dns.c
+++ b/plugins/check_dns.c
@@ -48,7 +48,8 @@ typedef struct {
48} check_dns_config_wrapper; 48} check_dns_config_wrapper;
49static check_dns_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); 49static check_dns_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50static check_dns_config_wrapper validate_arguments(check_dns_config_wrapper /*config_wrapper*/); 50static check_dns_config_wrapper validate_arguments(check_dns_config_wrapper /*config_wrapper*/);
51static mp_state_enum error_scan(char * /*input_buffer*/, bool * /*is_nxdomain*/, const char /*dns_server*/[ADDRESS_LENGTH]); 51static mp_state_enum error_scan(char * /*input_buffer*/, bool * /*is_nxdomain*/,
52 const char /*dns_server*/[ADDRESS_LENGTH]);
52static bool ip_match_cidr(const char * /*addr*/, const char * /*cidr_ro*/); 53static bool ip_match_cidr(const char * /*addr*/, const char * /*cidr_ro*/);
53static unsigned long ip2long(const char * /*src*/); 54static unsigned long ip2long(const char * /*src*/);
54static void print_help(void); 55static void print_help(void);
@@ -127,7 +128,8 @@ int main(int argc, char **argv) {
127 puts(chld_out.line[i]); 128 puts(chld_out.line[i]);
128 } 129 }
129 130
130 if (strcasestr(chld_out.line[i], ".in-addr.arpa") || strcasestr(chld_out.line[i], ".ip6.arpa")) { 131 if (strcasestr(chld_out.line[i], ".in-addr.arpa") ||
132 strcasestr(chld_out.line[i], ".ip6.arpa")) {
131 if ((strstr(chld_out.line[i], "canonical name = ") != NULL)) { 133 if ((strstr(chld_out.line[i], "canonical name = ") != NULL)) {
132 continue; 134 continue;
133 } 135 }
@@ -145,7 +147,8 @@ int main(int argc, char **argv) {
145 if (strstr(chld_out.line[i], "Server:") && strlen(config.dns_server) > 0) { 147 if (strstr(chld_out.line[i], "Server:") && strlen(config.dns_server) > 0) {
146 char *temp_buffer = strchr(chld_out.line[i], ':'); 148 char *temp_buffer = strchr(chld_out.line[i], ':');
147 if (temp_buffer == NULL) { 149 if (temp_buffer == NULL) {
148 die(STATE_UNKNOWN, _("'%s' returned a weirdly formatted Server line\n"), NSLOOKUP_COMMAND); 150 die(STATE_UNKNOWN, _("'%s' returned a weirdly formatted Server line\n"),
151 NSLOOKUP_COMMAND);
149 } 152 }
150 153
151 temp_buffer++; 154 temp_buffer++;
@@ -157,21 +160,25 @@ int main(int argc, char **argv) {
157 160
158 strip(temp_buffer); 161 strip(temp_buffer);
159 if (strlen(temp_buffer) == 0) { 162 if (strlen(temp_buffer) == 0) {
160 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty server string\n"), NSLOOKUP_COMMAND); 163 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty server string\n"),
164 NSLOOKUP_COMMAND);
161 } 165 }
162 166
163 if (strcmp(temp_buffer, config.dns_server) != 0) { 167 if (strcmp(temp_buffer, config.dns_server) != 0) {
164 die(STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"), config.dns_server); 168 die(STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"),
169 config.dns_server);
165 } 170 }
166 } 171 }
167 172
168 /* the server is responding, we just got the host name... */ 173 /* the server is responding, we just got the host name... */
169 if (strstr(chld_out.line[i], "Name:")) { 174 if (strstr(chld_out.line[i], "Name:")) {
170 parse_address = true; 175 parse_address = true;
171 } else if (parse_address && (strstr(chld_out.line[i], "Address:") || strstr(chld_out.line[i], "Addresses:"))) { 176 } else if (parse_address && (strstr(chld_out.line[i], "Address:") ||
177 strstr(chld_out.line[i], "Addresses:"))) {
172 char *temp_buffer = strchr(chld_out.line[i], ':'); 178 char *temp_buffer = strchr(chld_out.line[i], ':');
173 if (temp_buffer == NULL) { 179 if (temp_buffer == NULL) {
174 die(STATE_UNKNOWN, _("'%s' returned a weirdly formatted Address line\n"), NSLOOKUP_COMMAND); 180 die(STATE_UNKNOWN, _("'%s' returned a weirdly formatted Address line\n"),
181 NSLOOKUP_COMMAND);
175 } 182 }
176 183
177 temp_buffer++; 184 temp_buffer++;
@@ -183,7 +190,8 @@ int main(int argc, char **argv) {
183 190
184 strip(temp_buffer); 191 strip(temp_buffer);
185 if (strlen(temp_buffer) == 0) { 192 if (strlen(temp_buffer) == 0) {
186 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty host name string\n"), NSLOOKUP_COMMAND); 193 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty host name string\n"),
194 NSLOOKUP_COMMAND);
187 } 195 }
188 196
189 addresses[n_addresses++] = strdup(temp_buffer); 197 addresses[n_addresses++] = strdup(temp_buffer);
@@ -209,7 +217,8 @@ int main(int argc, char **argv) {
209 } 217 }
210 218
211 if (error_scan(chld_err.line[i], &is_nxdomain, config.dns_server) != STATE_OK) { 219 if (error_scan(chld_err.line[i], &is_nxdomain, config.dns_server) != STATE_OK) {
212 result = max_state(result, error_scan(chld_err.line[i], &is_nxdomain, config.dns_server)); 220 result =
221 max_state(result, error_scan(chld_err.line[i], &is_nxdomain, config.dns_server));
213 msg = strchr(input_buffer, ':'); 222 msg = strchr(input_buffer, ':');
214 if (msg) { 223 if (msg) {
215 msg++; 224 msg++;
@@ -242,7 +251,8 @@ int main(int argc, char **argv) {
242 } 251 }
243 *adrp = 0; 252 *adrp = 0;
244 } else { 253 } else {
245 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' msg parsing exited with no address\n"), NSLOOKUP_COMMAND); 254 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' msg parsing exited with no address\n"),
255 NSLOOKUP_COMMAND);
246 } 256 }
247 257
248 /* compare to expected address */ 258 /* compare to expected address */
@@ -255,7 +265,8 @@ int main(int argc, char **argv) {
255 for (size_t i = 0; i < config.expected_address_cnt; i++) { 265 for (size_t i = 0; i < config.expected_address_cnt; i++) {
256 /* check if we get a match on 'raw' ip or cidr */ 266 /* check if we get a match on 'raw' ip or cidr */
257 for (size_t j = 0; j < n_addresses; j++) { 267 for (size_t j = 0; j < n_addresses; j++) {
258 if (strcmp(addresses[j], config.expected_address[i]) == 0 || ip_match_cidr(addresses[j], config.expected_address[i])) { 268 if (strcmp(addresses[j], config.expected_address[i]) == 0 ||
269 ip_match_cidr(addresses[j], config.expected_address[i])) {
259 result = STATE_OK; 270 result = STATE_OK;
260 addr_match &= ~(1 << j); 271 addr_match &= ~(1 << j);
261 expect_match &= ~(1 << i); 272 expect_match &= ~(1 << i);
@@ -279,7 +290,8 @@ int main(int argc, char **argv) {
279 if (config.expect_nxdomain) { 290 if (config.expect_nxdomain) {
280 if (!is_nxdomain) { 291 if (!is_nxdomain) {
281 result = STATE_CRITICAL; 292 result = STATE_CRITICAL;
282 xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), config.query_address, address); 293 xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), config.query_address,
294 address);
283 } else { 295 } else {
284 if (address != NULL) { 296 if (address != NULL) {
285 free(address); 297 free(address);
@@ -291,7 +303,8 @@ int main(int argc, char **argv) {
291 /* check if authoritative */ 303 /* check if authoritative */
292 if (result == STATE_OK && config.expect_authority && non_authoritative) { 304 if (result == STATE_OK && config.expect_authority && non_authoritative) {
293 result = STATE_CRITICAL; 305 result = STATE_CRITICAL;
294 xasprintf(&msg, _("server %s is not authoritative for %s"), config.dns_server, config.query_address); 306 xasprintf(&msg, _("server %s is not authoritative for %s"), config.dns_server,
307 config.query_address);
295 } 308 }
296 309
297 long microsec = deltime(tv); 310 long microsec = deltime(tv);
@@ -306,24 +319,36 @@ int main(int argc, char **argv) {
306 } else if (result == STATE_CRITICAL) { 319 } else if (result == STATE_CRITICAL) {
307 printf("DNS %s: ", _("CRITICAL")); 320 printf("DNS %s: ", _("CRITICAL"));
308 } 321 }
309 printf(ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time), elapsed_time); 322 printf(ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time),
323 elapsed_time);
310 printf(_(". %s returns %s"), config.query_address, address); 324 printf(_(". %s returns %s"), config.query_address, address);
311 if ((config.time_thresholds->warning != NULL) && (config.time_thresholds->critical != NULL)) { 325 if ((config.time_thresholds->warning != NULL) &&
312 printf("|%s\n", fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end, true, 326 (config.time_thresholds->critical != NULL)) {
327 printf("|%s\n",
328 fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end,
329 true, config.time_thresholds->critical->end, true, 0, false, 0));
330 } else if ((config.time_thresholds->warning == NULL) &&
331 (config.time_thresholds->critical != NULL)) {
332 printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, true,
313 config.time_thresholds->critical->end, true, 0, false, 0)); 333 config.time_thresholds->critical->end, true, 0, false, 0));
314 } else if ((config.time_thresholds->warning == NULL) && (config.time_thresholds->critical != NULL)) { 334 } else if ((config.time_thresholds->warning != NULL) &&
315 printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, true, config.time_thresholds->critical->end, true, 0, false, 0)); 335 (config.time_thresholds->critical == NULL)) {
316 } else if ((config.time_thresholds->warning != NULL) && (config.time_thresholds->critical == NULL)) { 336 printf("|%s\n",
317 printf("|%s\n", fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end, false, 0, true, 0, false, 0)); 337 fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end,
338 false, 0, true, 0, false, 0));
318 } else { 339 } else {
319 printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, false, 0)); 340 printf("|%s\n",
341 fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, false, 0));
320 } 342 }
321 } else if (result == STATE_WARNING) { 343 } else if (result == STATE_WARNING) {
322 printf(_("DNS WARNING - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg); 344 printf(_("DNS WARNING - %s\n"),
345 !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
323 } else if (result == STATE_CRITICAL) { 346 } else if (result == STATE_CRITICAL) {
324 printf(_("DNS CRITICAL - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg); 347 printf(_("DNS CRITICAL - %s\n"),
348 !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
325 } else { 349 } else {
326 printf(_("DNS UNKNOWN - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg); 350 printf(_("DNS UNKNOWN - %s\n"),
351 !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
327 } 352 }
328 353
329 exit(result); 354 exit(result);
@@ -342,29 +367,34 @@ bool ip_match_cidr(const char *addr, const char *cidr_ro) {
342 mask = atoi(mask_c); 367 mask = atoi(mask_c);
343 368
344 /* https://www.cryptobells.com/verifying-ips-in-a-subnet-in-php/ */ 369 /* https://www.cryptobells.com/verifying-ips-in-a-subnet-in-php/ */
345 return (ip2long(addr) & ~((1 << (32 - mask)) - 1)) == (ip2long(subnet) >> (32 - mask)) << (32 - mask); 370 return (ip2long(addr) & ~((1 << (32 - mask)) - 1)) == (ip2long(subnet) >> (32 - mask))
371 << (32 - mask);
346} 372}
347 373
348unsigned long ip2long(const char *src) { 374unsigned long ip2long(const char *src) {
349 unsigned long ip[4]; 375 unsigned long ip[4];
350 /* http://computer-programming-forum.com/47-c-language/1376ffb92a12c471.htm */ 376 /* http://computer-programming-forum.com/47-c-language/1376ffb92a12c471.htm */
351 return (sscanf(src, "%3lu.%3lu.%3lu.%3lu", &ip[0], &ip[1], &ip[2], &ip[3]) == 4 && ip[0] < 256 && ip[1] < 256 && ip[2] < 256 && 377 return (sscanf(src, "%3lu.%3lu.%3lu.%3lu", &ip[0], &ip[1], &ip[2], &ip[3]) == 4 &&
352 ip[3] < 256) 378 ip[0] < 256 && ip[1] < 256 && ip[2] < 256 && ip[3] < 256)
353 ? ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3] 379 ? ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3]
354 : 0; 380 : 0;
355} 381}
356 382
357mp_state_enum error_scan(char *input_buffer, bool *is_nxdomain, const char dns_server[ADDRESS_LENGTH]) { 383mp_state_enum error_scan(char *input_buffer, bool *is_nxdomain,
384 const char dns_server[ADDRESS_LENGTH]) {
358 385
359 const int nxdomain = strstr(input_buffer, "Non-existent") || strstr(input_buffer, "** server can't find") || 386 const int nxdomain = strstr(input_buffer, "Non-existent") ||
387 strstr(input_buffer, "** server can't find") ||
360 strstr(input_buffer, "** Can't find") || strstr(input_buffer, "NXDOMAIN"); 388 strstr(input_buffer, "** Can't find") || strstr(input_buffer, "NXDOMAIN");
361 if (nxdomain) { 389 if (nxdomain) {
362 *is_nxdomain = true; 390 *is_nxdomain = true;
363 } 391 }
364 392
365 /* the DNS lookup timed out */ 393 /* the DNS lookup timed out */
366 if (strstr(input_buffer, _("Note: nslookup is deprecated and may be removed from future releases.")) || 394 if (strstr(input_buffer,
367 strstr(input_buffer, _("Consider using the `dig' or `host' programs instead. Run nslookup with")) || 395 _("Note: nslookup is deprecated and may be removed from future releases.")) ||
396 strstr(input_buffer,
397 _("Consider using the `dig' or `host' programs instead. Run nslookup with")) ||
368 strstr(input_buffer, _("the `-sil[ent]' option to prevent this message from appearing."))) { 398 strstr(input_buffer, _("the `-sil[ent]' option to prevent this message from appearing."))) {
369 return STATE_OK; 399 return STATE_OK;
370 } 400 }
@@ -382,8 +412,9 @@ mp_state_enum error_scan(char *input_buffer, bool *is_nxdomain, const char dns_s
382 } 412 }
383 413
384 /* Connection was refused */ 414 /* Connection was refused */
385 else if (strstr(input_buffer, "Connection refused") || strstr(input_buffer, "Couldn't find server") || 415 else if (strstr(input_buffer, "Connection refused") ||
386 strstr(input_buffer, "Refused") || (strstr(input_buffer, "** server can't find") && strstr(input_buffer, ": REFUSED"))) { 416 strstr(input_buffer, "Couldn't find server") || strstr(input_buffer, "Refused") ||
417 (strstr(input_buffer, "** server can't find") && strstr(input_buffer, ": REFUSED"))) {
387 die(STATE_CRITICAL, _("Connection to DNS %s was refused\n"), dns_server); 418 die(STATE_CRITICAL, _("Connection to DNS %s was refused\n"), dns_server);
388 } 419 }
389 420
@@ -504,20 +535,24 @@ check_dns_config_wrapper process_arguments(int argc, char **argv) {
504 if (strchr(optarg, ',') != NULL) { 535 if (strchr(optarg, ',') != NULL) {
505 char *comma = strchr(optarg, ','); 536 char *comma = strchr(optarg, ',');
506 while (comma != NULL) { 537 while (comma != NULL) {
507 result.config.expected_address = 538 result.config.expected_address = (char **)realloc(
508 (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **)); 539 result.config.expected_address,
509 result.config.expected_address[result.config.expected_address_cnt] = strndup(optarg, comma - optarg); 540 (result.config.expected_address_cnt + 1) * sizeof(char **));
541 result.config.expected_address[result.config.expected_address_cnt] =
542 strndup(optarg, comma - optarg);
510 result.config.expected_address_cnt++; 543 result.config.expected_address_cnt++;
511 optarg = comma + 1; 544 optarg = comma + 1;
512 comma = strchr(optarg, ','); 545 comma = strchr(optarg, ',');
513 } 546 }
514 result.config.expected_address = 547 result.config.expected_address =
515 (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **)); 548 (char **)realloc(result.config.expected_address,
549 (result.config.expected_address_cnt + 1) * sizeof(char **));
516 result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg); 550 result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg);
517 result.config.expected_address_cnt++; 551 result.config.expected_address_cnt++;
518 } else { 552 } else {
519 result.config.expected_address = 553 result.config.expected_address =
520 (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **)); 554 (char **)realloc(result.config.expected_address,
555 (result.config.expected_address_cnt + 1) * sizeof(char **));
521 result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg); 556 result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg);
522 result.config.expected_address_cnt++; 557 result.config.expected_address_cnt++;
523 } 558 }
@@ -586,9 +621,11 @@ void print_help(void) {
586 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 621 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
587 printf(COPYRIGHT, copyright, email); 622 printf(COPYRIGHT, copyright, email);
588 623
589 printf("%s\n", _("This plugin uses the nslookup program to obtain the IP address for the given host/domain query.")); 624 printf("%s\n", _("This plugin uses the nslookup program to obtain the IP address for the given "
625 "host/domain query."));
590 printf("%s\n", _("An optional DNS server to use may be specified.")); 626 printf("%s\n", _("An optional DNS server to use may be specified."));
591 printf("%s\n", _("If no DNS server is specified, the default server(s) specified in /etc/resolv.conf will be used.")); 627 printf("%s\n", _("If no DNS server is specified, the default server(s) specified in "
628 "/etc/resolv.conf will be used."));
592 629
593 printf("\n\n"); 630 printf("\n\n");
594 631
@@ -602,11 +639,14 @@ void print_help(void) {
602 printf(" -s, --server=HOST\n"); 639 printf(" -s, --server=HOST\n");
603 printf(" %s\n", _("Optional DNS server you want to use for the lookup")); 640 printf(" %s\n", _("Optional DNS server you want to use for the lookup"));
604 printf(" -a, --expected-address=IP-ADDRESS|CIDR|HOST\n"); 641 printf(" -a, --expected-address=IP-ADDRESS|CIDR|HOST\n");
605 printf(" %s\n", _("Optional IP-ADDRESS/CIDR you expect the DNS server to return. HOST must end")); 642 printf(" %s\n",
606 printf(" %s\n", _("with a dot (.). This option can be repeated multiple times (Returns OK if any")); 643 _("Optional IP-ADDRESS/CIDR you expect the DNS server to return. HOST must end"));
644 printf(" %s\n",
645 _("with a dot (.). This option can be repeated multiple times (Returns OK if any"));
607 printf(" %s\n", _("value matches).")); 646 printf(" %s\n", _("value matches)."));
608 printf(" -n, --expect-nxdomain\n"); 647 printf(" -n, --expect-nxdomain\n");
609 printf(" %s\n", _("Expect the DNS server to return NXDOMAIN (i.e. the domain was not found)")); 648 printf(" %s\n",
649 _("Expect the DNS server to return NXDOMAIN (i.e. the domain was not found)"));
610 printf(" %s\n", _("Cannot be used together with -a")); 650 printf(" %s\n", _("Cannot be used together with -a"));
611 printf(" -A, --expect-authority\n"); 651 printf(" -A, --expect-authority\n");
612 printf(" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup")); 652 printf(" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup"));
@@ -615,7 +655,8 @@ void print_help(void) {
615 printf(" -c, --critical=seconds\n"); 655 printf(" -c, --critical=seconds\n");
616 printf(" %s\n", _("Return critical if elapsed time exceeds value. Default off")); 656 printf(" %s\n", _("Return critical if elapsed time exceeds value. Default off"));
617 printf(" -L, --all\n"); 657 printf(" -L, --all\n");
618 printf(" %s\n", _("Return critical if the list of expected addresses does not match all addresses")); 658 printf(" %s\n",
659 _("Return critical if the list of expected addresses does not match all addresses"));
619 printf(" %s\n", _("returned. Default off")); 660 printf(" %s\n", _("returned. Default off"));
620 661
621 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 662 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
@@ -625,5 +666,7 @@ void print_help(void) {
625 666
626void print_usage(void) { 667void print_usage(void) {
627 printf("%s\n", _("Usage:")); 668 printf("%s\n", _("Usage:"));
628 printf("%s -H host [-s server] [-a expected-address] [-n] [-A] [-t timeout] [-w warn] [-c crit] [-L]\n", progname); 669 printf("%s -H host [-s server] [-a expected-address] [-n] [-A] [-t timeout] [-w warn] [-c "
670 "crit] [-L]\n",
671 progname);
629} 672}
diff --git a/plugins/check_dummy.c b/plugins/check_dummy.c
index 19f6c046..602d5868 100644
--- a/plugins/check_dummy.c
+++ b/plugins/check_dummy.c
@@ -45,18 +45,19 @@ int main(int argc, char **argv) {
45 bindtextdomain(PACKAGE, LOCALEDIR); 45 bindtextdomain(PACKAGE, LOCALEDIR);
46 textdomain(PACKAGE); 46 textdomain(PACKAGE);
47 47
48 if (argc < 2) 48 if (argc < 2) {
49 usage4(_("Could not parse arguments")); 49 usage4(_("Could not parse arguments"));
50 else if (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "--version") == 0) { 50 } else if (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "--version") == 0) {
51 print_revision(progname, NP_VERSION); 51 print_revision(progname, NP_VERSION);
52 exit(STATE_UNKNOWN); 52 exit(STATE_UNKNOWN);
53 } else if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { 53 } else if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
54 print_help(); 54 print_help();
55 exit(STATE_UNKNOWN); 55 exit(STATE_UNKNOWN);
56 } else if (!is_integer(argv[1])) 56 } else if (!is_integer(argv[1])) {
57 usage4(_("Arguments to check_dummy must be an integer")); 57 usage4(_("Arguments to check_dummy must be an integer"));
58 else 58 } else {
59 result = atoi(argv[1]); 59 result = atoi(argv[1]);
60 }
60 61
61 switch (result) { 62 switch (result) {
62 case STATE_OK: 63 case STATE_OK:
@@ -78,8 +79,9 @@ int main(int argc, char **argv) {
78 return STATE_UNKNOWN; 79 return STATE_UNKNOWN;
79 } 80 }
80 81
81 if (argc >= 3) 82 if (argc >= 3) {
82 printf(": %s", argv[2]); 83 printf(": %s", argv[2]);
84 }
83 85
84 printf("\n"); 86 printf("\n");
85 87
@@ -92,7 +94,8 @@ void print_help(void) {
92 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 94 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
93 printf(COPYRIGHT, copyright, email); 95 printf(COPYRIGHT, copyright, email);
94 96
95 printf("%s\n", _("This plugin will simply return the state corresponding to the numeric value")); 97 printf("%s\n",
98 _("This plugin will simply return the state corresponding to the numeric value"));
96 99
97 printf("%s\n", _("of the <state> argument with optional text")); 100 printf("%s\n", _("of the <state> argument with optional text"));
98 101
diff --git a/plugins/check_fping.c b/plugins/check_fping.c
index ec7abb67..6160c2cb 100644
--- a/plugins/check_fping.c
+++ b/plugins/check_fping.c
@@ -46,8 +46,9 @@ enum {
46 RTA = 1 46 RTA = 1
47}; 47};
48 48
49static mp_state_enum textscan(char *buf, const char * /*server_name*/, bool /*crta_p*/, double /*crta*/, bool /*wrta_p*/, double /*wrta*/, 49static mp_state_enum textscan(char *buf, const char * /*server_name*/, bool /*crta_p*/,
50 bool /*cpl_p*/, int /*cpl*/, bool /*wpl_p*/, int /*wpl*/, bool /*alive_p*/); 50 double /*crta*/, bool /*wrta_p*/, double /*wrta*/, bool /*cpl_p*/,
51 int /*cpl*/, bool /*wpl_p*/, int /*wpl*/, bool /*alive_p*/);
51 52
52typedef struct { 53typedef struct {
53 int errorcode; 54 int errorcode;
@@ -79,6 +80,24 @@ int main(int argc, char **argv) {
79 server = strscpy(server, config.server_name); 80 server = strscpy(server, config.server_name);
80 81
81 char *option_string = ""; 82 char *option_string = "";
83 char *fping_prog = NULL;
84
85 /* First determine if the target is dualstack or ipv6 only. */
86 bool server_is_inet6_addr = is_inet6_addr(server);
87
88 /*
89 * If the user requested -6 OR the user made no assertion and the address is v6 or dualstack
90 * -> we use ipv6
91 * If the user requested -4 OR the user made no assertion and the address is v4 ONLY
92 * -> we use ipv4
93 */
94 if (address_family == AF_INET6 || (address_family == AF_UNSPEC && server_is_inet6_addr)) {
95 xasprintf(&option_string, "%s-6 ", option_string);
96 } else {
97 xasprintf(&option_string, "%s-4 ", option_string);
98 }
99 fping_prog = strdup(PATH_TO_FPING);
100
82 /* compose the command */ 101 /* compose the command */
83 if (config.target_timeout) { 102 if (config.target_timeout) {
84 xasprintf(&option_string, "%s-t %d ", option_string, config.target_timeout); 103 xasprintf(&option_string, "%s-t %d ", option_string, config.target_timeout);
@@ -99,19 +118,28 @@ int main(int argc, char **argv) {
99 xasprintf(&option_string, "%s-R ", option_string); 118 xasprintf(&option_string, "%s-R ", option_string);
100 } 119 }
101 120
102 char *fping_prog = NULL; 121 if (config.fwmark_set) {
103#ifdef PATH_TO_FPING6 122 xasprintf(&option_string, "%s--fwmark %u ", option_string, config.fwmark);
104 if (address_family != AF_INET && is_inet6_addr(server)) { 123 }
105 fping_prog = strdup(PATH_TO_FPING6); 124
106 } else { 125 if (config.icmp_timestamp) {
107 fping_prog = strdup(PATH_TO_FPING); 126 xasprintf(&option_string, "%s--icmp-timestamp ", option_string);
127 }
128
129 if (config.check_source) {
130 xasprintf(&option_string, "%s--check-source ", option_string);
108 } 131 }
109#else
110 fping_prog = strdup(PATH_TO_FPING);
111#endif
112 132
113 char *command_line = NULL; 133 char *command_line = NULL;
114 xasprintf(&command_line, "%s %s-b %d -c %d %s", fping_prog, option_string, config.packet_size, config.packet_count, server); 134
135 if (config.icmp_timestamp) {
136 // no packet size settable for ICMP timestamp
137 xasprintf(&command_line, "%s %s -c %d %s", fping_prog, option_string, config.packet_count,
138 server);
139 } else {
140 xasprintf(&command_line, "%s %s-b %d -c %d %s", fping_prog, option_string,
141 config.packet_size, config.packet_count, server);
142 }
115 143
116 if (verbose) { 144 if (verbose) {
117 printf("%s\n", command_line); 145 printf("%s\n", command_line);
@@ -135,8 +163,9 @@ int main(int argc, char **argv) {
135 if (verbose) { 163 if (verbose) {
136 printf("%s", input_buffer); 164 printf("%s", input_buffer);
137 } 165 }
138 status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p, config.crta, config.wrta_p, config.wrta, 166 status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p,
139 config.cpl_p, config.cpl, config.wpl_p, config.wpl, config.alive_p)); 167 config.crta, config.wrta_p, config.wrta, config.cpl_p,
168 config.cpl, config.wpl_p, config.wpl, config.alive_p));
140 } 169 }
141 170
142 /* If we get anything on STDERR, at least set warning */ 171 /* If we get anything on STDERR, at least set warning */
@@ -145,8 +174,9 @@ int main(int argc, char **argv) {
145 if (verbose) { 174 if (verbose) {
146 printf("%s", input_buffer); 175 printf("%s", input_buffer);
147 } 176 }
148 status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p, config.crta, config.wrta_p, config.wrta, 177 status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p,
149 config.cpl_p, config.cpl, config.wpl_p, config.wpl, config.alive_p)); 178 config.crta, config.wrta_p, config.wrta, config.cpl_p,
179 config.cpl, config.wpl_p, config.wpl, config.alive_p));
150 } 180 }
151 (void)fclose(child_stderr); 181 (void)fclose(child_stderr);
152 182
@@ -175,8 +205,8 @@ int main(int argc, char **argv) {
175 return status; 205 return status;
176} 206}
177 207
178mp_state_enum textscan(char *buf, const char *server_name, bool crta_p, double crta, bool wrta_p, double wrta, bool cpl_p, int cpl, 208mp_state_enum textscan(char *buf, const char *server_name, bool crta_p, double crta, bool wrta_p,
179 bool wpl_p, int wpl, bool alive_p) { 209 double wrta, bool cpl_p, int cpl, bool wpl_p, int wpl, bool alive_p) {
180 /* stops testing after the first successful reply. */ 210 /* stops testing after the first successful reply. */
181 double rta; 211 double rta;
182 double loss; 212 double loss;
@@ -189,7 +219,8 @@ mp_state_enum textscan(char *buf, const char *server_name, bool crta_p, double c
189 die(STATE_OK, _("FPING %s - %s (rta=%f ms)|%s\n"), state_text(STATE_OK), server_name, rta, 219 die(STATE_OK, _("FPING %s - %s (rta=%f ms)|%s\n"), state_text(STATE_OK), server_name, rta,
190 /* No loss since we only waited for the first reply 220 /* No loss since we only waited for the first reply
191 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), */ 221 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), */
192 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0, false, 0)); 222 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0,
223 false, 0));
193 } 224 }
194 225
195 mp_state_enum status = STATE_UNKNOWN; 226 mp_state_enum status = STATE_UNKNOWN;
@@ -230,9 +261,11 @@ mp_state_enum textscan(char *buf, const char *server_name, bool crta_p, double c
230 } else { 261 } else {
231 status = STATE_OK; 262 status = STATE_OK;
232 } 263 }
233 die(status, _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"), state_text(status), server_name, loss, rta, 264 die(status, _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"), state_text(status),
265 server_name, loss, rta,
234 perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, false, 0, false, 0), 266 perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, false, 0, false, 0),
235 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0, false, 0)); 267 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0,
268 false, 0));
236 269
237 } else if (strstr(buf, "xmt/rcv/%loss")) { 270 } else if (strstr(buf, "xmt/rcv/%loss")) {
238 /* no min/max/avg if host was unreachable in fping v2.2.b1 */ 271 /* no min/max/avg if host was unreachable in fping v2.2.b1 */
@@ -268,13 +301,38 @@ mp_state_enum textscan(char *buf, const char *server_name, bool crta_p, double c
268 301
269/* process command-line arguments */ 302/* process command-line arguments */
270check_fping_config_wrapper process_arguments(int argc, char **argv) { 303check_fping_config_wrapper process_arguments(int argc, char **argv) {
271 static struct option longopts[] = { 304 enum {
272 {"hostname", required_argument, 0, 'H'}, {"sourceip", required_argument, 0, 'S'}, {"sourceif", required_argument, 0, 'I'}, 305 FWMARK_OPT = CHAR_MAX + 1,
273 {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'}, {"alive", no_argument, 0, 'a'}, 306 ICMP_TIMESTAMP_OPT,
274 {"bytes", required_argument, 0, 'b'}, {"number", required_argument, 0, 'n'}, {"target-timeout", required_argument, 0, 'T'}, 307 CHECK_SOURCE_OPT,
275 {"interval", required_argument, 0, 'i'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, 308 };
276 {"help", no_argument, 0, 'h'}, {"use-ipv4", no_argument, 0, '4'}, {"use-ipv6", no_argument, 0, '6'}, 309 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
277 {"dontfrag", no_argument, 0, 'M'}, {"random", no_argument, 0, 'R'}, {0, 0, 0, 0}}; 310 {"sourceip", required_argument, 0, 'S'},
311 {"sourceif", required_argument, 0, 'I'},
312 {"critical", required_argument, 0, 'c'},
313 {"warning", required_argument, 0, 'w'},
314 {"alive", no_argument, 0, 'a'},
315 {"bytes", required_argument, 0, 'b'},
316 {"number", required_argument, 0, 'n'},
317 {"target-timeout", required_argument, 0, 'T'},
318 {"interval", required_argument, 0, 'i'},
319 {"verbose", no_argument, 0, 'v'},
320 {"version", no_argument, 0, 'V'},
321 {"help", no_argument, 0, 'h'},
322 {"use-ipv4", no_argument, 0, '4'},
323 {"use-ipv6", no_argument, 0, '6'},
324 {"dontfrag", no_argument, 0, 'M'},
325 {"random", no_argument, 0, 'R'},
326#ifdef FPING_VERSION_5_2_OR_HIGHER
327 // only available with fping version >= 5.2
328 {"fwmark", required_argument, NULL, FWMARK_OPT},
329# ifdef FPING_VERSION_5_3_OR_HIGHER
330 // only available with fping version >= 5.3
331 {"icmp-timestamp", no_argument, NULL, ICMP_TIMESTAMP_OPT},
332 {"check-source", no_argument, NULL, CHECK_SOURCE_OPT},
333# endif
334#endif
335 {0, 0, 0, 0}};
278 336
279 char *rv[2]; 337 char *rv[2];
280 rv[PL] = NULL; 338 rv[PL] = NULL;
@@ -299,8 +357,9 @@ check_fping_config_wrapper process_arguments(int argc, char **argv) {
299 argc--; 357 argc--;
300 } 358 }
301 359
302 while (1) { 360 while (true) {
303 int option_index = getopt_long(argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:M:R:46", longopts, &option); 361 int option_index =
362 getopt_long(argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:M:R:46", longopts, &option);
304 363
305 if (option_index == -1 || option_index == EOF || option_index == 1) { 364 if (option_index == -1 || option_index == EOF || option_index == 1) {
306 break; 365 break;
@@ -340,11 +399,7 @@ check_fping_config_wrapper process_arguments(int argc, char **argv) {
340 address_family = AF_INET; 399 address_family = AF_INET;
341 break; 400 break;
342 case '6': /* IPv6 only */ 401 case '6': /* IPv6 only */
343#ifdef USE_IPV6
344 address_family = AF_INET6; 402 address_family = AF_INET6;
345#else
346 usage(_("IPv6 support not available\n"));
347#endif
348 break; 403 break;
349 case 'c': 404 case 'c':
350 get_threshold(optarg, rv); 405 get_threshold(optarg, rv);
@@ -406,6 +461,20 @@ check_fping_config_wrapper process_arguments(int argc, char **argv) {
406 case 'M': 461 case 'M':
407 result.config.dontfrag = true; 462 result.config.dontfrag = true;
408 break; 463 break;
464 case FWMARK_OPT:
465 if (is_intpos(optarg)) {
466 result.config.fwmark = (unsigned int)atol(optarg);
467 result.config.fwmark_set = true;
468 } else {
469 usage(_("fwmark must be a positive integer"));
470 }
471 break;
472 case ICMP_TIMESTAMP_OPT:
473 result.config.icmp_timestamp = true;
474 break;
475 case CHECK_SOURCE_OPT:
476 result.config.check_source = true;
477 break;
409 } 478 }
410 } 479 }
411 480
@@ -427,10 +496,12 @@ int get_threshold(char *arg, char *rv[2]) {
427 if (arg2) { 496 if (arg2) {
428 arg1[strcspn(arg1, ",:")] = 0; 497 arg1[strcspn(arg1, ",:")] = 0;
429 if (strstr(arg1, "%") && strstr(arg2, "%")) { 498 if (strstr(arg1, "%") && strstr(arg2, "%")) {
430 die(STATE_UNKNOWN, _("%s: Only one threshold may be packet loss (%s)\n"), progname, arg); 499 die(STATE_UNKNOWN, _("%s: Only one threshold may be packet loss (%s)\n"), progname,
500 arg);
431 } 501 }
432 if (!strstr(arg1, "%") && !strstr(arg2, "%")) { 502 if (!strstr(arg1, "%") && !strstr(arg2, "%")) {
433 die(STATE_UNKNOWN, _("%s: Only one threshold must be packet loss (%s)\n"), progname, arg); 503 die(STATE_UNKNOWN, _("%s: Only one threshold must be packet loss (%s)\n"), progname,
504 arg);
434 } 505 }
435 } 506 }
436 507
@@ -456,7 +527,8 @@ void print_help(void) {
456 printf("Copyright (c) 1999 Didi Rieder <adrieder@sbox.tu-graz.ac.at>\n"); 527 printf("Copyright (c) 1999 Didi Rieder <adrieder@sbox.tu-graz.ac.at>\n");
457 printf(COPYRIGHT, copyright, email); 528 printf(COPYRIGHT, copyright, email);
458 529
459 printf("%s\n", _("This plugin will use the fping command to ping the specified host for a fast check")); 530 printf("%s\n",
531 _("This plugin will use the fping command to ping the specified host for a fast check"));
460 532
461 printf("%s\n", _("Note that it is necessary to set the suid flag on fping.")); 533 printf("%s\n", _("Note that it is necessary to set the suid flag on fping."));
462 534
@@ -470,7 +542,8 @@ void print_help(void) {
470 printf(UT_IPv46); 542 printf(UT_IPv46);
471 543
472 printf(" %s\n", "-H, --hostname=HOST"); 544 printf(" %s\n", "-H, --hostname=HOST");
473 printf(" %s\n", _("name or IP Address of host to ping (IP Address bypasses name lookup, reducing system load)")); 545 printf(" %s\n", _("name or IP Address of host to ping (IP Address bypasses name lookup, "
546 "reducing system load)"));
474 printf(" %s\n", "-w, --warning=THRESHOLD"); 547 printf(" %s\n", "-w, --warning=THRESHOLD");
475 printf(" %s\n", _("warning threshold pair")); 548 printf(" %s\n", _("warning threshold pair"));
476 printf(" %s\n", "-c, --critical=THRESHOLD"); 549 printf(" %s\n", "-c, --critical=THRESHOLD");
@@ -484,7 +557,8 @@ void print_help(void) {
484 printf(" %s\n", "-T, --target-timeout=INTEGER"); 557 printf(" %s\n", "-T, --target-timeout=INTEGER");
485 printf(" %s (default: fping's default for -t)\n", _("Target timeout (ms)")); 558 printf(" %s (default: fping's default for -t)\n", _("Target timeout (ms)"));
486 printf(" %s\n", "-i, --interval=INTEGER"); 559 printf(" %s\n", "-i, --interval=INTEGER");
487 printf(" %s (default: fping's default for -p)\n", _("Interval (ms) between sending packets")); 560 printf(" %s (default: fping's default for -p)\n",
561 _("Interval (ms) between sending packets"));
488 printf(" %s\n", "-S, --sourceip=HOST"); 562 printf(" %s\n", "-S, --sourceip=HOST");
489 printf(" %s\n", _("name or IP Address of sourceip")); 563 printf(" %s\n", _("name or IP Address of sourceip"));
490 printf(" %s\n", "-I, --sourceif=IF"); 564 printf(" %s\n", "-I, --sourceif=IF");
@@ -493,9 +567,20 @@ void print_help(void) {
493 printf(" %s\n", _("set the Don't Fragment flag")); 567 printf(" %s\n", _("set the Don't Fragment flag"));
494 printf(" %s\n", "-R, --random"); 568 printf(" %s\n", "-R, --random");
495 printf(" %s\n", _("random packet data (to foil link data compression)")); 569 printf(" %s\n", _("random packet data (to foil link data compression)"));
570#ifdef FPING_VERSION_5_2_OR_HIGHER
571 printf(" %s\n", "--fwmark=INTEGER");
572 printf(" %s\n", _("set the routing mark to INTEGER (fping option)"));
573# ifdef FPING_VERSION_5_3_OR_HIGHER
574 printf(" %s\n", "--icmp-timestamp");
575 printf(" %s\n", _("use ICMP Timestamp instead of ICMP Echo (fping option)"));
576 printf(" %s\n", "--check-source");
577 printf(" %s\n", _("discard replies not from target address (fping option)"));
578# endif
579#endif
496 printf(UT_VERBOSE); 580 printf(UT_VERBOSE);
497 printf("\n"); 581 printf("\n");
498 printf(" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)")); 582 printf(" %s\n",
583 _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)"));
499 printf(" %s\n", _("which triggers a WARNING or CRITICAL state, and <pl> is the percentage of")); 584 printf(" %s\n", _("which triggers a WARNING or CRITICAL state, and <pl> is the percentage of"));
500 printf(" %s\n", _("packet loss to trigger an alarm state.")); 585 printf(" %s\n", _("packet loss to trigger an alarm state."));
501 586
@@ -507,5 +592,6 @@ void print_help(void) {
507 592
508void print_usage(void) { 593void print_usage(void) {
509 printf("%s\n", _("Usage:")); 594 printf("%s\n", _("Usage:"));
510 printf(" %s <host_address> -w limit -c limit [-b size] [-n number] [-T number] [-i number]\n", progname); 595 printf(" %s <host_address> -w limit -c limit [-b size] [-n number] [-T number] [-i number]\n",
596 progname);
511} 597}
diff --git a/plugins/check_fping.d/config.h b/plugins/check_fping.d/config.h
index a0697bf3..d3e50565 100644
--- a/plugins/check_fping.d/config.h
+++ b/plugins/check_fping.d/config.h
@@ -29,6 +29,20 @@ typedef struct {
29 bool cpl_p; 29 bool cpl_p;
30 int wpl; 30 int wpl;
31 bool wpl_p; 31 bool wpl_p;
32
33 // only available with fping version >= 5.2
34 // for a given uint _fwmark_ fping sets _fwmark_ as a firewall mark
35 // in the packets
36 unsigned int fwmark;
37 bool fwmark_set;
38
39 // only available with fping version >= 5.3
40 // Setting icmp_timestamp tells fping to use ICMP Timestamp (ICMP type 13) instead
41 // of ICMP Echo
42 bool icmp_timestamp;
43
44 // Setting check_source lets fping discard replies which are not from the target address
45 bool check_source;
32} check_fping_config; 46} check_fping_config;
33 47
34check_fping_config check_fping_config_init() { 48check_fping_config check_fping_config_init() {
@@ -53,6 +67,15 @@ check_fping_config check_fping_config_init() {
53 .cpl_p = false, 67 .cpl_p = false,
54 .wpl = 0, 68 .wpl = 0,
55 .wpl_p = false, 69 .wpl_p = false,
70
71 // only available with fping version >= 5.2
72 .fwmark = 0,
73 .fwmark_set = false, // just to be deterministic
74
75 // only available with fping version >= 5.3
76 .icmp_timestamp = false,
77 .check_source = false,
78
56 }; 79 };
57 return tmp; 80 return tmp;
58} 81}
diff --git a/plugins/check_game.c b/plugins/check_game.c
index c0193b03..974a7253 100644
--- a/plugins/check_game.c
+++ b/plugins/check_game.c
@@ -77,7 +77,8 @@ int main(int argc, char **argv) {
77 77
78 /* create the command line to execute */ 78 /* create the command line to execute */
79 char *command_line = NULL; 79 char *command_line = NULL;
80 xasprintf(&command_line, "%s -raw %s -%s %s", PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, config.game_type, config.server_ip); 80 xasprintf(&command_line, "%s -raw %s -%s %s", PATH_TO_QSTAT, QSTAT_DATA_DELIMITER,
81 config.game_type, config.server_ip);
81 82
82 if (config.port) { 83 if (config.port) {
83 xasprintf(&command_line, "%s:%-d", command_line, config.port); 84 xasprintf(&command_line, "%s:%-d", command_line, config.port);
@@ -130,11 +131,13 @@ int main(int argc, char **argv) {
130 printf(_("CRITICAL - Game server timeout\n")); 131 printf(_("CRITICAL - Game server timeout\n"));
131 result = STATE_CRITICAL; 132 result = STATE_CRITICAL;
132 } else { 133 } else {
133 printf("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n", ret[config.qstat_game_players], ret[config.qstat_game_players_max], 134 printf("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n", ret[config.qstat_game_players],
134 ret[config.qstat_game_field], ret[config.qstat_map_field], ret[config.qstat_ping_field], 135 ret[config.qstat_game_players_max], ret[config.qstat_game_field],
135 perfdata("players", atol(ret[config.qstat_game_players]), "", false, 0, false, 0, true, 0, true, 136 ret[config.qstat_map_field], ret[config.qstat_ping_field],
136 atol(ret[config.qstat_game_players_max])), 137 perfdata("players", atol(ret[config.qstat_game_players]), "", false, 0, false, 0,
137 fperfdata("ping", strtod(ret[config.qstat_ping_field], NULL), "", false, 0, false, 0, true, 0, false, 0)); 138 true, 0, true, atol(ret[config.qstat_game_players_max])),
139 fperfdata("ping", strtod(ret[config.qstat_ping_field], NULL), "", false, 0, false, 0,
140 true, 0, false, 0));
138 } 141 }
139 142
140 exit(result); 143 exit(result);
@@ -144,19 +147,20 @@ int main(int argc, char **argv) {
144#define max_players_field_index 130 147#define max_players_field_index 130
145 148
146check_game_config_wrapper process_arguments(int argc, char **argv) { 149check_game_config_wrapper process_arguments(int argc, char **argv) {
147 static struct option long_opts[] = {{"help", no_argument, 0, 'h'}, 150 static struct option long_opts[] = {
148 {"version", no_argument, 0, 'V'}, 151 {"help", no_argument, 0, 'h'},
149 {"verbose", no_argument, 0, 'v'}, 152 {"version", no_argument, 0, 'V'},
150 {"timeout", required_argument, 0, 't'}, 153 {"verbose", no_argument, 0, 'v'},
151 {"hostname", required_argument, 0, 'H'}, 154 {"timeout", required_argument, 0, 't'},
152 {"port", required_argument, 0, 'P'}, 155 {"hostname", required_argument, 0, 'H'},
153 {"game-type", required_argument, 0, 'G'}, 156 {"port", required_argument, 0, 'P'},
154 {"map-field", required_argument, 0, 'm'}, 157 {"game-type", required_argument, 0, 'G'},
155 {"ping-field", required_argument, 0, 'p'}, 158 {"map-field", required_argument, 0, 'm'},
156 {"game-field", required_argument, 0, 'g'}, 159 {"ping-field", required_argument, 0, 'p'},
157 {"players-field", required_argument, 0, players_field_index}, 160 {"game-field", required_argument, 0, 'g'},
158 {"max-players-field", required_argument, 0, max_players_field_index}, 161 {"players-field", required_argument, 0, players_field_index},
159 {0, 0, 0, 0}}; 162 {"max-players-field", required_argument, 0, max_players_field_index},
163 {0, 0, 0, 0}};
160 164
161 check_game_config_wrapper result = { 165 check_game_config_wrapper result = {
162 .config = check_game_config_init(), 166 .config = check_game_config_init(),
@@ -216,21 +220,24 @@ check_game_config_wrapper process_arguments(int argc, char **argv) {
216 break; 220 break;
217 case 'p': /* index of ping field */ 221 case 'p': /* index of ping field */
218 result.config.qstat_ping_field = atoi(optarg); 222 result.config.qstat_ping_field = atoi(optarg);
219 if (result.config.qstat_ping_field < 0 || result.config.qstat_ping_field > QSTAT_MAX_RETURN_ARGS) { 223 if (result.config.qstat_ping_field < 0 ||
224 result.config.qstat_ping_field > QSTAT_MAX_RETURN_ARGS) {
220 result.errorcode = ERROR; 225 result.errorcode = ERROR;
221 return result; 226 return result;
222 } 227 }
223 break; 228 break;
224 case 'm': /* index on map field */ 229 case 'm': /* index on map field */
225 result.config.qstat_map_field = atoi(optarg); 230 result.config.qstat_map_field = atoi(optarg);
226 if (result.config.qstat_map_field < 0 || result.config.qstat_map_field > QSTAT_MAX_RETURN_ARGS) { 231 if (result.config.qstat_map_field < 0 ||
232 result.config.qstat_map_field > QSTAT_MAX_RETURN_ARGS) {
227 result.errorcode = ERROR; 233 result.errorcode = ERROR;
228 return result; 234 return result;
229 } 235 }
230 break; 236 break;
231 case 'g': /* index of game field */ 237 case 'g': /* index of game field */
232 result.config.qstat_game_field = atoi(optarg); 238 result.config.qstat_game_field = atoi(optarg);
233 if (result.config.qstat_game_field < 0 || result.config.qstat_game_field > QSTAT_MAX_RETURN_ARGS) { 239 if (result.config.qstat_game_field < 0 ||
240 result.config.qstat_game_field > QSTAT_MAX_RETURN_ARGS) {
234 result.errorcode = ERROR; 241 result.errorcode = ERROR;
235 return result; 242 return result;
236 } 243 }
@@ -240,14 +247,16 @@ check_game_config_wrapper process_arguments(int argc, char **argv) {
240 if (result.config.qstat_game_players_max == 0) { 247 if (result.config.qstat_game_players_max == 0) {
241 result.config.qstat_game_players_max = result.config.qstat_game_players - 1; 248 result.config.qstat_game_players_max = result.config.qstat_game_players - 1;
242 } 249 }
243 if (result.config.qstat_game_players < 0 || result.config.qstat_game_players > QSTAT_MAX_RETURN_ARGS) { 250 if (result.config.qstat_game_players < 0 ||
251 result.config.qstat_game_players > QSTAT_MAX_RETURN_ARGS) {
244 result.errorcode = ERROR; 252 result.errorcode = ERROR;
245 return result; 253 return result;
246 } 254 }
247 break; 255 break;
248 case max_players_field_index: /* index of max players field */ 256 case max_players_field_index: /* index of max players field */
249 result.config.qstat_game_players_max = atoi(optarg); 257 result.config.qstat_game_players_max = atoi(optarg);
250 if (result.config.qstat_game_players_max < 0 || result.config.qstat_game_players_max > QSTAT_MAX_RETURN_ARGS) { 258 if (result.config.qstat_game_players_max < 0 ||
259 result.config.qstat_game_players_max > QSTAT_MAX_RETURN_ARGS) {
251 result.errorcode = ERROR; 260 result.errorcode = ERROR;
252 return result; 261 return result;
253 } 262 }
@@ -286,7 +295,7 @@ void print_help(void) {
286 printf(UT_HELP_VRSN); 295 printf(UT_HELP_VRSN);
287 printf(UT_EXTRA_OPTS); 296 printf(UT_EXTRA_OPTS);
288 printf(" -H, --hostname=ADDRESS\n" 297 printf(" -H, --hostname=ADDRESS\n"
289 " Host name, IP Address, or unix socket (must be an absolute path)\n"); 298 " Host name, IP Address, or unix socket (must be an absolute path)\n");
290 printf(" %s\n", "-P"); 299 printf(" %s\n", "-P");
291 printf(" %s\n", _("Optional port to connect to")); 300 printf(" %s\n", _("Optional port to connect to"));
292 printf(" %s\n", "-g"); 301 printf(" %s\n", "-g");
@@ -300,8 +309,10 @@ void print_help(void) {
300 309
301 printf("\n"); 310 printf("\n");
302 printf("%s\n", _("Notes:")); 311 printf("%s\n", _("Notes:"));
303 printf(" %s\n", _("This plugin uses the 'qstat' command, the popular game server status query tool.")); 312 printf(" %s\n",
304 printf(" %s\n", _("If you don't have the package installed, you will need to download it from")); 313 _("This plugin uses the 'qstat' command, the popular game server status query tool."));
314 printf(" %s\n",
315 _("If you don't have the package installed, you will need to download it from"));
305 printf(" %s\n", _("https://github.com/multiplay/qstat before you can use this plugin.")); 316 printf(" %s\n", _("https://github.com/multiplay/qstat before you can use this plugin."));
306 317
307 printf(UT_SUPPORT); 318 printf(UT_SUPPORT);
@@ -309,7 +320,8 @@ void print_help(void) {
309 320
310void print_usage(void) { 321void print_usage(void) {
311 printf("%s\n", _("Usage:")); 322 printf("%s\n", _("Usage:"));
312 printf(" %s [-hvV] [-P port] [-t timeout] [-g game_field] [-m map_field] [-p ping_field] [-G game-time] [-H hostname] <game> " 323 printf(" %s [-hvV] [-P port] [-t timeout] [-g game_field] [-m map_field] [-p ping_field] [-G "
324 "game-time] [-H hostname] <game> "
313 "<ip_address>\n", 325 "<ip_address>\n",
314 progname); 326 progname);
315} 327}
diff --git a/plugins/check_hpjd.c b/plugins/check_hpjd.c
index 62417fd6..9907abc5 100644
--- a/plugins/check_hpjd.c
+++ b/plugins/check_hpjd.c
@@ -85,13 +85,16 @@ int main(int argc, char **argv) {
85 char query_string[512]; 85 char query_string[512];
86 /* removed ' 2>1' at end of command 10/27/1999 - EG */ 86 /* removed ' 2>1' at end of command 10/27/1999 - EG */
87 /* create the query string */ 87 /* create the query string */
88 sprintf(query_string, "%s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0", HPJD_LINE_STATUS, HPJD_PAPER_STATUS, 88 sprintf(query_string, "%s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0",
89 HPJD_INTERVENTION_REQUIRED, HPJD_GD_PERIPHERAL_ERROR, HPJD_GD_PAPER_JAM, HPJD_GD_PAPER_OUT, HPJD_GD_TONER_LOW, 89 HPJD_LINE_STATUS, HPJD_PAPER_STATUS, HPJD_INTERVENTION_REQUIRED,
90 HPJD_GD_PAGE_PUNT, HPJD_GD_MEMORY_OUT, HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT, HPJD_GD_STATUS_DISPLAY); 90 HPJD_GD_PERIPHERAL_ERROR, HPJD_GD_PAPER_JAM, HPJD_GD_PAPER_OUT, HPJD_GD_TONER_LOW,
91 HPJD_GD_PAGE_PUNT, HPJD_GD_MEMORY_OUT, HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT,
92 HPJD_GD_STATUS_DISPLAY);
91 93
92 /* get the command to run */ 94 /* get the command to run */
93 char command_line[1024]; 95 char command_line[1024];
94 sprintf(command_line, "%s -OQa -m : -v 1 -c %s %s:%u %s", PATH_TO_SNMPGET, config.community, config.address, config.port, query_string); 96 sprintf(command_line, "%s -OQa -m : -v 1 -c %s %s:%u %s", PATH_TO_SNMPGET, config.community,
97 config.address, config.port, query_string);
95 98
96 /* run the command */ 99 /* run the command */
97 child_process = spopen(command_line); 100 child_process = spopen(command_line);
@@ -177,7 +180,8 @@ int main(int argc, char **argv) {
177 strcpy(display_message, temp_buffer + 1); 180 strcpy(display_message, temp_buffer + 1);
178 break; 181 break;
179 default: /* fold multiline message */ 182 default: /* fold multiline message */
180 strncat(display_message, input_buffer, sizeof(display_message) - strlen(display_message) - 1); 183 strncat(display_message, input_buffer,
184 sizeof(display_message) - strlen(display_message) - 1);
181 } 185 }
182 } 186 }
183 187
diff --git a/plugins/check_http.c b/plugins/check_http.c
index baff682a..d2f080c7 100644
--- a/plugins/check_http.c
+++ b/plugins/check_http.c
@@ -1,35 +1,35 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_http plugin 3 * Monitoring check_http plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2024 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_http plugin 10 * This file contains the check_http plugin
11* 11 *
12* This plugin tests the HTTP service on the specified host. It can test 12 * This plugin tests the HTTP service on the specified host. It can test
13* normal (http) and secure (https) servers, follow redirects, search for 13 * normal (http) and secure (https) servers, follow redirects, search for
14* strings and regular expressions, check connection times, and report on 14 * strings and regular expressions, check connection times, and report on
15* certificate expiration times. 15 * certificate expiration times.
16* 16 *
17* 17 *
18* This program is free software: you can redistribute it and/or modify 18 * This program is free software: you can redistribute it and/or modify
19* it under the terms of the GNU General Public License as published by 19 * it under the terms of the GNU General Public License as published by
20* the Free Software Foundation, either version 3 of the License, or 20 * the Free Software Foundation, either version 3 of the License, or
21* (at your option) any later version. 21 * (at your option) any later version.
22* 22 *
23* This program is distributed in the hope that it will be useful, 23 * This program is distributed in the hope that it will be useful,
24* but WITHOUT ANY WARRANTY; without even the implied warranty of 24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26* GNU General Public License for more details. 26 * GNU General Public License for more details.
27* 27 *
28* You should have received a copy of the GNU General Public License 28 * You should have received a copy of the GNU General Public License
29* along with this program. If not, see <http://www.gnu.org/licenses/>. 29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30* 30 *
31* 31 *
32*****************************************************************************/ 32 *****************************************************************************/
33 33
34const char *progname = "check_http"; 34const char *progname = "check_http";
35const char *copyright = "1999-2024"; 35const char *copyright = "1999-2024";
@@ -41,7 +41,6 @@ const char *email = "devel@monitoring-plugins.org";
41#include "base64.h" 41#include "base64.h"
42#include "netutils.h" 42#include "netutils.h"
43#include "utils.h" 43#include "utils.h"
44#include "base64.h"
45#include <ctype.h> 44#include <ctype.h>
46 45
47#define STICKY_NONE 0 46#define STICKY_NONE 0
@@ -50,1346 +49,1394 @@ const char *email = "devel@monitoring-plugins.org";
50 49
51#define HTTP_EXPECT "HTTP/1." 50#define HTTP_EXPECT "HTTP/1."
52enum { 51enum {
53 MAX_IPV4_HOSTLENGTH = 255, 52 MAX_IPV4_HOSTLENGTH = 255,
54 HTTP_PORT = 80, 53 HTTP_PORT = 80,
55 HTTPS_PORT = 443, 54 HTTPS_PORT = 443,
56 MAX_PORT = 65535, 55 MAX_PORT = 65535,
57 DEFAULT_MAX_REDIRS = 15 56 DEFAULT_MAX_REDIRS = 15
58}; 57};
59 58
60#ifdef HAVE_SSL 59#ifdef HAVE_SSL
61bool check_cert = false; 60static bool check_cert = false;
62bool continue_after_check_cert = false; 61static bool continue_after_check_cert = false;
63int ssl_version = 0; 62static int ssl_version = 0;
64int days_till_exp_warn, days_till_exp_crit; 63static int days_till_exp_warn, days_till_exp_crit;
65char *randbuff; 64# define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
66X509 *server_cert; 65# define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
67# define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
68# define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
69#else /* ifndef HAVE_SSL */ 66#else /* ifndef HAVE_SSL */
70# define my_recv(buf, len) read(sd, buf, len) 67# define my_recv(buf, len) read(sd, buf, len)
71# define my_send(buf, len) send(sd, buf, len, 0) 68# define my_send(buf, len) send(sd, buf, len, 0)
72#endif /* HAVE_SSL */ 69#endif /* HAVE_SSL */
73bool no_body = false; 70static bool no_body = false;
74int maximum_age = -1; 71static int maximum_age = -1;
75 72
76enum { 73enum {
77 REGS = 2, 74 REGS = 2,
78 MAX_RE_SIZE = 1024 75 MAX_RE_SIZE = 1024
79}; 76};
80#include "regex.h" 77#include "regex.h"
81regex_t preg; 78static regex_t preg;
82regmatch_t pmatch[REGS]; 79static regmatch_t pmatch[REGS];
83char regexp[MAX_RE_SIZE]; 80static char regexp[MAX_RE_SIZE];
84char errbuf[MAX_INPUT_BUFFER]; 81static char errbuf[MAX_INPUT_BUFFER];
85int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE; 82static int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
86int errcode; 83static int errcode;
87int invert_regex = 0; 84static int invert_regex = 0;
88int state_regex = STATE_CRITICAL; 85static int state_regex = STATE_CRITICAL;
89 86
90struct timeval tv; 87static struct timeval tv;
91struct timeval tv_temp; 88static struct timeval tv_temp;
92 89
93#define HTTP_URL "/" 90#define HTTP_URL "/"
94#define CRLF "\r\n" 91#define CRLF "\r\n"
95 92
96bool specify_port = false; 93static bool specify_port = false;
97int server_port = HTTP_PORT; 94static int server_port = HTTP_PORT;
98int virtual_port = 0; 95static int virtual_port = 0;
99char server_port_text[6] = ""; 96static char server_type[6] = "http";
100char server_type[6] = "http"; 97static char *server_address;
101char *server_address; 98static char *host_name;
102char *host_name; 99static int host_name_length;
103int host_name_length; 100static char *server_url;
104char *server_url; 101static char *user_agent;
105char *user_agent; 102static int server_url_length;
106int server_url_length; 103static int server_expect_yn = 0;
107int server_expect_yn = 0; 104static char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
108char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT; 105static char header_expect[MAX_INPUT_BUFFER] = "";
109char header_expect[MAX_INPUT_BUFFER] = ""; 106static char string_expect[MAX_INPUT_BUFFER] = "";
110char string_expect[MAX_INPUT_BUFFER] = ""; 107static char *warning_thresholds = NULL;
111char *warning_thresholds = NULL; 108static char *critical_thresholds = NULL;
112char *critical_thresholds = NULL; 109static thresholds *thlds;
113thresholds *thlds; 110static char user_auth[MAX_INPUT_BUFFER] = "";
114char user_auth[MAX_INPUT_BUFFER] = ""; 111static char proxy_auth[MAX_INPUT_BUFFER] = "";
115char proxy_auth[MAX_INPUT_BUFFER] = ""; 112static bool display_html = false;
116bool display_html = false; 113static char **http_opt_headers;
117char **http_opt_headers; 114static int http_opt_headers_count = 0;
118int http_opt_headers_count = 0; 115static int onredirect = STATE_OK;
119int onredirect = STATE_OK; 116static int followsticky = STICKY_NONE;
120int followsticky = STICKY_NONE; 117static bool use_ssl = false;
121bool use_ssl = false; 118static bool use_sni = false;
122bool use_sni = false; 119static bool verbose = false;
123bool verbose = false; 120static bool show_extended_perfdata = false;
124bool show_extended_perfdata = false; 121static bool show_body = false;
125bool show_body = false; 122static int sd;
126int sd; 123static int min_page_len = 0;
127int min_page_len = 0; 124static int max_page_len = 0;
128int max_page_len = 0; 125static int redir_depth = 0;
129int redir_depth = 0; 126static int max_depth = DEFAULT_MAX_REDIRS;
130int max_depth = DEFAULT_MAX_REDIRS; 127static char *http_method;
131char *http_method; 128static char *http_method_proxy;
132char *http_method_proxy; 129static char *http_post_data;
133char *http_post_data; 130static char *http_content_type;
134char *http_content_type; 131static char buffer[MAX_INPUT_BUFFER];
135char buffer[MAX_INPUT_BUFFER]; 132static char *client_cert = NULL;
136char *client_cert = NULL; 133static char *client_privkey = NULL;
137char *client_privkey = NULL;
138 134
139// Forward function declarations 135// Forward function declarations
140bool process_arguments (int, char **); 136static bool process_arguments(int /*argc*/, char ** /*argv*/);
141int check_http (void); 137static int check_http(void);
142void redir (char *pos, char *status_line); 138static void redir(char *pos, char *status_line);
143bool server_type_check(const char *type); 139static bool server_type_check(const char *type);
144int server_port_check(int ssl_flag); 140static int server_port_check(int ssl_flag);
145char *perfd_time (double microsec); 141static char *perfd_time(double elapsed_time);
146char *perfd_time_connect (double microsec); 142static char *perfd_time_connect(double elapsed_time_connect);
147char *perfd_time_ssl (double microsec); 143static char *perfd_time_ssl(double elapsed_time_ssl);
148char *perfd_time_firstbyte (double microsec); 144static char *perfd_time_firstbyte(double elapsed_time_firstbyte);
149char *perfd_time_headers (double microsec); 145static char *perfd_time_headers(double elapsed_time_headers);
150char *perfd_time_transfer (double microsec); 146static char *perfd_time_transfer(double elapsed_time_transfer);
151char *perfd_size (int page_len); 147static char *perfd_size(int page_len);
152void print_help (void); 148void print_help(void);
153void print_usage (void); 149void print_usage(void);
154char *unchunk_content(const char *content); 150static char *unchunk_content(const char *content);
155 151
156int 152int main(int argc, char **argv) {
157main (int argc, char **argv) 153 int result = STATE_UNKNOWN;
158{ 154
159 int result = STATE_UNKNOWN; 155 setlocale(LC_ALL, "");
160 156 bindtextdomain(PACKAGE, LOCALEDIR);
161 setlocale (LC_ALL, ""); 157 textdomain(PACKAGE);
162 bindtextdomain (PACKAGE, LOCALEDIR); 158
163 textdomain (PACKAGE); 159 /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
164 160 server_url = strdup(HTTP_URL);
165 /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */ 161 server_url_length = strlen(server_url);
166 server_url = strdup(HTTP_URL); 162 xasprintf(&user_agent, "User-Agent: check_http/v%s (monitoring-plugins %s)", NP_VERSION,
167 server_url_length = strlen(server_url); 163 VERSION);
168 xasprintf (&user_agent, "User-Agent: check_http/v%s (monitoring-plugins %s)", 164
169 NP_VERSION, VERSION); 165 /* Parse extra opts if any */
170 166 argv = np_extra_opts(&argc, argv, progname);
171 /* Parse extra opts if any */ 167
172 argv=np_extra_opts (&argc, argv, progname); 168 if (!process_arguments(argc, argv)) {
173 169 usage4(_("Could not parse arguments"));
174 if (process_arguments (argc, argv) == false) 170 }
175 usage4 (_("Could not parse arguments")); 171
176 172 if (display_html) {
177 if (display_html == true) 173 printf("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", use_ssl ? "https" : "http",
178 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", 174 host_name ? host_name : server_address, server_port, server_url);
179 use_ssl ? "https" : "http", host_name ? host_name : server_address, 175 }
180 server_port, server_url); 176
181 177 /* initialize alarm signal handling, set socket timeout, start timer */
182 /* initialize alarm signal handling, set socket timeout, start timer */ 178 (void)signal(SIGALRM, socket_timeout_alarm_handler);
183 (void) signal (SIGALRM, socket_timeout_alarm_handler); 179 (void)alarm(socket_timeout);
184 (void) alarm (socket_timeout); 180 gettimeofday(&tv, NULL);
185 gettimeofday (&tv, NULL); 181
186 182 result = check_http();
187 result = check_http (); 183 return result;
188 return result;
189} 184}
190 185
191/* check whether a file exists */ 186/* check whether a file exists */
192void 187void test_file(char *path) {
193test_file (char *path) 188 if (access(path, R_OK) == 0) {
194{ 189 return;
195 if (access(path, R_OK) == 0) 190 }
196 return; 191 usage2(_("file does not exist or is not readable"), path);
197 usage2 (_("file does not exist or is not readable"), path);
198} 192}
199 193
200/* 194/*
201 * process command-line arguments 195 * process command-line arguments
202 * returns true on success, false otherwise 196 * returns true on success, false otherwise
203 */ 197 */
204bool process_arguments (int argc, char **argv) 198bool process_arguments(int argc, char **argv) {
205{ 199 int c = 1;
206 int c = 1; 200 char *p;
207 char *p; 201 char *temp;
208 char *temp; 202
209 203 enum {
210 enum { 204 INVERT_REGEX = CHAR_MAX + 1,
211 INVERT_REGEX = CHAR_MAX + 1, 205 SNI_OPTION,
212 SNI_OPTION, 206 MAX_REDIRS_OPTION,
213 MAX_REDIRS_OPTION, 207 CONTINUE_AFTER_CHECK_CERT,
214 CONTINUE_AFTER_CHECK_CERT, 208 STATE_REGEX
215 STATE_REGEX 209 };
216 }; 210
217 211 int option = 0;
218 int option = 0; 212 static struct option longopts[] = {
219 static struct option longopts[] = { 213 STD_LONG_OPTS,
220 STD_LONG_OPTS, 214 {"link", no_argument, 0, 'L'},
221 {"link", no_argument, 0, 'L'}, 215 {"nohtml", no_argument, 0, 'n'},
222 {"nohtml", no_argument, 0, 'n'}, 216 {"ssl", optional_argument, 0, 'S'},
223 {"ssl", optional_argument, 0, 'S'}, 217 {"sni", no_argument, 0, SNI_OPTION},
224 {"sni", no_argument, 0, SNI_OPTION}, 218 {"post", required_argument, 0, 'P'},
225 {"post", required_argument, 0, 'P'}, 219 {"method", required_argument, 0, 'j'},
226 {"method", required_argument, 0, 'j'}, 220 {"IP-address", required_argument, 0, 'I'},
227 {"IP-address", required_argument, 0, 'I'}, 221 {"url", required_argument, 0, 'u'},
228 {"url", required_argument, 0, 'u'}, 222 {"port", required_argument, 0, 'p'},
229 {"port", required_argument, 0, 'p'}, 223 {"authorization", required_argument, 0, 'a'},
230 {"authorization", required_argument, 0, 'a'}, 224 {"proxy-authorization", required_argument, 0, 'b'},
231 {"proxy-authorization", required_argument, 0, 'b'}, 225 {"header-string", required_argument, 0, 'd'},
232 {"header-string", required_argument, 0, 'd'}, 226 {"string", required_argument, 0, 's'},
233 {"string", required_argument, 0, 's'}, 227 {"expect", required_argument, 0, 'e'},
234 {"expect", required_argument, 0, 'e'}, 228 {"regex", required_argument, 0, 'r'},
235 {"regex", required_argument, 0, 'r'}, 229 {"ereg", required_argument, 0, 'r'},
236 {"ereg", required_argument, 0, 'r'}, 230 {"eregi", required_argument, 0, 'R'},
237 {"eregi", required_argument, 0, 'R'}, 231 {"linespan", no_argument, 0, 'l'},
238 {"linespan", no_argument, 0, 'l'}, 232 {"onredirect", required_argument, 0, 'f'},
239 {"onredirect", required_argument, 0, 'f'}, 233 {"certificate", required_argument, 0, 'C'},
240 {"certificate", required_argument, 0, 'C'}, 234 {"client-cert", required_argument, 0, 'J'},
241 {"client-cert", required_argument, 0, 'J'}, 235 {"private-key", required_argument, 0, 'K'},
242 {"private-key", required_argument, 0, 'K'}, 236 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
243 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT}, 237 {"useragent", required_argument, 0, 'A'},
244 {"useragent", required_argument, 0, 'A'}, 238 {"header", required_argument, 0, 'k'},
245 {"header", required_argument, 0, 'k'}, 239 {"no-body", no_argument, 0, 'N'},
246 {"no-body", no_argument, 0, 'N'}, 240 {"max-age", required_argument, 0, 'M'},
247 {"max-age", required_argument, 0, 'M'}, 241 {"content-type", required_argument, 0, 'T'},
248 {"content-type", required_argument, 0, 'T'}, 242 {"pagesize", required_argument, 0, 'm'},
249 {"pagesize", required_argument, 0, 'm'}, 243 {"invert-regex", no_argument, NULL, INVERT_REGEX},
250 {"invert-regex", no_argument, NULL, INVERT_REGEX}, 244 {"state-regex", required_argument, 0, STATE_REGEX},
251 {"state-regex", required_argument, 0, STATE_REGEX}, 245 {"use-ipv4", no_argument, 0, '4'},
252 {"use-ipv4", no_argument, 0, '4'}, 246 {"use-ipv6", no_argument, 0, '6'},
253 {"use-ipv6", no_argument, 0, '6'}, 247 {"extended-perfdata", no_argument, 0, 'E'},
254 {"extended-perfdata", no_argument, 0, 'E'}, 248 {"show-body", no_argument, 0, 'B'},
255 {"show-body", no_argument, 0, 'B'}, 249 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
256 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION}, 250 {0, 0, 0, 0}};
257 {0, 0, 0, 0} 251
258 }; 252 if (argc < 2) {
259 253 return false;
260 if (argc < 2) 254 }
261 return false; 255
262 256 for (c = 1; c < argc; c++) {
263 for (c = 1; c < argc; c++) { 257 if (strcmp("-to", argv[c]) == 0) {
264 if (strcmp ("-to", argv[c]) == 0) 258 strcpy(argv[c], "-t");
265 strcpy (argv[c], "-t"); 259 }
266 if (strcmp ("-hn", argv[c]) == 0) 260 if (strcmp("-hn", argv[c]) == 0) {
267 strcpy (argv[c], "-H"); 261 strcpy(argv[c], "-H");
268 if (strcmp ("-wt", argv[c]) == 0) 262 }
269 strcpy (argv[c], "-w"); 263 if (strcmp("-wt", argv[c]) == 0) {
270 if (strcmp ("-ct", argv[c]) == 0) 264 strcpy(argv[c], "-w");
271 strcpy (argv[c], "-c"); 265 }
272 if (strcmp ("-nohtml", argv[c]) == 0) 266 if (strcmp("-ct", argv[c]) == 0) {
273 strcpy (argv[c], "-n"); 267 strcpy(argv[c], "-c");
274 } 268 }
275 269 if (strcmp("-nohtml", argv[c]) == 0) {
276 while (1) { 270 strcpy(argv[c], "-n");
277 c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:nlLS::m:M:NEB", longopts, &option); 271 }
278 if (c == -1 || c == EOF) 272 }
279 break; 273
280 274 while (1) {
281 switch (c) { 275 c = getopt_long(argc, argv,
282 case '?': /* usage */ 276 "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:nlLS::m:M:NEB",
283 usage5 (); 277 longopts, &option);
284 break; 278 if (c == -1 || c == EOF) {
285 case 'h': /* help */ 279 break;
286 print_help (); 280 }
287 exit (STATE_UNKNOWN); 281
288 break; 282 switch (c) {
289 case 'V': /* version */ 283 case '?': /* usage */
290 print_revision (progname, NP_VERSION); 284 usage5();
291 exit (STATE_UNKNOWN); 285 break;
292 break; 286 case 'h': /* help */
293 case 't': /* timeout period */ 287 print_help();
294 if (!is_intnonneg (optarg)) 288 exit(STATE_UNKNOWN);
295 usage2 (_("Timeout interval must be a positive integer"), optarg); 289 break;
296 else 290 case 'V': /* version */
297 socket_timeout = atoi (optarg); 291 print_revision(progname, NP_VERSION);
298 break; 292 exit(STATE_UNKNOWN);
299 case 'c': /* critical time threshold */ 293 break;
300 critical_thresholds = optarg; 294 case 't': /* timeout period */
301 break; 295 if (!is_intnonneg(optarg)) {
302 case 'w': /* warning time threshold */ 296 usage2(_("Timeout interval must be a positive integer"), optarg);
303 warning_thresholds = optarg; 297 } else {
304 break; 298 socket_timeout = atoi(optarg);
305 case 'A': /* User Agent String */ 299 }
306 xasprintf (&user_agent, "User-Agent: %s", optarg); 300 break;
307 break; 301 case 'c': /* critical time threshold */
308 case 'k': /* Additional headers */ 302 critical_thresholds = optarg;
309 if (http_opt_headers_count == 0) 303 break;
310 http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count)); 304 case 'w': /* warning time threshold */
311 else 305 warning_thresholds = optarg;
312 http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count)); 306 break;
313 http_opt_headers[http_opt_headers_count - 1] = optarg; 307 case 'A': /* User Agent String */
314 /* xasprintf (&http_opt_headers, "%s", optarg); */ 308 xasprintf(&user_agent, "User-Agent: %s", optarg);
315 break; 309 break;
316 case 'L': /* show html link */ 310 case 'k': /* Additional headers */
317 display_html = true; 311 if (http_opt_headers_count == 0) {
318 break; 312 http_opt_headers = malloc(sizeof(char *) * (++http_opt_headers_count));
319 case 'n': /* do not show html link */ 313 } else {
320 display_html = false; 314 http_opt_headers =
321 break; 315 realloc(http_opt_headers, sizeof(char *) * (++http_opt_headers_count));
322 case 'C': /* Check SSL cert validity */ 316 }
317 http_opt_headers[http_opt_headers_count - 1] = optarg;
318 /* xasprintf (&http_opt_headers, "%s", optarg); */
319 break;
320 case 'L': /* show html link */
321 display_html = true;
322 break;
323 case 'n': /* do not show html link */
324 display_html = false;
325 break;
326 case 'C': /* Check SSL cert validity */
323#ifdef HAVE_SSL 327#ifdef HAVE_SSL
324 if ((temp=strchr(optarg,','))!=NULL) { 328 if ((temp = strchr(optarg, ',')) != NULL) {
325 *temp='\0'; 329 *temp = '\0';
326 if (!is_intnonneg (optarg)) 330 if (!is_intnonneg(optarg)) {
327 usage2 (_("Invalid certificate expiration period"), optarg); 331 usage2(_("Invalid certificate expiration period"), optarg);
328 days_till_exp_warn = atoi(optarg); 332 }
329 *temp=','; 333 days_till_exp_warn = atoi(optarg);
330 temp++; 334 *temp = ',';
331 if (!is_intnonneg (temp)) 335 temp++;
332 usage2 (_("Invalid certificate expiration period"), temp); 336 if (!is_intnonneg(temp)) {
333 days_till_exp_crit = atoi (temp); 337 usage2(_("Invalid certificate expiration period"), temp);
334 } 338 }
335 else { 339 days_till_exp_crit = atoi(temp);
336 days_till_exp_crit=0; 340 } else {
337 if (!is_intnonneg (optarg)) 341 days_till_exp_crit = 0;
338 usage2 (_("Invalid certificate expiration period"), optarg); 342 if (!is_intnonneg(optarg)) {
339 days_till_exp_warn = atoi (optarg); 343 usage2(_("Invalid certificate expiration period"), optarg);
340 } 344 }
341 check_cert = true; 345 days_till_exp_warn = atoi(optarg);
342 goto enable_ssl; 346 }
347 check_cert = true;
348 goto enable_ssl;
343#endif 349#endif
344 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */ 350 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
345#ifdef HAVE_SSL 351#ifdef HAVE_SSL
346 continue_after_check_cert = true; 352 continue_after_check_cert = true;
347 break; 353 break;
348#endif 354#endif
349 case 'J': /* use client certificate */ 355 case 'J': /* use client certificate */
350#ifdef HAVE_SSL 356#ifdef HAVE_SSL
351 test_file(optarg); 357 test_file(optarg);
352 client_cert = optarg; 358 client_cert = optarg;
353 goto enable_ssl; 359 goto enable_ssl;
354#endif 360#endif
355 case 'K': /* use client private key */ 361 case 'K': /* use client private key */
356#ifdef HAVE_SSL 362#ifdef HAVE_SSL
357 test_file(optarg); 363 test_file(optarg);
358 client_privkey = optarg; 364 client_privkey = optarg;
359 goto enable_ssl; 365 goto enable_ssl;
360#endif 366#endif
361 case 'S': /* use SSL */ 367 case 'S': /* use SSL */
362#ifdef HAVE_SSL 368#ifdef HAVE_SSL
363 enable_ssl: 369 enable_ssl:
364 /* ssl_version initialized to 0 as a default. Only set if it's non-zero. This helps when we include multiple 370 /* ssl_version initialized to 0 as a default. Only set if it's non-zero. This helps
365 parameters, like -S and -C combinations */ 371 when we include multiple parameters, like -S and -C combinations */
366 use_ssl = true; 372 use_ssl = true;
367 if (c=='S' && optarg != NULL) { 373 if (c == 'S' && optarg != NULL) {
368 int got_plus = strchr(optarg, '+') != NULL; 374 int got_plus = strchr(optarg, '+') != NULL;
369 375
370 if (!strncmp (optarg, "1.2", 3)) 376 if (!strncmp(optarg, "1.2", 3)) {
371 ssl_version = got_plus ? MP_TLSv1_2_OR_NEWER : MP_TLSv1_2; 377 ssl_version = got_plus ? MP_TLSv1_2_OR_NEWER : MP_TLSv1_2;
372 else if (!strncmp (optarg, "1.1", 3)) 378 } else if (!strncmp(optarg, "1.1", 3)) {
373 ssl_version = got_plus ? MP_TLSv1_1_OR_NEWER : MP_TLSv1_1; 379 ssl_version = got_plus ? MP_TLSv1_1_OR_NEWER : MP_TLSv1_1;
374 else if (optarg[0] == '1') 380 } else if (optarg[0] == '1') {
375 ssl_version = got_plus ? MP_TLSv1_OR_NEWER : MP_TLSv1; 381 ssl_version = got_plus ? MP_TLSv1_OR_NEWER : MP_TLSv1;
376 else if (optarg[0] == '3') 382 } else if (optarg[0] == '3') {
377 ssl_version = got_plus ? MP_SSLv3_OR_NEWER : MP_SSLv3; 383 ssl_version = got_plus ? MP_SSLv3_OR_NEWER : MP_SSLv3;
378 else if (optarg[0] == '2') 384 } else if (optarg[0] == '2') {
379 ssl_version = got_plus ? MP_SSLv2_OR_NEWER : MP_SSLv2; 385 ssl_version = got_plus ? MP_SSLv2_OR_NEWER : MP_SSLv2;
380 else 386 } else {
381 usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with optional '+' suffix)")); 387 usage4(_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with "
382 } 388 "optional '+' suffix)"));
383 if (specify_port == false) 389 }
384 server_port = HTTPS_PORT; 390 }
391 if (!specify_port) {
392 server_port = HTTPS_PORT;
393 }
385#else 394#else
386 /* -C -J and -K fall through to here without SSL */ 395 /* -C -J and -K fall through to here without SSL */
387 usage4 (_("Invalid option - SSL is not available")); 396 usage4(_("Invalid option - SSL is not available"));
388#endif 397#endif
389 break; 398 break;
390 case SNI_OPTION: 399 case SNI_OPTION:
391 use_sni = true; 400 use_sni = true;
392 break; 401 break;
393 case MAX_REDIRS_OPTION: 402 case MAX_REDIRS_OPTION:
394 if (!is_intnonneg (optarg)) 403 if (!is_intnonneg(optarg)) {
395 usage2 (_("Invalid max_redirs count"), optarg); 404 usage2(_("Invalid max_redirs count"), optarg);
396 else { 405 } else {
397 max_depth = atoi (optarg); 406 max_depth = atoi(optarg);
398 } 407 }
399 break; 408 break;
400 case 'f': /* onredirect */ 409 case 'f': /* onredirect */
401 if (!strcmp (optarg, "stickyport")) 410 if (!strcmp(optarg, "stickyport")) {
402 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST|STICKY_PORT; 411 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST | STICKY_PORT;
403 else if (!strcmp (optarg, "sticky")) 412 } else if (!strcmp(optarg, "sticky")) {
404 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST; 413 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST;
405 else if (!strcmp (optarg, "follow")) 414 } else if (!strcmp(optarg, "follow")) {
406 onredirect = STATE_DEPENDENT, followsticky = STICKY_NONE; 415 onredirect = STATE_DEPENDENT, followsticky = STICKY_NONE;
407 else if (!strcmp (optarg, "unknown")) 416 } else if (!strcmp(optarg, "unknown")) {
408 onredirect = STATE_UNKNOWN; 417 onredirect = STATE_UNKNOWN;
409 else if (!strcmp (optarg, "ok")) 418 } else if (!strcmp(optarg, "ok")) {
410 onredirect = STATE_OK; 419 onredirect = STATE_OK;
411 else if (!strcmp (optarg, "warning")) 420 } else if (!strcmp(optarg, "warning")) {
412 onredirect = STATE_WARNING; 421 onredirect = STATE_WARNING;
413 else if (!strcmp (optarg, "critical")) 422 } else if (!strcmp(optarg, "critical")) {
414 onredirect = STATE_CRITICAL; 423 onredirect = STATE_CRITICAL;
415 else usage2 (_("Invalid onredirect option"), optarg); 424 } else {
416 if (verbose) 425 usage2(_("Invalid onredirect option"), optarg);
417 printf(_("option f:%d \n"), onredirect); 426 }
418 break; 427 if (verbose) {
419 /* Note: H, I, and u must be malloc'd or will fail on redirects */ 428 printf(_("option f:%d \n"), onredirect);
420 case 'H': /* Host Name (virtual host) */ 429 }
421 host_name = strdup (optarg); 430 break;
422 if (host_name[0] == '[') { 431 /* Note: H, I, and u must be malloc'd or will fail on redirects */
423 if ((p = strstr (host_name, "]:")) != NULL) { /* [IPv6]:port */ 432 case 'H': /* Host Name (virtual host) */
424 virtual_port = atoi (p + 2); 433 host_name = strdup(optarg);
425 /* cut off the port */ 434 if (host_name[0] == '[') {
426 host_name_length = strlen (host_name) - strlen (p) - 1; 435 if ((p = strstr(host_name, "]:")) != NULL) { /* [IPv6]:port */
427 free (host_name); 436 virtual_port = atoi(p + 2);
428 host_name = strndup (optarg, host_name_length); 437 /* cut off the port */
429 if (specify_port == false) 438 host_name_length = strlen(host_name) - strlen(p) - 1;
430 server_port = virtual_port; 439 free(host_name);
431 } 440 host_name = strndup(optarg, host_name_length);
432 } else if ((p = strchr (host_name, ':')) != NULL 441 if (!specify_port) {
433 && strchr (++p, ':') == NULL) { /* IPv4:port or host:port */ 442 server_port = virtual_port;
434 virtual_port = atoi (p); 443 }
435 /* cut off the port */ 444 }
436 host_name_length = strlen (host_name) - strlen (p) - 1; 445 } else if ((p = strchr(host_name, ':')) != NULL &&
437 free (host_name); 446 strchr(++p, ':') == NULL) { /* IPv4:port or host:port */
438 host_name = strndup (optarg, host_name_length); 447 virtual_port = atoi(p);
439 if (specify_port == false) 448 /* cut off the port */
440 server_port = virtual_port; 449 host_name_length = strlen(host_name) - strlen(p) - 1;
441 } 450 free(host_name);
442 break; 451 host_name = strndup(optarg, host_name_length);
443 case 'I': /* Server IP-address */ 452 if (!specify_port) {
444 server_address = strdup (optarg); 453 server_port = virtual_port;
445 break; 454 }
446 case 'u': /* URL path */ 455 }
447 server_url = strdup (optarg); 456 break;
448 server_url_length = strlen (server_url); 457 case 'I': /* Server IP-address */
449 break; 458 server_address = strdup(optarg);
450 case 'p': /* Server port */ 459 break;
451 if (!is_intnonneg (optarg)) 460 case 'u': /* URL path */
452 usage2 (_("Invalid port number"), optarg); 461 server_url = strdup(optarg);
453 else { 462 server_url_length = strlen(server_url);
454 server_port = atoi (optarg); 463 break;
455 specify_port = true; 464 case 'p': /* Server port */
456 } 465 if (!is_intnonneg(optarg)) {
457 break; 466 usage2(_("Invalid port number"), optarg);
458 case 'a': /* authorization info */ 467 } else {
459 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1); 468 server_port = atoi(optarg);
460 user_auth[MAX_INPUT_BUFFER - 1] = 0; 469 specify_port = true;
461 break; 470 }
462 case 'b': /* proxy-authorization info */ 471 break;
463 strncpy (proxy_auth, optarg, MAX_INPUT_BUFFER - 1); 472 case 'a': /* authorization info */
464 proxy_auth[MAX_INPUT_BUFFER - 1] = 0; 473 strncpy(user_auth, optarg, MAX_INPUT_BUFFER - 1);
465 break; 474 user_auth[MAX_INPUT_BUFFER - 1] = 0;
466 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */ 475 break;
467 if (! http_post_data) 476 case 'b': /* proxy-authorization info */
468 http_post_data = strdup (optarg); 477 strncpy(proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
469 if (! http_method) 478 proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
470 http_method = strdup("POST"); 479 break;
471 break; 480 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
472 case 'j': /* Set HTTP method */ 481 if (!http_post_data) {
473 if (http_method) 482 http_post_data = strdup(optarg);
474 free(http_method); 483 }
475 http_method = strdup (optarg); 484 if (!http_method) {
476 char *tmp; 485 http_method = strdup("POST");
477 if ((tmp = strstr(http_method, ":")) != NULL) { 486 }
478 tmp[0] = '\0'; // set the ":" in the middle to 0 487 break;
479 http_method_proxy = ++tmp; // this points to the second part 488 case 'j': /* Set HTTP method */
480 } 489 if (http_method) {
481 break; 490 free(http_method);
482 case 'd': /* string or substring */ 491 }
483 strncpy (header_expect, optarg, MAX_INPUT_BUFFER - 1); 492 http_method = strdup(optarg);
484 header_expect[MAX_INPUT_BUFFER - 1] = 0; 493 char *tmp;
485 break; 494 if ((tmp = strstr(http_method, ":")) != NULL) {
486 case 's': /* string or substring */ 495 tmp[0] = '\0'; // set the ":" in the middle to 0
487 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1); 496 http_method_proxy = ++tmp; // this points to the second part
488 string_expect[MAX_INPUT_BUFFER - 1] = 0; 497 }
489 break; 498 break;
490 case 'e': /* string or substring */ 499 case 'd': /* string or substring */
491 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1); 500 strncpy(header_expect, optarg, MAX_INPUT_BUFFER - 1);
492 server_expect[MAX_INPUT_BUFFER - 1] = 0; 501 header_expect[MAX_INPUT_BUFFER - 1] = 0;
493 server_expect_yn = 1; 502 break;
494 break; 503 case 's': /* string or substring */
495 case 'T': /* Content-type */ 504 strncpy(string_expect, optarg, MAX_INPUT_BUFFER - 1);
496 xasprintf (&http_content_type, "%s", optarg); 505 string_expect[MAX_INPUT_BUFFER - 1] = 0;
497 break; 506 break;
498 case 'l': /* linespan */ 507 case 'e': /* string or substring */
499 cflags &= ~REG_NEWLINE; 508 strncpy(server_expect, optarg, MAX_INPUT_BUFFER - 1);
500 break; 509 server_expect[MAX_INPUT_BUFFER - 1] = 0;
501 case 'R': /* regex */ 510 server_expect_yn = 1;
502 cflags |= REG_ICASE; 511 break;
512 case 'T': /* Content-type */
513 xasprintf(&http_content_type, "%s", optarg);
514 break;
515 case 'l': /* linespan */
516 cflags &= ~REG_NEWLINE;
517 break;
518 case 'R': /* regex */
519 cflags |= REG_ICASE;
503 // fall through 520 // fall through
504 case 'r': /* regex */ 521 case 'r': /* regex */
505 strncpy (regexp, optarg, MAX_RE_SIZE - 1); 522 strncpy(regexp, optarg, MAX_RE_SIZE - 1);
506 regexp[MAX_RE_SIZE - 1] = 0; 523 regexp[MAX_RE_SIZE - 1] = 0;
507 errcode = regcomp (&preg, regexp, cflags); 524 errcode = regcomp(&preg, regexp, cflags);
508 if (errcode != 0) { 525 if (errcode != 0) {
509 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 526 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
510 printf (_("Could Not Compile Regular Expression: %s"), errbuf); 527 printf(_("Could Not Compile Regular Expression: %s"), errbuf);
511 return false; 528 return false;
512 } 529 }
513 break; 530 break;
514 case INVERT_REGEX: 531 case INVERT_REGEX:
515 invert_regex = 1; 532 invert_regex = 1;
516 break; 533 break;
517 case STATE_REGEX: 534 case STATE_REGEX:
518 if (!strcmp (optarg, "critical")) 535 if (!strcmp(optarg, "critical")) {
519 state_regex = STATE_CRITICAL; 536 state_regex = STATE_CRITICAL;
520 else if (!strcmp (optarg, "warning")) 537 } else if (!strcmp(optarg, "warning")) {
521 state_regex = STATE_WARNING; 538 state_regex = STATE_WARNING;
522 else usage2 (_("Invalid state-regex option"), optarg); 539 } else {
523 break; 540 usage2(_("Invalid state-regex option"), optarg);
524 case '4': 541 }
525 address_family = AF_INET; 542 break;
526 break; 543 case '4':
527 case '6': 544 address_family = AF_INET;
545 break;
546 case '6':
528#ifdef USE_IPV6 547#ifdef USE_IPV6
529 address_family = AF_INET6; 548 address_family = AF_INET6;
530#else 549#else
531 usage4 (_("IPv6 support not available")); 550 usage4(_("IPv6 support not available"));
532#endif 551#endif
533 break; 552 break;
534 case 'v': /* verbose */ 553 case 'v': /* verbose */
535 verbose = true; 554 verbose = true;
536 break; 555 break;
537 case 'm': /* min_page_length */ 556 case 'm': /* min_page_length */
538 { 557 {
539 char *tmp; 558 char *tmp;
540 if (strchr(optarg, ':') != (char *)NULL) { 559 if (strchr(optarg, ':') != (char *)NULL) {
541 /* range, so get two values, min:max */ 560 /* range, so get two values, min:max */
542 tmp = strtok(optarg, ":"); 561 tmp = strtok(optarg, ":");
543 if (tmp == NULL) { 562 if (tmp == NULL) {
544 printf("Bad format: try \"-m min:max\"\n"); 563 printf("Bad format: try \"-m min:max\"\n");
545 exit (STATE_WARNING); 564 exit(STATE_WARNING);
546 } else 565 } else {
547 min_page_len = atoi(tmp); 566 min_page_len = atoi(tmp);
548 567 }
549 tmp = strtok(NULL, ":"); 568
550 if (tmp == NULL) { 569 tmp = strtok(NULL, ":");
551 printf("Bad format: try \"-m min:max\"\n"); 570 if (tmp == NULL) {
552 exit (STATE_WARNING); 571 printf("Bad format: try \"-m min:max\"\n");
553 } else 572 exit(STATE_WARNING);
554 max_page_len = atoi(tmp); 573 } else {
555 } else 574 max_page_len = atoi(tmp);
556 min_page_len = atoi (optarg); 575 }
557 break; 576 } else {
558 } 577 min_page_len = atoi(optarg);
559 case 'N': /* no-body */ 578 }
560 no_body = true; 579 break;
561 break; 580 }
562 case 'M': /* max-age */ 581 case 'N': /* no-body */
563 { 582 no_body = true;
564 int L = strlen(optarg); 583 break;
565 if (L && optarg[L-1] == 'm') 584 case 'M': /* max-age */
566 maximum_age = atoi (optarg) * 60; 585 {
567 else if (L && optarg[L-1] == 'h') 586 int L = strlen(optarg);
568 maximum_age = atoi (optarg) * 60 * 60; 587 if (L && optarg[L - 1] == 'm') {
569 else if (L && optarg[L-1] == 'd') 588 maximum_age = atoi(optarg) * 60;
570 maximum_age = atoi (optarg) * 60 * 60 * 24; 589 } else if (L && optarg[L - 1] == 'h') {
571 else if (L && (optarg[L-1] == 's' || 590 maximum_age = atoi(optarg) * 60 * 60;
572 isdigit (optarg[L-1]))) 591 } else if (L && optarg[L - 1] == 'd') {
573 maximum_age = atoi (optarg); 592 maximum_age = atoi(optarg) * 60 * 60 * 24;
574 else { 593 } else if (L && (optarg[L - 1] == 's' || isdigit(optarg[L - 1]))) {
575 fprintf (stderr, "unparsable max-age: %s\n", optarg); 594 maximum_age = atoi(optarg);
576 exit (STATE_WARNING); 595 } else {
577 } 596 fprintf(stderr, "unparsable max-age: %s\n", optarg);
578 } 597 exit(STATE_WARNING);
579 break; 598 }
580 case 'E': /* show extended perfdata */ 599 } break;
581 show_extended_perfdata = true; 600 case 'E': /* show extended perfdata */
582 break; 601 show_extended_perfdata = true;
583 case 'B': /* print body content after status line */ 602 break;
584 show_body = true; 603 case 'B': /* print body content after status line */
585 break; 604 show_body = true;
586 } 605 break;
587 } 606 }
588 607 }
589 c = optind; 608
590 609 c = optind;
591 if (server_address == NULL && c < argc) 610
592 server_address = strdup (argv[c++]); 611 if (server_address == NULL && c < argc) {
593 612 server_address = strdup(argv[c++]);
594 if (host_name == NULL && c < argc) 613 }
595 host_name = strdup (argv[c++]);
596
597 if (server_address == NULL) {
598 if (host_name == NULL)
599 usage4 (_("You must specify a server address or host name"));
600 else
601 server_address = strdup (host_name);
602 }
603
604 set_thresholds(&thlds, warning_thresholds, critical_thresholds);
605
606 if (critical_thresholds && thlds->critical->end>(double)socket_timeout)
607 socket_timeout = (int)thlds->critical->end + 1;
608
609 if (http_method == NULL)
610 http_method = strdup ("GET");
611
612 if (http_method_proxy == NULL)
613 http_method_proxy = strdup ("GET");
614
615 if (client_cert && !client_privkey)
616 usage4 (_("If you use a client certificate you must also specify a private key file"));
617
618 if (virtual_port == 0)
619 virtual_port = server_port;
620
621 return true;
622}
623 614
615 if (host_name == NULL && c < argc) {
616 host_name = strdup(argv[c++]);
617 }
618
619 if (server_address == NULL) {
620 if (host_name == NULL) {
621 usage4(_("You must specify a server address or host name"));
622 } else {
623 server_address = strdup(host_name);
624 }
625 }
624 626
627 set_thresholds(&thlds, warning_thresholds, critical_thresholds);
628
629 if (critical_thresholds && thlds->critical->end > (double)socket_timeout) {
630 socket_timeout = (int)thlds->critical->end + 1;
631 }
632
633 if (http_method == NULL) {
634 http_method = strdup("GET");
635 }
636
637 if (http_method_proxy == NULL) {
638 http_method_proxy = strdup("GET");
639 }
640
641 if (client_cert && !client_privkey) {
642 usage4(_("If you use a client certificate you must also specify a private key file"));
643 }
644
645 if (virtual_port == 0) {
646 virtual_port = server_port;
647 }
648
649 return true;
650}
625 651
626/* Returns 1 if we're done processing the document body; 0 to keep going */ 652/* Returns 1 if we're done processing the document body; 0 to keep going */
627static int 653static int document_headers_done(char *full_page) {
628document_headers_done (char *full_page) 654 const char *body;
629{
630 const char *body;
631 655
632 for (body = full_page; *body; body++) { 656 for (body = full_page; *body; body++) {
633 if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3)) 657 if (!strncmp(body, "\n\n", 2) || !strncmp(body, "\n\r\n", 3)) {
634 break; 658 break;
635 } 659 }
660 }
636 661
637 if (!*body) 662 if (!*body) {
638 return 0; /* haven't read end of headers yet */ 663 return 0; /* haven't read end of headers yet */
664 }
639 665
640 full_page[body - full_page] = 0; 666 full_page[body - full_page] = 0;
641 return 1; 667 return 1;
642} 668}
643 669
644static time_t 670static time_t parse_time_string(const char *string) {
645parse_time_string (const char *string) 671 struct tm tm;
646{ 672 time_t t;
647 struct tm tm; 673 memset(&tm, 0, sizeof(tm));
648 time_t t; 674
649 memset (&tm, 0, sizeof(tm)); 675 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
650 676
651 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */ 677 if (isupper(string[0]) && /* Tue */
652 678 islower(string[1]) && islower(string[2]) && ',' == string[3] && ' ' == string[4] &&
653 if (isupper (string[0]) && /* Tue */ 679 (isdigit(string[5]) || string[5] == ' ') && /* 25 */
654 islower (string[1]) && 680 isdigit(string[6]) && ' ' == string[7] && isupper(string[8]) && /* Dec */
655 islower (string[2]) && 681 islower(string[9]) && islower(string[10]) && ' ' == string[11] &&
656 ',' == string[3] && 682 isdigit(string[12]) && /* 2001 */
657 ' ' == string[4] && 683 isdigit(string[13]) && isdigit(string[14]) && isdigit(string[15]) && ' ' == string[16] &&
658 (isdigit(string[5]) || string[5] == ' ') && /* 25 */ 684 isdigit(string[17]) && /* 02: */
659 isdigit (string[6]) && 685 isdigit(string[18]) && ':' == string[19] && isdigit(string[20]) && /* 59: */
660 ' ' == string[7] && 686 isdigit(string[21]) && ':' == string[22] && isdigit(string[23]) && /* 03 */
661 isupper (string[8]) && /* Dec */ 687 isdigit(string[24]) && ' ' == string[25] && 'G' == string[26] && /* GMT */
662 islower (string[9]) && 688 'M' == string[27] && /* GMT */
663 islower (string[10]) && 689 'T' == string[28]) {
664 ' ' == string[11] && 690
665 isdigit (string[12]) && /* 2001 */ 691 tm.tm_sec = 10 * (string[23] - '0') + (string[24] - '0');
666 isdigit (string[13]) && 692 tm.tm_min = 10 * (string[20] - '0') + (string[21] - '0');
667 isdigit (string[14]) && 693 tm.tm_hour = 10 * (string[17] - '0') + (string[18] - '0');
668 isdigit (string[15]) && 694 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5] - '0') + (string[6] - '0');
669 ' ' == string[16] && 695 tm.tm_mon = (!strncmp(string + 8, "Jan", 3) ? 0
670 isdigit (string[17]) && /* 02: */ 696 : !strncmp(string + 8, "Feb", 3) ? 1
671 isdigit (string[18]) && 697 : !strncmp(string + 8, "Mar", 3) ? 2
672 ':' == string[19] && 698 : !strncmp(string + 8, "Apr", 3) ? 3
673 isdigit (string[20]) && /* 59: */ 699 : !strncmp(string + 8, "May", 3) ? 4
674 isdigit (string[21]) && 700 : !strncmp(string + 8, "Jun", 3) ? 5
675 ':' == string[22] && 701 : !strncmp(string + 8, "Jul", 3) ? 6
676 isdigit (string[23]) && /* 03 */ 702 : !strncmp(string + 8, "Aug", 3) ? 7
677 isdigit (string[24]) && 703 : !strncmp(string + 8, "Sep", 3) ? 8
678 ' ' == string[25] && 704 : !strncmp(string + 8, "Oct", 3) ? 9
679 'G' == string[26] && /* GMT */ 705 : !strncmp(string + 8, "Nov", 3) ? 10
680 'M' == string[27] && /* GMT */ 706 : !strncmp(string + 8, "Dec", 3) ? 11
681 'T' == string[28]) { 707 : -1);
682 708 tm.tm_year = ((1000 * (string[12] - '0') + 100 * (string[13] - '0') +
683 tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0'); 709 10 * (string[14] - '0') + (string[15] - '0')) -
684 tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0'); 710 1900);
685 tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0'); 711
686 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0'); 712 tm.tm_isdst = 0; /* GMT is never in DST, right? */
687 tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 : 713
688 !strncmp (string+8, "Feb", 3) ? 1 : 714 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31) {
689 !strncmp (string+8, "Mar", 3) ? 2 : 715 return 0;
690 !strncmp (string+8, "Apr", 3) ? 3 : 716 }
691 !strncmp (string+8, "May", 3) ? 4 : 717
692 !strncmp (string+8, "Jun", 3) ? 5 : 718 /*
693 !strncmp (string+8, "Jul", 3) ? 6 : 719 This is actually wrong: we need to subtract the local timezone
694 !strncmp (string+8, "Aug", 3) ? 7 : 720 offset from GMT from this value. But, that's ok in this usage,
695 !strncmp (string+8, "Sep", 3) ? 8 : 721 because we only comparing these two GMT dates against each other,
696 !strncmp (string+8, "Oct", 3) ? 9 : 722 so it doesn't matter what time zone we parse them in.
697 !strncmp (string+8, "Nov", 3) ? 10 : 723 */
698 !strncmp (string+8, "Dec", 3) ? 11 : 724
699 -1); 725 t = mktime(&tm);
700 tm.tm_year = ((1000 * (string[12]-'0') + 726 if (t == (time_t)-1) {
701 100 * (string[13]-'0') + 727 t = 0;
702 10 * (string[14]-'0') + 728 }
703 (string[15]-'0')) 729
704 - 1900); 730 if (verbose) {
705 731 const char *s = string;
706 tm.tm_isdst = 0; /* GMT is never in DST, right? */ 732 while (*s && *s != '\r' && *s != '\n') {
707 733 fputc(*s++, stdout);
708 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31) 734 }
709 return 0; 735 printf(" ==> %lu\n", (unsigned long)t);
710 736 }
711 /* 737
712 This is actually wrong: we need to subtract the local timezone 738 return t;
713 offset from GMT from this value. But, that's ok in this usage, 739 }
714 because we only comparing these two GMT dates against each other, 740 return 0;
715 so it doesn't matter what time zone we parse them in.
716 */
717
718 t = mktime (&tm);
719 if (t == (time_t) -1) t = 0;
720
721 if (verbose) {
722 const char *s = string;
723 while (*s && *s != '\r' && *s != '\n')
724 fputc (*s++, stdout);
725 printf (" ==> %lu\n", (unsigned long) t);
726 }
727
728 return t;
729
730 } else {
731 return 0;
732 }
733} 741}
734 742
735/* Checks if the server 'reply' is one of the expected 'statuscodes' */ 743/* Checks if the server 'reply' is one of the expected 'statuscodes' */
736static int 744static int expected_statuscode(const char *reply, const char *statuscodes) {
737expected_statuscode (const char *reply, const char *statuscodes) 745 char *expected;
738{ 746 char *code;
739 char *expected, *code; 747 int result = 0;
740 int result = 0; 748
741 749 if ((expected = strdup(statuscodes)) == NULL) {
742 if ((expected = strdup (statuscodes)) == NULL) 750 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
743 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); 751 }
744 752
745 for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ",")) 753 for (code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) {
746 if (strstr (reply, code) != NULL) { 754 if (strstr(reply, code) != NULL) {
747 result = 1; 755 result = 1;
748 break; 756 break;
749 } 757 }
750 758 }
751 free (expected); 759
752 return result; 760 free(expected);
761 return result;
753} 762}
754 763
755static int 764static int check_document_dates(const char *headers, char **msg) {
756check_document_dates (const char *headers, char **msg) 765 const char *s;
757{ 766 char *server_date = 0;
758 const char *s; 767 char *document_date = 0;
759 char *server_date = 0; 768 int date_result = STATE_OK;
760 char *document_date = 0; 769
761 int date_result = STATE_OK; 770 s = headers;
762 771 while (*s) {
763 s = headers; 772 const char *field = s;
764 while (*s) { 773 const char *value = 0;
765 const char *field = s; 774
766 const char *value = 0; 775 /* Find the end of the header field */
767 776 while (*s && !isspace(*s) && *s != ':') {
768 /* Find the end of the header field */ 777 s++;
769 while (*s && !isspace(*s) && *s != ':') 778 }
770 s++; 779
771 780 /* Remember the header value, if any. */
772 /* Remember the header value, if any. */ 781 if (*s == ':') {
773 if (*s == ':') 782 value = ++s;
774 value = ++s; 783 }
775 784
776 /* Skip to the end of the header, including continuation lines. */ 785 /* Skip to the end of the header, including continuation lines. */
777 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t'))) 786 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t'))) {
778 s++; 787 s++;
779 788 }
780 /* Avoid stepping over end-of-string marker */ 789
781 if (*s) 790 /* Avoid stepping over end-of-string marker */
782 s++; 791 if (*s) {
783 792 s++;
784 /* Process this header. */ 793 }
785 if (value && value > field+2) { 794
786 char *ff = (char *) malloc (value-field); 795 /* Process this header. */
787 char *ss = ff; 796 if (value && value > field + 2) {
788 while (field < value-1) 797 char *ff = (char *)malloc(value - field);
789 *ss++ = tolower(*field++); 798 char *ss = ff;
790 *ss++ = 0; 799 while (field < value - 1) {
791 800 *ss++ = tolower(*field++);
792 if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) { 801 }
793 const char *e; 802 *ss++ = 0;
794 while (*value && isspace (*value)) 803
795 value++; 804 if (!strcmp(ff, "date") || !strcmp(ff, "last-modified")) {
796 for (e = value; *e && *e != '\r' && *e != '\n'; e++) 805 const char *e;
797 ; 806 while (*value && isspace(*value)) {
798 ss = (char *) malloc (e - value + 1); 807 value++;
799 strncpy (ss, value, e - value); 808 }
800 ss[e - value] = 0; 809 for (e = value; *e && *e != '\r' && *e != '\n'; e++) {
801 if (!strcmp (ff, "date")) { 810 ;
802 if (server_date) free (server_date); 811 }
803 server_date = ss; 812 ss = (char *)malloc(e - value + 1);
804 } else { 813 strncpy(ss, value, e - value);
805 if (document_date) free (document_date); 814 ss[e - value] = 0;
806 document_date = ss; 815 if (!strcmp(ff, "date")) {
807 } 816 if (server_date) {
808 } 817 free(server_date);
809 free (ff); 818 }
810 } 819 server_date = ss;
811 } 820 } else {
812 821 if (document_date) {
813 /* Done parsing the body. Now check the dates we (hopefully) parsed. */ 822 free(document_date);
814 if (!server_date || !*server_date) { 823 }
815 xasprintf (msg, _("%sServer date unknown, "), *msg); 824 document_date = ss;
816 date_result = max_state_alt(STATE_UNKNOWN, date_result); 825 }
817 } else if (!document_date || !*document_date) { 826 }
818 xasprintf (msg, _("%sDocument modification date unknown, "), *msg); 827 free(ff);
819 date_result = max_state_alt(STATE_CRITICAL, date_result); 828 }
820 } else { 829 }
821 time_t srv_data = parse_time_string (server_date); 830
822 time_t doc_data = parse_time_string (document_date); 831 /* Done parsing the body. Now check the dates we (hopefully) parsed. */
823 832 if (!server_date || !*server_date) {
824 if (srv_data <= 0) { 833 xasprintf(msg, _("%sServer date unknown, "), *msg);
825 xasprintf (msg, _("%sServer date \"%100s\" unparsable, "), *msg, server_date); 834 date_result = max_state_alt(STATE_UNKNOWN, date_result);
826 date_result = max_state_alt(STATE_CRITICAL, date_result); 835 } else if (!document_date || !*document_date) {
827 } else if (doc_data <= 0) { 836 xasprintf(msg, _("%sDocument modification date unknown, "), *msg);
828 xasprintf (msg, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date); 837 date_result = max_state_alt(STATE_CRITICAL, date_result);
829 date_result = max_state_alt(STATE_CRITICAL, date_result); 838 } else {
830 } else if (doc_data > srv_data + 30) { 839 time_t srv_data = parse_time_string(server_date);
831 xasprintf (msg, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data); 840 time_t doc_data = parse_time_string(document_date);
832 date_result = max_state_alt(STATE_CRITICAL, date_result); 841
833 } else if (doc_data < srv_data - maximum_age) { 842 if (srv_data <= 0) {
834 int n = (srv_data - doc_data); 843 xasprintf(msg, _("%sServer date \"%100s\" unparsable, "), *msg, server_date);
835 if (n > (60 * 60 * 24 * 2)) { 844 date_result = max_state_alt(STATE_CRITICAL, date_result);
836 xasprintf (msg, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24)); 845 } else if (doc_data <= 0) {
837 date_result = max_state_alt(STATE_CRITICAL, date_result); 846 xasprintf(msg, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date);
838 } else { 847 date_result = max_state_alt(STATE_CRITICAL, date_result);
839 xasprintf (msg, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60); 848 } else if (doc_data > srv_data + 30) {
840 date_result = max_state_alt(STATE_CRITICAL, date_result); 849 xasprintf(msg, _("%sDocument is %d seconds in the future, "), *msg,
841 } 850 (int)doc_data - (int)srv_data);
842 } 851 date_result = max_state_alt(STATE_CRITICAL, date_result);
843 free (server_date); 852 } else if (doc_data < srv_data - maximum_age) {
844 free (document_date); 853 int n = (srv_data - doc_data);
845 } 854 if (n > (60 * 60 * 24 * 2)) {
846 return date_result; 855 xasprintf(msg, _("%sLast modified %.1f days ago, "), *msg,
856 ((float)n) / (60 * 60 * 24));
857 date_result = max_state_alt(STATE_CRITICAL, date_result);
858 } else {
859 xasprintf(msg, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60),
860 (n / 60) % 60, n % 60);
861 date_result = max_state_alt(STATE_CRITICAL, date_result);
862 }
863 }
864 free(server_date);
865 free(document_date);
866 }
867 return date_result;
847} 868}
848 869
849int 870int get_content_length(const char *headers) {
850get_content_length (const char *headers) 871 const char *s;
851{ 872 int content_length = 0;
852 const char *s; 873
853 int content_length = 0; 874 s = headers;
854 875 while (*s) {
855 s = headers; 876 const char *field = s;
856 while (*s) { 877 const char *value = 0;
857 const char *field = s; 878
858 const char *value = 0; 879 /* Find the end of the header field */
859 880 while (*s && !isspace(*s) && *s != ':') {
860 /* Find the end of the header field */ 881 s++;
861 while (*s && !isspace(*s) && *s != ':') 882 }
862 s++; 883
863 884 /* Remember the header value, if any. */
864 /* Remember the header value, if any. */ 885 if (*s == ':') {
865 if (*s == ':') 886 value = ++s;
866 value = ++s; 887 }
867 888
868 /* Skip to the end of the header, including continuation lines. */ 889 /* Skip to the end of the header, including continuation lines. */
869 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t'))) 890 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t'))) {
870 s++; 891 s++;
871 892 }
872 /* Avoid stepping over end-of-string marker */ 893
873 if (*s) 894 /* Avoid stepping over end-of-string marker */
874 s++; 895 if (*s) {
875 896 s++;
876 /* Process this header. */ 897 }
877 if (value && value > field+2) { 898
878 char *ff = (char *) malloc (value-field); 899 /* Process this header. */
879 char *ss = ff; 900 if (value && value > field + 2) {
880 while (field < value-1) 901 char *ff = (char *)malloc(value - field);
881 *ss++ = tolower(*field++); 902 char *ss = ff;
882 *ss++ = 0; 903 while (field < value - 1) {
883 904 *ss++ = tolower(*field++);
884 if (!strcmp (ff, "content-length")) { 905 }
885 const char *e; 906 *ss++ = 0;
886 while (*value && isspace (*value)) 907
887 value++; 908 if (!strcmp(ff, "content-length")) {
888 for (e = value; *e && *e != '\r' && *e != '\n'; e++) 909 const char *e;
889 ; 910 while (*value && isspace(*value)) {
890 ss = (char *) malloc (e - value + 1); 911 value++;
891 strncpy (ss, value, e - value); 912 }
892 ss[e - value] = 0; 913 for (e = value; *e && *e != '\r' && *e != '\n'; e++) {
893 content_length = atoi(ss); 914 ;
894 free (ss); 915 }
895 } 916 ss = (char *)malloc(e - value + 1);
896 free (ff); 917 strncpy(ss, value, e - value);
897 } 918 ss[e - value] = 0;
898 } 919 content_length = atoi(ss);
899 return (content_length); 920 free(ss);
921 }
922 free(ff);
923 }
924 }
925 return (content_length);
900} 926}
901 927
902char * 928char *prepend_slash(char *path) {
903prepend_slash (char *path) 929 char *newpath;
904{
905 char *newpath;
906 930
907 if (path[0] == '/') 931 if (path[0] == '/') {
908 return path; 932 return path;
933 }
909 934
910 if ((newpath = malloc (strlen(path) + 2)) == NULL) 935 if ((newpath = malloc(strlen(path) + 2)) == NULL) {
911 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); 936 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
912 newpath[0] = '/'; 937 }
913 strcpy (newpath + 1, path); 938 newpath[0] = '/';
914 free (path); 939 strcpy(newpath + 1, path);
915 return newpath; 940 free(path);
941 return newpath;
916} 942}
917 943
918int 944int check_http(void) {
919check_http (void) 945 char *msg;
920{ 946 char *status_line;
921 char *msg; 947 char *status_code;
922 char *status_line; 948 char *header;
923 char *status_code; 949 char *page;
924 char *header; 950 char *auth;
925 char *page; 951 int http_status;
926 char *auth; 952 int i = 0;
927 int http_status; 953 size_t pagesize = 0;
928 int i = 0; 954 char *full_page;
929 size_t pagesize = 0; 955 char *full_page_new;
930 char *full_page; 956 char *buf;
931 char *full_page_new; 957 char *pos;
932 char *buf; 958 long microsec = 0L;
933 char *pos; 959 double elapsed_time = 0.0;
934 long microsec = 0L; 960 long microsec_connect = 0L;
935 double elapsed_time = 0.0; 961 double elapsed_time_connect = 0.0;
936 long microsec_connect = 0L; 962 long microsec_ssl = 0L;
937 double elapsed_time_connect = 0.0; 963 double elapsed_time_ssl = 0.0;
938 long microsec_ssl = 0L; 964 long microsec_firstbyte = 0L;
939 double elapsed_time_ssl = 0.0; 965 double elapsed_time_firstbyte = 0.0;
940 long microsec_firstbyte = 0L; 966 long microsec_headers = 0L;
941 double elapsed_time_firstbyte = 0.0; 967 double elapsed_time_headers = 0.0;
942 long microsec_headers = 0L; 968 long microsec_transfer = 0L;
943 double elapsed_time_headers = 0.0; 969 double elapsed_time_transfer = 0.0;
944 long microsec_transfer = 0L; 970 int page_len = 0;
945 double elapsed_time_transfer = 0.0; 971 int result = STATE_OK;
946 int page_len = 0; 972 char *force_host_header = NULL;
947 int result = STATE_OK; 973
948 char *force_host_header = NULL; 974 /* try to connect to the host at the given port number */
949 975 gettimeofday(&tv_temp, NULL);
950 /* try to connect to the host at the given port number */ 976 if (my_tcp_connect(server_address, server_port, &sd) != STATE_OK) {
951 gettimeofday (&tv_temp, NULL); 977 die(STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
952 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK) 978 }
953 die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n")); 979 microsec_connect = deltime(tv_temp);
954 microsec_connect = deltime (tv_temp); 980
955 981 /* if we are called with the -I option, the -j method is CONNECT and */
956 /* if we are called with the -I option, the -j method is CONNECT and */ 982 /* we received -S for SSL, then we tunnel the request through a proxy*/
957 /* we received -S for SSL, then we tunnel the request through a proxy*/ 983 /* @20100414, public[at]frank4dd.com, http://www.frank4dd.com/howto */
958 /* @20100414, public[at]frank4dd.com, http://www.frank4dd.com/howto */ 984
959 985 if (server_address != NULL && strcmp(http_method, "CONNECT") == 0 && host_name != NULL &&
960 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0 986 use_ssl) {
961 && host_name != NULL && use_ssl == true) { 987
962 988 if (verbose) {
963 if (verbose) printf ("Entering CONNECT tunnel mode with proxy %s:%d to dst %s:%d\n", server_address, server_port, host_name, HTTPS_PORT); 989 printf("Entering CONNECT tunnel mode with proxy %s:%d to dst %s:%d\n", server_address,
964 asprintf (&buf, "%s %s:%d HTTP/1.1\r\n%s\r\n", http_method, host_name, HTTPS_PORT, user_agent); 990 server_port, host_name, HTTPS_PORT);
965 if (strlen(proxy_auth)) { 991 }
966 base64_encode_alloc (proxy_auth, strlen (proxy_auth), &auth); 992 asprintf(&buf, "%s %s:%d HTTP/1.1\r\n%s\r\n", http_method, host_name, HTTPS_PORT,
967 xasprintf (&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth); 993 user_agent);
968 } 994 if (strlen(proxy_auth)) {
969 /* optionally send any other header tag */ 995 base64_encode_alloc(proxy_auth, strlen(proxy_auth), &auth);
970 if (http_opt_headers_count) { 996 xasprintf(&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth);
971 for (i = 0; i < http_opt_headers_count ; i++) { 997 }
972 if (force_host_header != http_opt_headers[i]) { 998 /* optionally send any other header tag */
973 xasprintf (&buf, "%s%s\r\n", buf, http_opt_headers[i]); 999 if (http_opt_headers_count) {
974 } 1000 for (i = 0; i < http_opt_headers_count; i++) {
975 } 1001 if (force_host_header != http_opt_headers[i]) {
976 /* This cannot be free'd here because a redirection will then try to access this and segfault */ 1002 xasprintf(&buf, "%s%s\r\n", buf, http_opt_headers[i]);
977 /* Covered in a testcase in tests/check_http.t */ 1003 }
978 /* free(http_opt_headers); */ 1004 }
979 } 1005 /* This cannot be free'd here because a redirection will then try to access this and
980 asprintf (&buf, "%sProxy-Connection: keep-alive\r\n", buf); 1006 * segfault */
981 asprintf (&buf, "%sHost: %s\r\n", buf, host_name); 1007 /* Covered in a testcase in tests/check_http.t */
982 /* we finished our request, send empty line with CRLF */ 1008 /* free(http_opt_headers); */
983 asprintf (&buf, "%s%s", buf, CRLF); 1009 }
984 if (verbose) printf ("%s\n", buf); 1010 asprintf(&buf, "%sProxy-Connection: keep-alive\r\n", buf);
985 send(sd, buf, strlen (buf), 0); 1011 asprintf(&buf, "%sHost: %s\r\n", buf, host_name);
986 buf[0]='\0'; 1012 /* we finished our request, send empty line with CRLF */
987 1013 asprintf(&buf, "%s%s", buf, CRLF);
988 if (verbose) printf ("Receive response from proxy\n"); 1014 if (verbose) {
989 read (sd, buffer, MAX_INPUT_BUFFER-1); 1015 printf("%s\n", buf);
990 if (verbose) printf ("%s", buffer); 1016 }
991 /* Here we should check if we got HTTP/1.1 200 Connection established */ 1017 send(sd, buf, strlen(buf), 0);
992 } 1018 buf[0] = '\0';
1019
1020 if (verbose) {
1021 printf("Receive response from proxy\n");
1022 }
1023 read(sd, buffer, MAX_INPUT_BUFFER - 1);
1024 if (verbose) {
1025 printf("%s", buffer);
1026 }
1027 /* Here we should check if we got HTTP/1.1 200 Connection established */
1028 }
993#ifdef HAVE_SSL 1029#ifdef HAVE_SSL
994 elapsed_time_connect = (double)microsec_connect / 1.0e6; 1030 elapsed_time_connect = (double)microsec_connect / 1.0e6;
995 if (use_ssl == true) { 1031 if (use_ssl) {
996 gettimeofday (&tv_temp, NULL); 1032 gettimeofday(&tv_temp, NULL);
997 result = np_net_ssl_init_with_hostname_version_and_cert(sd, (use_sni ? host_name : NULL), ssl_version, client_cert, client_privkey); 1033 result = np_net_ssl_init_with_hostname_version_and_cert(
998 if (verbose) printf ("SSL initialized\n"); 1034 sd, (use_sni ? host_name : NULL), ssl_version, client_cert, client_privkey);
999 if (result != STATE_OK) 1035 if (verbose) {
1000 die (STATE_CRITICAL, NULL); 1036 printf("SSL initialized\n");
1001 microsec_ssl = deltime (tv_temp); 1037 }
1002 elapsed_time_ssl = (double)microsec_ssl / 1.0e6; 1038 if (result != STATE_OK) {
1003 if (check_cert == true) { 1039 die(STATE_CRITICAL, _("HTTP CRITICAL - SSL error\n"));
1004 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 1040 }
1005 if (continue_after_check_cert == false) { 1041 microsec_ssl = deltime(tv_temp);
1006 if (sd) close(sd); 1042 elapsed_time_ssl = (double)microsec_ssl / 1.0e6;
1007 np_net_ssl_cleanup(); 1043 if (check_cert) {
1008 return result; 1044 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit);
1009 } 1045 if (!continue_after_check_cert) {
1010 } 1046 if (sd) {
1011 } 1047 close(sd);
1048 }
1049 np_net_ssl_cleanup();
1050 return result;
1051 }
1052 }
1053 }
1012#endif /* HAVE_SSL */ 1054#endif /* HAVE_SSL */
1013 1055
1014 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0 1056 if (server_address != NULL && strcmp(http_method, "CONNECT") == 0 && host_name != NULL &&
1015 && host_name != NULL && use_ssl == true) 1057 use_ssl) {
1016 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method_proxy, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent); 1058 asprintf(&buf, "%s %s %s\r\n%s\r\n", http_method_proxy, server_url,
1017 else 1059 host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
1018 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent); 1060 } else {
1019 1061 asprintf(&buf, "%s %s %s\r\n%s\r\n", http_method, server_url,
1020 /* tell HTTP/1.1 servers not to keep the connection alive */ 1062 host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
1021 xasprintf (&buf, "%sConnection: close\r\n", buf); 1063 }
1022 1064
1023 /* check if Host header is explicitly set in options */ 1065 /* tell HTTP/1.1 servers not to keep the connection alive */
1024 if (http_opt_headers_count) { 1066 xasprintf(&buf, "%sConnection: close\r\n", buf);
1025 for (i = 0; i < http_opt_headers_count ; i++) { 1067
1026 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) { 1068 /* check if Host header is explicitly set in options */
1027 force_host_header = http_opt_headers[i]; 1069 if (http_opt_headers_count) {
1028 } 1070 for (i = 0; i < http_opt_headers_count; i++) {
1029 } 1071 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) {
1030 } 1072 force_host_header = http_opt_headers[i];
1031 1073 }
1032 /* optionally send the host header info */ 1074 }
1033 if (host_name) { 1075 }
1034 if (force_host_header) { 1076
1035 xasprintf (&buf, "%s%s\r\n", buf, force_host_header); 1077 /* optionally send the host header info */
1036 } 1078 if (host_name) {
1037 else { 1079 if (force_host_header) {
1038 /* 1080 xasprintf(&buf, "%s%s\r\n", buf, force_host_header);
1039 * Specify the port only if we're using a non-default port (see RFC 2616, 1081 } else {
1040 * 14.23). Some server applications/configurations cause trouble if the 1082 /*
1041 * (default) port is explicitly specified in the "Host:" header line. 1083 * Specify the port only if we're using a non-default port (see RFC 2616,
1042 */ 1084 * 14.23). Some server applications/configurations cause trouble if the
1043 if ((use_ssl == false && virtual_port == HTTP_PORT) || 1085 * (default) port is explicitly specified in the "Host:" header line.
1044 (use_ssl == true && virtual_port == HTTPS_PORT) || 1086 */
1045 (server_address != NULL && strcmp(http_method, "CONNECT") == 0 1087 if ((!use_ssl && virtual_port == HTTP_PORT) ||
1046 && host_name != NULL && use_ssl == true)) 1088 (use_ssl && virtual_port == HTTPS_PORT) ||
1047 xasprintf (&buf, "%sHost: %s\r\n", buf, host_name); 1089 (server_address != NULL && strcmp(http_method, "CONNECT") == 0 &&
1048 else 1090 host_name != NULL && use_ssl)) {
1049 xasprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, virtual_port); 1091 xasprintf(&buf, "%sHost: %s\r\n", buf, host_name);
1050 } 1092 } else {
1051 } 1093 xasprintf(&buf, "%sHost: %s:%d\r\n", buf, host_name, virtual_port);
1052 1094 }
1053 /* optionally send any other header tag */ 1095 }
1054 if (http_opt_headers_count) { 1096 }
1055 for (i = 0; i < http_opt_headers_count ; i++) { 1097
1056 if (force_host_header != http_opt_headers[i]) { 1098 /* optionally send any other header tag */
1057 xasprintf (&buf, "%s%s\r\n", buf, http_opt_headers[i]); 1099 if (http_opt_headers_count) {
1058 } 1100 for (i = 0; i < http_opt_headers_count; i++) {
1059 } 1101 if (force_host_header != http_opt_headers[i]) {
1060 /* This cannot be free'd here because a redirection will then try to access this and segfault */ 1102 xasprintf(&buf, "%s%s\r\n", buf, http_opt_headers[i]);
1061 /* Covered in a testcase in tests/check_http.t */ 1103 }
1062 /* free(http_opt_headers); */ 1104 }
1063 } 1105 /* This cannot be free'd here because a redirection will then try to access this and
1064 1106 * segfault */
1065 /* optionally send the authentication info */ 1107 /* Covered in a testcase in tests/check_http.t */
1066 if (strlen(user_auth)) { 1108 /* free(http_opt_headers); */
1067 base64_encode_alloc (user_auth, strlen (user_auth), &auth); 1109 }
1068 xasprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth); 1110
1069 } 1111 /* optionally send the authentication info */
1070 1112 if (strlen(user_auth)) {
1071 /* optionally send the proxy authentication info */ 1113 base64_encode_alloc(user_auth, strlen(user_auth), &auth);
1072 if (strlen(proxy_auth)) { 1114 xasprintf(&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
1073 base64_encode_alloc (proxy_auth, strlen (proxy_auth), &auth); 1115 }
1074 xasprintf (&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth); 1116
1075 } 1117 /* optionally send the proxy authentication info */
1076 1118 if (strlen(proxy_auth)) {
1077 /* either send http POST data (any data, not only POST)*/ 1119 base64_encode_alloc(proxy_auth, strlen(proxy_auth), &auth);
1078 if (http_post_data) { 1120 xasprintf(&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth);
1079 if (http_content_type) { 1121 }
1080 xasprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type); 1122
1081 } else { 1123 /* either send http POST data (any data, not only POST)*/
1082 xasprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf); 1124 if (http_post_data) {
1083 } 1125 if (http_content_type) {
1084 1126 xasprintf(&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
1085 xasprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data)); 1127 } else {
1086 xasprintf (&buf, "%s%s", buf, http_post_data); 1128 xasprintf(&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
1087 } else { 1129 }
1088 /* or just a newline so the server knows we're done with the request */ 1130
1089 xasprintf (&buf, "%s%s", buf, CRLF); 1131 xasprintf(&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen(http_post_data));
1090 } 1132 xasprintf(&buf, "%s%s", buf, http_post_data);
1091 1133 } else {
1092 if (verbose) printf ("%s\n", buf); 1134 /* or just a newline so the server knows we're done with the request */
1093 gettimeofday (&tv_temp, NULL); 1135 xasprintf(&buf, "%s%s", buf, CRLF);
1094 my_send (buf, strlen (buf)); 1136 }
1095 microsec_headers = deltime (tv_temp); 1137
1096 elapsed_time_headers = (double)microsec_headers / 1.0e6; 1138 if (verbose) {
1097 1139 printf("%s\n", buf);
1098 /* fetch the page */ 1140 }
1099 full_page = strdup(""); 1141 gettimeofday(&tv_temp, NULL);
1100 gettimeofday (&tv_temp, NULL); 1142 my_send(buf, strlen(buf));
1101 while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) { 1143 microsec_headers = deltime(tv_temp);
1102 if ((i >= 1) && (elapsed_time_firstbyte <= 0.000001)) { 1144 elapsed_time_headers = (double)microsec_headers / 1.0e6;
1103 microsec_firstbyte = deltime (tv_temp); 1145
1104 elapsed_time_firstbyte = (double)microsec_firstbyte / 1.0e6; 1146 /* fetch the page */
1105 } 1147 full_page = strdup("");
1106 while ((pos = memchr(buffer, '\0', i))) { 1148 gettimeofday(&tv_temp, NULL);
1107 /* replace nul character with a blank */ 1149 while ((i = my_recv(buffer, MAX_INPUT_BUFFER - 1)) > 0) {
1108 *pos = ' '; 1150 if ((i >= 1) && (elapsed_time_firstbyte <= 0.000001)) {
1109 } 1151 microsec_firstbyte = deltime(tv_temp);
1110 buffer[i] = '\0'; 1152 elapsed_time_firstbyte = (double)microsec_firstbyte / 1.0e6;
1111 1153 }
1112 if ((full_page_new = realloc(full_page, pagesize + i + 1)) == NULL) 1154 while ((pos = memchr(buffer, '\0', i))) {
1113 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate memory for full_page\n")); 1155 /* replace nul character with a blank */
1114 1156 *pos = ' ';
1115 memmove(&full_page_new[pagesize], buffer, i + 1); 1157 }
1116 1158 buffer[i] = '\0';
1117 full_page = full_page_new; 1159
1118 1160 if ((full_page_new = realloc(full_page, pagesize + i + 1)) == NULL) {
1119 pagesize += i; 1161 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate memory for full_page\n"));
1120 1162 }
1121 if (no_body && document_headers_done (full_page)) { 1163
1122 i = 0; 1164 memmove(&full_page_new[pagesize], buffer, i + 1);
1123 break; 1165
1124 } 1166 full_page = full_page_new;
1125 } 1167
1126 microsec_transfer = deltime (tv_temp); 1168 pagesize += i;
1127 elapsed_time_transfer = (double)microsec_transfer / 1.0e6; 1169
1128 1170 if (no_body && document_headers_done(full_page)) {
1129 if (i < 0 && errno != ECONNRESET) { 1171 i = 0;
1130 die(STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n")); 1172 break;
1131 } 1173 }
1132 1174 }
1133 /* return a CRITICAL status if we couldn't read any data */ 1175 microsec_transfer = deltime(tv_temp);
1134 if (pagesize == (size_t) 0) 1176 elapsed_time_transfer = (double)microsec_transfer / 1.0e6;
1135 die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n")); 1177
1136 1178 if (i < 0 && errno != ECONNRESET) {
1137 /* close the connection */ 1179 die(STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
1138 if (sd) close(sd); 1180 }
1181
1182 /* return a CRITICAL status if we couldn't read any data */
1183 if (pagesize == (size_t)0) {
1184 die(STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
1185 }
1186
1187 /* close the connection */
1188 if (sd) {
1189 close(sd);
1190 }
1139#ifdef HAVE_SSL 1191#ifdef HAVE_SSL
1140 np_net_ssl_cleanup(); 1192 np_net_ssl_cleanup();
1141#endif 1193#endif
1142 1194
1143 /* Save check time */ 1195 /* Save check time */
1144 microsec = deltime (tv); 1196 microsec = deltime(tv);
1145 elapsed_time = (double)microsec / 1.0e6; 1197 elapsed_time = (double)microsec / 1.0e6;
1146 1198
1147 /* leave full_page untouched so we can free it later */ 1199 /* leave full_page untouched so we can free it later */
1148 page = full_page; 1200 page = full_page;
1149 1201
1150 if (verbose) 1202 if (verbose) {
1151 printf ("%s://%s:%d%s is %d characters\n", 1203 printf("%s://%s:%d%s is %d characters\n", use_ssl ? "https" : "http", server_address,
1152 use_ssl ? "https" : "http", server_address, 1204 server_port, server_url, (int)pagesize);
1153 server_port, server_url, (int)pagesize); 1205 }
1154 1206
1155 /* find status line and null-terminate it */ 1207 /* find status line and null-terminate it */
1156 status_line = page; 1208 status_line = page;
1157 page += (size_t) strcspn (page, "\r\n"); 1209 page += (size_t)strcspn(page, "\r\n");
1158 pos = page; 1210 pos = page;
1159 page += (size_t) strspn (page, "\r\n"); 1211 page += (size_t)strspn(page, "\r\n");
1160 status_line[strcspn(status_line, "\r\n")] = 0; 1212 status_line[strcspn(status_line, "\r\n")] = 0;
1161 strip (status_line); 1213 strip(status_line);
1162 if (verbose) 1214 if (verbose) {
1163 printf ("STATUS: %s\n", status_line); 1215 printf("STATUS: %s\n", status_line);
1164 1216 }
1165 /* find header info and null-terminate it */ 1217
1166 header = page; 1218 /* find header info and null-terminate it */
1167 while (strcspn (page, "\r\n") > 0) { 1219 header = page;
1168 page += (size_t) strcspn (page, "\r\n"); 1220 while (strcspn(page, "\r\n") > 0) {
1169 pos = page; 1221 page += (size_t)strcspn(page, "\r\n");
1170 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) || 1222 pos = page;
1171 (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2)) 1223 if ((strspn(page, "\r") == 1 && strspn(page, "\r\n") >= 2) ||
1172 page += (size_t) 2; 1224 (strspn(page, "\n") == 1 && strspn(page, "\r\n") >= 2)) {
1173 else 1225 page += (size_t)2;
1174 page += (size_t) 1; 1226 } else {
1175 } 1227 page += (size_t)1;
1176 page += (size_t) strspn (page, "\r\n"); 1228 }
1177 header[pos - header] = 0; 1229 }
1178 if (verbose) 1230 page += (size_t)strspn(page, "\r\n");
1179 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header, 1231 header[pos - header] = 0;
1180 (no_body ? " [[ skipped ]]" : page)); 1232 if (verbose) {
1181 1233 printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
1182 /* make sure the status line matches the response we are looking for */ 1234 (no_body ? " [[ skipped ]]" : page));
1183 if (!expected_statuscode (status_line, server_expect)) { 1235 }
1184 if (server_port == HTTP_PORT) 1236
1185 xasprintf (&msg, 1237 /* make sure the status line matches the response we are looking for */
1186 _("Invalid HTTP response received from host: %s\n"), 1238 if (!expected_statuscode(status_line, server_expect)) {
1187 status_line); 1239 if (server_port == HTTP_PORT) {
1188 else 1240 xasprintf(&msg, _("Invalid HTTP response received from host: %s\n"), status_line);
1189 xasprintf (&msg, 1241 } else {
1190 _("Invalid HTTP response received from host on port %d: %s\n"), 1242 xasprintf(&msg, _("Invalid HTTP response received from host on port %d: %s\n"),
1191 server_port, status_line); 1243 server_port, status_line);
1192 if (show_body) 1244 }
1193 xasprintf (&msg, _("%s\n%s"), msg, page); 1245 if (show_body) {
1194 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg); 1246 xasprintf(&msg, _("%s\n%s"), msg, page);
1195 } 1247 }
1196 1248 die(STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
1197 /* Bypass normal status line check if server_expect was set by user and not default */ 1249 }
1198 /* NOTE: After this if/else block msg *MUST* be an asprintf-allocated string */ 1250
1199 if ( server_expect_yn ) { 1251 /* Bypass normal status line check if server_expect was set by user and not default */
1200 xasprintf (&msg, 1252 /* NOTE: After this if/else block msg *MUST* be an asprintf-allocated string */
1201 _("Status line output matched \"%s\" - "), server_expect); 1253 if (server_expect_yn) {
1202 if (verbose) 1254 xasprintf(&msg, _("Status line output matched \"%s\" - "), server_expect);
1203 printf ("%s\n",msg); 1255 if (verbose) {
1204 } 1256 printf("%s\n", msg);
1205 else { 1257 }
1206 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */ 1258 } else {
1207 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */ 1259 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
1208 /* Status-Code = 3 DIGITS */ 1260 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
1209 1261 /* Status-Code = 3 DIGITS */
1210 status_code = strchr (status_line, ' ') + sizeof (char); 1262
1211 if (strspn (status_code, "1234567890") != 3) 1263 status_code = strchr(status_line, ' ') + sizeof(char);
1212 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line); 1264 if (strspn(status_code, "1234567890") != 3) {
1213 1265 die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
1214 http_status = atoi (status_code); 1266 }
1215 1267
1216 /* check the return code */ 1268 http_status = atoi(status_code);
1217 1269
1218 if (http_status >= 600 || http_status < 100) { 1270 /* check the return code */
1219 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line); 1271
1220 } 1272 if (http_status >= 600 || http_status < 100) {
1221 /* server errors result in a critical state */ 1273 die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
1222 else if (http_status >= 500) { 1274 }
1223 xasprintf (&msg, _("%s - "), status_line); 1275 /* server errors result in a critical state */
1224 result = STATE_CRITICAL; 1276 else if (http_status >= 500) {
1225 } 1277 xasprintf(&msg, _("%s - "), status_line);
1226 /* client errors result in a warning state */ 1278 result = STATE_CRITICAL;
1227 else if (http_status >= 400) { 1279 }
1228 xasprintf (&msg, _("%s - "), status_line); 1280 /* client errors result in a warning state */
1229 result = max_state_alt(STATE_WARNING, result); 1281 else if (http_status >= 400) {
1230 } 1282 xasprintf(&msg, _("%s - "), status_line);
1231 /* check redirected page if specified */ 1283 result = max_state_alt(STATE_WARNING, result);
1232 else if (http_status >= 300) { 1284 }
1233 1285 /* check redirected page if specified */
1234 if (onredirect == STATE_DEPENDENT) 1286 else if (http_status >= 300) {
1235 redir (header, status_line); 1287
1236 else 1288 if (onredirect == STATE_DEPENDENT) {
1237 result = max_state_alt(onredirect, result); 1289 redir(header, status_line);
1238 xasprintf (&msg, _("%s - "), status_line); 1290 } else {
1239 } /* end if (http_status >= 300) */ 1291 result = max_state_alt(onredirect, result);
1240 else { 1292 }
1241 /* Print OK status anyway */ 1293 xasprintf(&msg, _("%s - "), status_line);
1242 xasprintf (&msg, _("%s - "), status_line); 1294 } /* end if (http_status >= 300) */
1243 } 1295 else {
1244 1296 /* Print OK status anyway */
1245 } /* end else (server_expect_yn) */ 1297 xasprintf(&msg, _("%s - "), status_line);
1246 1298 }
1247 /* reset the alarm - must be called *after* redir or we'll never die on redirects! */ 1299
1248 alarm (0); 1300 } /* end else (server_expect_yn) */
1249 1301
1250 if (maximum_age >= 0) { 1302 /* reset the alarm - must be called *after* redir or we'll never die on redirects! */
1251 result = max_state_alt(check_document_dates(header, &msg), result); 1303 alarm(0);
1252 } 1304
1253 1305 if (maximum_age >= 0) {
1254 /* Page and Header content checks go here */ 1306 result = max_state_alt(check_document_dates(header, &msg), result);
1255 if (strlen(header_expect) > 0) { 1307 }
1256 if (strstr(header, header_expect) == NULL) { 1308
1257 // We did not find the header, the rest is for building the output and setting the state 1309 /* Page and Header content checks go here */
1258 char output_header_search[30] = ""; 1310 if (strlen(header_expect) > 0) {
1259 1311 if (strstr(header, header_expect) == NULL) {
1260 strncpy(&output_header_search[0], header_expect, 1312 // We did not find the header, the rest is for building the output and setting the state
1261 sizeof(output_header_search)); 1313 char output_header_search[30] = "";
1262 1314
1263 if (output_header_search[sizeof(output_header_search) - 1] != '\0') { 1315 strncpy(&output_header_search[0], header_expect, sizeof(output_header_search));
1264 bcopy("...", 1316
1265 &output_header_search[sizeof(output_header_search) - 4], 1317 if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
1266 4); 1318 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4);
1267 } 1319 }
1268 1320
1269 xasprintf (&msg, 1321 xasprintf(&msg, _("%sheader '%s' not found on '%s://%s:%d%s', "), msg,
1270 _("%sheader '%s' not found on '%s://%s:%d%s', "), 1322 output_header_search, use_ssl ? "https" : "http",
1271 msg, 1323 host_name ? host_name : server_address, server_port, server_url);
1272 output_header_search, use_ssl ? "https" : "http", 1324
1273 host_name ? host_name : server_address, server_port, 1325 result = STATE_CRITICAL;
1274 server_url); 1326 }
1275 1327 }
1276 result = STATE_CRITICAL; 1328
1277 } 1329 // At this point we should test if the content is chunked and unchunk it, so
1278 } 1330 // it can be searched (and possibly printed)
1279 1331 const char *chunked_header_regex_string = "Transfer-Encoding: *chunked *";
1280 // At this point we should test if the content is chunked and unchunk it, so 1332 regex_t chunked_header_regex;
1281 // it can be searched (and possibly printed) 1333
1282 const char *chunked_header_regex_string = "Transfer-Encoding: *chunked *"; 1334 if (regcomp(&chunked_header_regex, chunked_header_regex_string, REG_ICASE)) {
1283 regex_t chunked_header_regex; 1335 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN),
1284 1336 "Failed to compile chunked_header_regex regex");
1285 if (regcomp(&chunked_header_regex, chunked_header_regex_string, REG_ICASE)) { 1337 }
1286 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to compile chunked_header_regex regex"); 1338
1287 } 1339 regmatch_t chre_pmatch[1]; // We actually do not care about this, since we only want to know IF
1288 1340 // it was found
1289 regmatch_t chre_pmatch[1]; // We actually do not care about this, since we only want to know IF it was found 1341
1290 1342 if (!no_body && regexec(&chunked_header_regex, header, 1, chre_pmatch, 0) == 0) {
1291 if (!no_body && regexec(&chunked_header_regex, header, 1, chre_pmatch, 0) == 0) { 1343 if (verbose) {
1292 if (verbose) { 1344 printf("Found chunked content\n");
1293 printf("Found chunked content\n"); 1345 }
1294 } 1346 // We actually found the chunked header
1295 // We actually found the chunked header 1347 char *tmp = unchunk_content(page);
1296 char *tmp = unchunk_content(page); 1348 if (tmp == NULL) {
1297 if (tmp == NULL) { 1349 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN),
1298 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to unchunk message body"); 1350 "Failed to unchunk message body");
1299 } 1351 }
1300 page = tmp; 1352 page = tmp;
1301 } 1353 }
1302 1354
1303 if (strlen(string_expect) > 0) { 1355 if (strlen(string_expect) > 0) {
1304 if (!strstr(page, string_expect)) { 1356 if (!strstr(page, string_expect)) {
1305 // We found the string the body, the rest is for building the output 1357 // We found the string the body, the rest is for building the output
1306 char output_string_search[30] = ""; 1358 char output_string_search[30] = "";
1307 strncpy(&output_string_search[0], string_expect, 1359 strncpy(&output_string_search[0], string_expect, sizeof(output_string_search));
1308 sizeof(output_string_search)); 1360 if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
1309 if (output_string_search[sizeof(output_string_search) - 1] != '\0') { 1361 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4);
1310 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 1362 }
1311 4); 1363 xasprintf(&msg, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg,
1312 } 1364 output_string_search, use_ssl ? "https" : "http",
1313 xasprintf (&msg, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search, use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url); 1365 host_name ? host_name : server_address, server_port, server_url);
1314 result = STATE_CRITICAL; 1366 result = STATE_CRITICAL;
1315 } 1367 }
1316 } 1368 }
1317 1369
1318 if (strlen(regexp) > 0) { 1370 if (strlen(regexp) > 0) {
1319 errcode = regexec(&preg, page, REGS, pmatch, 0); 1371 errcode = regexec(&preg, page, REGS, pmatch, 0);
1320 if ((errcode == 0 && invert_regex == 0) || 1372 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
1321 (errcode == REG_NOMATCH && invert_regex == 1)) { 1373 /* OK - No-op to avoid changing the logic around it */
1322 /* OK - No-op to avoid changing the logic around it */ 1374 result = max_state_alt(STATE_OK, result);
1323 result = max_state_alt(STATE_OK, result); 1375 } else if ((errcode == REG_NOMATCH && invert_regex == 0) ||
1324 } 1376 (errcode == 0 && invert_regex == 1)) {
1325 else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) { 1377 if (invert_regex == 0) {
1326 if (invert_regex == 0) 1378 xasprintf(&msg, _("%spattern not found, "), msg);
1327 xasprintf (&msg, _("%spattern not found, "), msg); 1379 } else {
1328 else 1380 xasprintf(&msg, _("%spattern found, "), msg);
1329 xasprintf (&msg, _("%spattern found, "), msg); 1381 }
1330 result = state_regex; 1382 result = state_regex;
1331 } 1383 } else {
1332 else { 1384 /* FIXME: Shouldn't that be UNKNOWN? */
1333 /* FIXME: Shouldn't that be UNKNOWN? */ 1385 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1334 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1386 xasprintf(&msg, _("%sExecute Error: %s, "), msg, errbuf);
1335 xasprintf (&msg, _("%sExecute Error: %s, "), msg, errbuf); 1387 result = STATE_CRITICAL;
1336 result = STATE_CRITICAL; 1388 }
1337 } 1389 }
1338 } 1390
1339 1391 /* make sure the page is of an appropriate size */
1340 /* make sure the page is of an appropriate size */ 1392 /* page_len = get_content_length(header); */
1341 /* page_len = get_content_length(header); */ 1393 /* FIXME: Will this work with -N ? IMHO we should use
1342 /* FIXME: Will this work with -N ? IMHO we should use 1394 * get_content_length(header) and always check if it's different than the
1343 * get_content_length(header) and always check if it's different than the 1395 * returned pagesize
1344 * returned pagesize 1396 */
1345 */ 1397 /* FIXME: IIRC pagesize returns headers - shouldn't we make
1346 /* FIXME: IIRC pagesize returns headers - shouldn't we make 1398 * it == get_content_length(header) ??
1347 * it == get_content_length(header) ?? 1399 */
1348 */ 1400 page_len = pagesize;
1349 page_len = pagesize; 1401 if ((max_page_len > 0) && (page_len > max_page_len)) {
1350 if ((max_page_len > 0) && (page_len > max_page_len)) { 1402 xasprintf(&msg, _("%spage size %d too large, "), msg, page_len);
1351 xasprintf (&msg, _("%spage size %d too large, "), msg, page_len); 1403 result = max_state_alt(STATE_WARNING, result);
1352 result = max_state_alt(STATE_WARNING, result); 1404 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1353 } else if ((min_page_len > 0) && (page_len < min_page_len)) { 1405 xasprintf(&msg, _("%spage size %d too small, "), msg, page_len);
1354 xasprintf (&msg, _("%spage size %d too small, "), msg, page_len); 1406 result = max_state_alt(STATE_WARNING, result);
1355 result = max_state_alt(STATE_WARNING, result); 1407 }
1356 } 1408
1357 1409 /* Cut-off trailing characters */
1358 /* Cut-off trailing characters */ 1410 if (msg[strlen(msg) - 2] == ',') {
1359 if(msg[strlen(msg)-2] == ',') 1411 msg[strlen(msg) - 2] = '\0';
1360 msg[strlen(msg)-2] = '\0'; 1412 } else {
1361 else 1413 msg[strlen(msg) - 3] = '\0';
1362 msg[strlen(msg)-3] = '\0'; 1414 }
1363 1415
1364 /* check elapsed time */ 1416 /* check elapsed time */
1365 if (show_extended_perfdata) 1417 if (show_extended_perfdata) {
1366 xasprintf (&msg, 1418 xasprintf(
1367 _("%s - %d bytes in %.3f second response time %s|%s %s %s %s %s %s %s"), 1419 &msg, _("%s - %d bytes in %.3f second response time %s|%s %s %s %s %s %s %s"), msg,
1368 msg, page_len, elapsed_time, 1420 page_len, elapsed_time, (display_html ? "</A>" : ""), perfd_time(elapsed_time),
1369 (display_html ? "</A>" : ""), 1421 perfd_size(page_len), perfd_time_connect(elapsed_time_connect),
1370 perfd_time (elapsed_time), 1422 use_ssl ? perfd_time_ssl(elapsed_time_ssl) : "",
1371 perfd_size (page_len), 1423 perfd_time_headers(elapsed_time_headers), perfd_time_firstbyte(elapsed_time_firstbyte),
1372 perfd_time_connect (elapsed_time_connect), 1424 perfd_time_transfer(elapsed_time_transfer));
1373 use_ssl == true ? perfd_time_ssl (elapsed_time_ssl) : "", 1425 } else {
1374 perfd_time_headers (elapsed_time_headers), 1426 xasprintf(&msg, _("%s - %d bytes in %.3f second response time %s|%s %s"), msg, page_len,
1375 perfd_time_firstbyte (elapsed_time_firstbyte), 1427 elapsed_time, (display_html ? "</A>" : ""), perfd_time(elapsed_time),
1376 perfd_time_transfer (elapsed_time_transfer)); 1428 perfd_size(page_len));
1377 else 1429 }
1378 xasprintf (&msg, 1430
1379 _("%s - %d bytes in %.3f second response time %s|%s %s"), 1431 if (show_body) {
1380 msg, page_len, elapsed_time, 1432 xasprintf(&msg, _("%s\n%s"), msg, page);
1381 (display_html ? "</A>" : ""), 1433 }
1382 perfd_time (elapsed_time), 1434
1383 perfd_size (page_len)); 1435 result = max_state_alt(get_status(elapsed_time, thlds), result);
1384 1436
1385 if (show_body) 1437 die(result, "HTTP %s: %s\n", state_text(result), msg);
1386 xasprintf (&msg, _("%s\n%s"), msg, page); 1438 /* die failed? */
1387 1439 return STATE_UNKNOWN;
1388 result = max_state_alt(get_status(elapsed_time, thlds), result);
1389
1390 die (result, "HTTP %s: %s\n", state_text(result), msg);
1391 /* die failed? */
1392 return STATE_UNKNOWN;
1393} 1440}
1394 1441
1395/* Receivces a pointer to the beginning of the body of a HTTP message 1442/* Receivces a pointer to the beginning of the body of a HTTP message
@@ -1398,94 +1445,95 @@ check_http (void)
1398 * The result must be freed by the caller. 1445 * The result must be freed by the caller.
1399 */ 1446 */
1400char *unchunk_content(const char *content) { 1447char *unchunk_content(const char *content) {
1401 // https://en.wikipedia.org/wiki/Chunked_transfer_encoding 1448 // https://en.wikipedia.org/wiki/Chunked_transfer_encoding
1402 // https://www.rfc-editor.org/rfc/rfc7230#section-4.1 1449 // https://www.rfc-editor.org/rfc/rfc7230#section-4.1
1403 char *result = NULL; 1450 char *result = NULL;
1404 char *start_of_chunk; 1451 char *start_of_chunk;
1405 char* end_of_chunk; 1452 char *end_of_chunk;
1406 long size_of_chunk; 1453 long size_of_chunk;
1407 const char *pointer = content; 1454 const char *pointer = content;
1408 char *endptr; 1455 char *endptr;
1409 long length_of_chunk = 0; 1456 long length_of_chunk = 0;
1410 size_t overall_size = 0; 1457 size_t overall_size = 0;
1411 1458
1412 while (true) { 1459 while (true) {
1413 size_of_chunk = strtol(pointer, &endptr, 16); 1460 size_of_chunk = strtol(pointer, &endptr, 16);
1414 if (size_of_chunk == LONG_MIN || size_of_chunk == LONG_MAX) { 1461 if (size_of_chunk == LONG_MIN || size_of_chunk == LONG_MAX) {
1415 // Apparently underflow or overflow, should not happen 1462 // Apparently underflow or overflow, should not happen
1416 if (verbose) { 1463 if (verbose) {
1417 printf("Got an underflow or overflow from strtol at: %u\n", __LINE__); 1464 printf("Got an underflow or overflow from strtol at: %u\n", __LINE__);
1418 } 1465 }
1419 return NULL; 1466 return NULL;
1420 } 1467 }
1421 if (endptr == pointer) { 1468 if (endptr == pointer) {
1422 // Apparently this was not a number 1469 // Apparently this was not a number
1423 if (verbose) { 1470 if (verbose) {
1424 printf("Chunked content did not start with a number at all (Line: %u)\n", __LINE__); 1471 printf("Chunked content did not start with a number at all (Line: %u)\n", __LINE__);
1425 } 1472 }
1426 return NULL; 1473 return NULL;
1427 } 1474 }
1428 1475
1429 // So, we got the length of the chunk 1476 // So, we got the length of the chunk
1430 if (*endptr == ';') { 1477 if (*endptr == ';') {
1431 // Chunk extension starts here 1478 // Chunk extension starts here
1432 while (*endptr != '\r') { 1479 while (*endptr != '\r') {
1433 endptr++; 1480 endptr++;
1434 } 1481 }
1435 } 1482 }
1436 1483
1437 start_of_chunk = endptr + 2; 1484 start_of_chunk = endptr + 2;
1438 end_of_chunk = start_of_chunk + size_of_chunk; 1485 end_of_chunk = start_of_chunk + size_of_chunk;
1439 length_of_chunk = (long)(end_of_chunk - start_of_chunk); 1486 length_of_chunk = (long)(end_of_chunk - start_of_chunk);
1440 pointer = end_of_chunk + 2; //Next number should be here 1487 pointer = end_of_chunk + 2; // Next number should be here
1441 1488
1442 if (length_of_chunk == 0) { 1489 if (length_of_chunk == 0) {
1443 // Chunk length is 0, so this is the last one 1490 // Chunk length is 0, so this is the last one
1444 break; 1491 break;
1445 } 1492 }
1446 1493
1447 overall_size += length_of_chunk; 1494 overall_size += length_of_chunk;
1448 1495
1449 if (result == NULL) { 1496 if (result == NULL) {
1450 // Size of the chunk plus the ending NULL byte 1497 // Size of the chunk plus the ending NULL byte
1451 result = (char *)malloc(length_of_chunk +1); 1498 result = (char *)malloc(length_of_chunk + 1);
1452 if (result == NULL) { 1499 if (result == NULL) {
1453 if (verbose) { 1500 if (verbose) {
1454 printf("Failed to allocate memory for unchunked body\n"); 1501 printf("Failed to allocate memory for unchunked body\n");
1455 } 1502 }
1456 return NULL; 1503 return NULL;
1457 } 1504 }
1458 } else { 1505 } else {
1459 // Enlarge memory to the new size plus the ending NULL byte 1506 // Enlarge memory to the new size plus the ending NULL byte
1460 void *tmp = realloc(result, overall_size +1); 1507 void *tmp = realloc(result, overall_size + 1);
1461 if (tmp == NULL) { 1508 if (tmp == NULL) {
1462 if (verbose) { 1509 if (verbose) {
1463 printf("Failed to allocate memory for unchunked body\n"); 1510 printf("Failed to allocate memory for unchunked body\n");
1464 } 1511 }
1465 return NULL; 1512 return NULL;
1466 } else { 1513 }
1467 result = tmp; 1514 result = tmp;
1468 } 1515 }
1469 } 1516
1470 1517 memcpy(result + (overall_size - size_of_chunk), start_of_chunk, size_of_chunk);
1471 memcpy(result + (overall_size - size_of_chunk), start_of_chunk, size_of_chunk); 1518 }
1472 } 1519
1473 1520 if (overall_size == 0 && result == NULL) {
1474 if (overall_size == 0 && result == NULL) { 1521 // We might just have received the end chunk without previous content, so result is never
1475 // We might just have received the end chunk without previous content, so result is never allocated 1522 // allocated
1476 result = calloc(1, sizeof(char)); 1523 result = calloc(1, sizeof(char));
1477 // No error handling here, we can only return NULL anyway 1524 // No error handling here, we can only return NULL anyway
1478 } else { 1525 } else {
1479 result[overall_size] = '\0'; 1526 result[overall_size] = '\0';
1480 } 1527 }
1481 return result; 1528 return result;
1482} 1529}
1483 1530
1484/* per RFC 2396 */ 1531/* per RFC 2396 */
1485#define URI_HTTP "%5[HTPShtps]" 1532#define URI_HTTP "%5[HTPShtps]"
1486#define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]" 1533#define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1487#define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */ 1534#define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
1488#define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]" 1535#define URI_PATH \
1536 "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1489#define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH 1537#define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH
1490#define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH 1538#define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1491#define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT 1539#define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
@@ -1494,414 +1542,431 @@ char *unchunk_content(const char *content) {
1494#define HD5 "//" URI_HOST "/" URI_PATH 1542#define HD5 "//" URI_HOST "/" URI_PATH
1495#define HD6 URI_PATH 1543#define HD6 URI_PATH
1496 1544
1497void 1545void redir(char *pos, char *status_line) {
1498redir (char *pos, char *status_line) 1546 int i = 0;
1499{ 1547 char *x;
1500 int i = 0; 1548 char xx[2];
1501 char *x; 1549 char type[6];
1502 char xx[2]; 1550 char *addr;
1503 char type[6]; 1551 char *url;
1504 char *addr; 1552
1505 char *url; 1553 addr = malloc(MAX_IPV4_HOSTLENGTH + 1);
1506 1554 if (addr == NULL) {
1507 addr = malloc (MAX_IPV4_HOSTLENGTH + 1); 1555 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
1508 if (addr == NULL) 1556 }
1509 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n")); 1557
1510 1558 memset(addr, 0, MAX_IPV4_HOSTLENGTH);
1511 memset(addr, 0, MAX_IPV4_HOSTLENGTH); 1559 url = malloc(strcspn(pos, "\r\n"));
1512 url = malloc (strcspn (pos, "\r\n")); 1560 if (url == NULL) {
1513 if (url == NULL) 1561 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1514 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n")); 1562 }
1515 1563
1516 while (pos) { 1564 while (pos) {
1517 sscanf (pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i); 1565 sscanf(pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i);
1518 if (i == 0) { 1566 if (i == 0) {
1519 pos += (size_t) strcspn (pos, "\r\n"); 1567 pos += (size_t)strcspn(pos, "\r\n");
1520 pos += (size_t) strspn (pos, "\r\n"); 1568 pos += (size_t)strspn(pos, "\r\n");
1521 if (strlen(pos) == 0) 1569 if (strlen(pos) == 0) {
1522 die (STATE_UNKNOWN, 1570 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
1523 _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"), 1571 status_line, (display_html ? "</A>" : ""));
1524 status_line, (display_html ? "</A>" : "")); 1572 }
1525 continue; 1573 continue;
1526 } 1574 }
1527 1575
1528 pos += i; 1576 pos += i;
1529 pos += strspn (pos, " \t"); 1577 pos += strspn(pos, " \t");
1530 1578
1531 /* 1579 /*
1532 * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by 1580 * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by
1533 * preceding each extra line with at least one SP or HT.'' 1581 * preceding each extra line with at least one SP or HT.''
1534 */ 1582 */
1535 for (; (i = strspn (pos, "\r\n")); pos += i) { 1583 for (; (i = strspn(pos, "\r\n")); pos += i) {
1536 pos += i; 1584 pos += i;
1537 if (!(i = strspn (pos, " \t"))) { 1585 if (!(i = strspn(pos, " \t"))) {
1538 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"), 1586 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
1539 display_html ? "</A>" : ""); 1587 display_html ? "</A>" : "");
1540 } 1588 }
1541 } 1589 }
1542 1590
1543 url = realloc (url, strcspn (pos, "\r\n") + 1); 1591 url = realloc(url, strcspn(pos, "\r\n") + 1);
1544 if (url == NULL) 1592 if (url == NULL) {
1545 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n")); 1593 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1546 1594 }
1547 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */ 1595
1548 if (sscanf (pos, HD1, type, addr, &i, url) == 4) { 1596 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1549 url = prepend_slash (url); 1597 if (sscanf(pos, HD1, type, addr, &i, url) == 4) {
1550 use_ssl = server_type_check (type); 1598 url = prepend_slash(url);
1551 } 1599 use_ssl = server_type_check(type);
1552 1600 }
1553 /* URI_HTTP URI_HOST URI_PATH */ 1601
1554 else if (sscanf (pos, HD2, type, addr, url) == 3 ) { 1602 /* URI_HTTP URI_HOST URI_PATH */
1555 url = prepend_slash (url); 1603 else if (sscanf(pos, HD2, type, addr, url) == 3) {
1556 use_ssl = server_type_check (type); 1604 url = prepend_slash(url);
1557 i = server_port_check (use_ssl); 1605 use_ssl = server_type_check(type);
1558 } 1606 i = server_port_check(use_ssl);
1559 1607 }
1560 /* URI_HTTP URI_HOST URI_PORT */ 1608
1561 else if (sscanf (pos, HD3, type, addr, &i) == 3) { 1609 /* URI_HTTP URI_HOST URI_PORT */
1562 strcpy (url, HTTP_URL); 1610 else if (sscanf(pos, HD3, type, addr, &i) == 3) {
1563 use_ssl = server_type_check (type); 1611 strcpy(url, HTTP_URL);
1564 } 1612 use_ssl = server_type_check(type);
1565 1613 }
1566 /* URI_HTTP URI_HOST */ 1614
1567 else if (sscanf (pos, HD4, type, addr) == 2) { 1615 /* URI_HTTP URI_HOST */
1568 strcpy (url, HTTP_URL); 1616 else if (sscanf(pos, HD4, type, addr) == 2) {
1569 use_ssl = server_type_check (type); 1617 strcpy(url, HTTP_URL);
1570 i = server_port_check (use_ssl); 1618 use_ssl = server_type_check(type);
1571 } 1619 i = server_port_check(use_ssl);
1572 /* URI_HTTP, URI_HOST, URI_PATH */ 1620 }
1573 else if (sscanf (pos, HD5, addr, url) == 2) { 1621 /* URI_HTTP, URI_HOST, URI_PATH */
1574 if(use_ssl){ 1622 else if (sscanf(pos, HD5, addr, url) == 2) {
1575 strcpy (type,"https"); 1623 if (use_ssl) {
1576 } 1624 strcpy(type, "https");
1577 else{ 1625 } else {
1578 strcpy (type, server_type); 1626 strcpy(type, server_type);
1579 } 1627 }
1580 xasprintf (&url, "/%s", url); 1628 xasprintf(&url, "/%s", url);
1581 use_ssl = server_type_check (type); 1629 use_ssl = server_type_check(type);
1582 i = server_port_check (use_ssl); 1630 i = server_port_check(use_ssl);
1583 } 1631 }
1584 1632
1585 /* URI_PATH */ 1633 /* URI_PATH */
1586 else if (sscanf (pos, HD6, url) == 1) { 1634 else if (sscanf(pos, HD6, url) == 1) {
1587 /* relative url */ 1635 /* relative url */
1588 if ((url[0] != '/')) { 1636 if ((url[0] != '/')) {
1589 if ((x = strrchr(server_url, '/'))) 1637 if ((x = strrchr(server_url, '/'))) {
1590 *x = '\0'; 1638 *x = '\0';
1591 xasprintf (&url, "%s/%s", server_url, url); 1639 }
1592 } 1640 xasprintf(&url, "%s/%s", server_url, url);
1593 i = server_port; 1641 }
1594 strcpy (type, server_type); 1642 i = server_port;
1595 strcpy (addr, host_name ? host_name : server_address); 1643 strcpy(type, server_type);
1596 } 1644 strcpy(addr, host_name ? host_name : server_address);
1597 1645 }
1598 else { 1646
1599 die (STATE_UNKNOWN, 1647 else {
1600 _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"), 1648 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"), pos,
1601 pos, (display_html ? "</A>" : "")); 1649 (display_html ? "</A>" : ""));
1602 } 1650 }
1603 1651
1604 break; 1652 break;
1605 1653
1606 } /* end while (pos) */ 1654 } /* end while (pos) */
1607 1655
1608 if (++redir_depth > max_depth) 1656 if (++redir_depth > max_depth) {
1609 die (STATE_WARNING, 1657 die(STATE_WARNING,
1610 _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"), 1658 _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"), max_depth,
1611 max_depth, type, addr, i, url, (display_html ? "</A>" : "")); 1659 type, addr, i, url, (display_html ? "</A>" : ""));
1612 1660 }
1613 if (server_port==i && 1661
1614 !strncmp(server_address, addr, MAX_IPV4_HOSTLENGTH) && 1662 if (server_port == i && !strncmp(server_address, addr, MAX_IPV4_HOSTLENGTH) &&
1615 (host_name && !strncmp(host_name, addr, MAX_IPV4_HOSTLENGTH)) && 1663 (host_name && !strncmp(host_name, addr, MAX_IPV4_HOSTLENGTH)) && !strcmp(server_url, url)) {
1616 !strcmp(server_url, url)) 1664 die(STATE_CRITICAL,
1617 die (STATE_CRITICAL, 1665 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), type,
1618 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), 1666 addr, i, url, (display_html ? "</A>" : ""));
1619 type, addr, i, url, (display_html ? "</A>" : "")); 1667 }
1620 1668
1621 strcpy (server_type, type); 1669 strcpy(server_type, type);
1622 1670
1623 free (host_name); 1671 free(host_name);
1624 host_name = strndup (addr, MAX_IPV4_HOSTLENGTH); 1672 host_name = strndup(addr, MAX_IPV4_HOSTLENGTH);
1625 1673
1626 if (!(followsticky & STICKY_HOST)) { 1674 if (!(followsticky & STICKY_HOST)) {
1627 free (server_address); 1675 free(server_address);
1628 server_address = strndup (addr, MAX_IPV4_HOSTLENGTH); 1676 server_address = strndup(addr, MAX_IPV4_HOSTLENGTH);
1629 } 1677 }
1630 if (!(followsticky & STICKY_PORT)) { 1678 if (!(followsticky & STICKY_PORT)) {
1631 server_port = i; 1679 server_port = i;
1632 } 1680 }
1633 1681
1634 free (server_url); 1682 free(server_url);
1635 server_url = url; 1683 server_url = url;
1636 1684
1637 if (server_port > MAX_PORT) 1685 if (server_port > MAX_PORT) {
1638 die (STATE_UNKNOWN, 1686 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"),
1639 _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"), 1687 MAX_PORT, server_type, server_address, server_port, server_url,
1640 MAX_PORT, server_type, server_address, server_port, server_url, 1688 display_html ? "</A>" : "");
1641 display_html ? "</A>" : ""); 1689 }
1642
1643 /* reset virtual port */
1644 virtual_port = server_port;
1645
1646 if (verbose)
1647 printf (_("Redirection to %s://%s:%d%s\n"), server_type,
1648 host_name ? host_name : server_address, server_port, server_url);
1649
1650 free(addr);
1651 check_http ();
1652}
1653 1690
1691 /* reset virtual port */
1692 virtual_port = server_port;
1654 1693
1655bool 1694 if (verbose) {
1656server_type_check (const char *type) 1695 printf(_("Redirection to %s://%s:%d%s\n"), server_type,
1657{ 1696 host_name ? host_name : server_address, server_port, server_url);
1658 if (strcmp (type, "https")) 1697 }
1659 return false; 1698
1660 else 1699 free(addr);
1661 return true; 1700 check_http();
1662} 1701}
1663 1702
1664int 1703bool server_type_check(const char *type) { return (!(bool)strcmp(type, "https")); }
1665server_port_check (int ssl_flag) 1704
1666{ 1705int server_port_check(int ssl_flag) {
1667 if (ssl_flag) 1706 if (ssl_flag) {
1668 return HTTPS_PORT; 1707 return HTTPS_PORT;
1669 else 1708 }
1670 return HTTP_PORT; 1709 return HTTP_PORT;
1671} 1710}
1672 1711
1673char *perfd_time (double elapsed_time) 1712char *perfd_time(double elapsed_time) {
1674{ 1713 return fperfdata("time", elapsed_time, "s", thlds->warning,
1675 return fperfdata ("time", elapsed_time, "s", 1714 thlds->warning ? thlds->warning->end : 0, thlds->critical,
1676 thlds->warning?true:false, thlds->warning?thlds->warning->end:0, 1715 thlds->critical ? thlds->critical->end : 0, true, 0, true, socket_timeout);
1677 thlds->critical?true:false, thlds->critical?thlds->critical->end:0,
1678 true, 0, true, socket_timeout);
1679} 1716}
1680 1717
1681char *perfd_time_connect (double elapsed_time_connect) 1718char *perfd_time_connect(double elapsed_time_connect) {
1682{ 1719 return fperfdata("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true,
1683 return fperfdata ("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1720 socket_timeout);
1684} 1721}
1685 1722
1686char *perfd_time_ssl (double elapsed_time_ssl) 1723char *perfd_time_ssl(double elapsed_time_ssl) {
1687{ 1724 return fperfdata("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true,
1688 return fperfdata ("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1725 socket_timeout);
1689} 1726}
1690 1727
1691char *perfd_time_headers (double elapsed_time_headers) 1728char *perfd_time_headers(double elapsed_time_headers) {
1692{ 1729 return fperfdata("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true,
1693 return fperfdata ("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1730 socket_timeout);
1694} 1731}
1695 1732
1696char *perfd_time_firstbyte (double elapsed_time_firstbyte) 1733char *perfd_time_firstbyte(double elapsed_time_firstbyte) {
1697{ 1734 return fperfdata("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0,
1698 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1735 true, socket_timeout);
1699} 1736}
1700 1737
1701char *perfd_time_transfer (double elapsed_time_transfer) 1738char *perfd_time_transfer(double elapsed_time_transfer) {
1702{ 1739 return fperfdata("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0,
1703 return fperfdata ("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1740 true, socket_timeout);
1704} 1741}
1705 1742
1706char *perfd_size (int page_len) 1743char *perfd_size(int page_len) {
1707{ 1744 return perfdata("size", page_len, "B", (min_page_len > 0), min_page_len, (min_page_len > 0), 0,
1708 return perfdata ("size", page_len, "B", 1745 true, 0, false, 0);
1709 (min_page_len>0?true:false), min_page_len,
1710 (min_page_len>0?true:false), 0,
1711 true, 0, false, 0);
1712} 1746}
1713 1747
1714void 1748void print_help(void) {
1715print_help (void) 1749 print_revision(progname, NP_VERSION);
1716{
1717 print_revision (progname, NP_VERSION);
1718 1750
1719 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 1751 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1720 printf (COPYRIGHT, copyright, email); 1752 printf(COPYRIGHT, copyright, email);
1721 1753
1722 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test")); 1754 printf("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1723 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for")); 1755 printf("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1724 printf ("%s\n", _("strings and regular expressions, check connection times, and report on")); 1756 printf("%s\n", _("strings and regular expressions, check connection times, and report on"));
1725 printf ("%s\n", _("certificate expiration times.")); 1757 printf("%s\n", _("certificate expiration times."));
1726 1758
1727 printf ("\n\n"); 1759 printf("\n");
1760 printf("%s\n", _("ATTENTION!"));
1761 printf("\n");
1762 printf("%s\n", _("THIS PLUGIN IS DEPRECATED. The functionality was reimplemented by the"));
1763 printf("%s\n", _("check_curl plugin, which can be used as a drop-in replacement. You should"));
1764 printf("%s\n", _("migrate your checks over to check_curl, because check_http is going to be"));
1765 printf("%s\n", _("removed sooner than later. Just replace check_http with check_curl in your"));
1766 printf("%s\n", _("check command definitions."));
1767 printf("%s\n",
1768 _("Report issues to: https://github.com/monitoring-plugins/monitoring-plugins/issues"));
1728 1769
1729 print_usage (); 1770 printf("\n\n");
1771
1772 print_usage();
1730 1773
1731#ifdef HAVE_SSL 1774#ifdef HAVE_SSL
1732 printf (_("In the first form, make an HTTP request.")); 1775 printf(_("In the first form, make an HTTP request."));
1733 printf (_("In the second form, connect to the server and check the TLS certificate.")); 1776 printf(_("In the second form, connect to the server and check the TLS certificate."));
1734#endif 1777#endif
1735 printf (_("NOTE: One or both of -H and -I must be specified")); 1778 printf(_("NOTE: One or both of -H and -I must be specified"));
1736 1779
1737 printf ("\n"); 1780 printf("\n");
1738 1781
1739 printf (UT_HELP_VRSN); 1782 printf(UT_HELP_VRSN);
1740 printf (UT_EXTRA_OPTS); 1783 printf(UT_EXTRA_OPTS);
1741 1784
1742 printf (" %s\n", "-H, --hostname=ADDRESS"); 1785 printf(" %s\n", "-H, --hostname=ADDRESS");
1743 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)")); 1786 printf(" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1744 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)")); 1787 printf(" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1745 printf (" %s\n", "-I, --IP-address=ADDRESS"); 1788 printf(" %s\n", "-I, --IP-address=ADDRESS");
1746 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup).")); 1789 printf(" %s\n",
1747 printf (" %s\n", "-p, --port=INTEGER"); 1790 _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1748 printf (" %s", _("Port number (default: ")); 1791 printf(" %s\n", "-p, --port=INTEGER");
1749 printf ("%d)\n", HTTP_PORT); 1792 printf(" %s", _("Port number (default: "));
1793 printf("%d)\n", HTTP_PORT);
1750 1794
1751 printf (UT_IPv46); 1795 printf(UT_IPv46);
1752 1796
1753#ifdef HAVE_SSL 1797#ifdef HAVE_SSL
1754 printf (" %s\n", "-S, --ssl=VERSION[+]"); 1798 printf(" %s\n", "-S, --ssl=VERSION[+]");
1755 printf (" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents")); 1799 printf(" %s\n",
1756 printf (" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,")); 1800 _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents"));
1757 printf (" %s\n", _("1.2 = TLSv1.2). With a '+' suffix, newer versions are also accepted.")); 1801 printf(" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,"));
1758 printf (" %s\n", "--sni"); 1802 printf(" %s\n", _("1.2 = TLSv1.2). With a '+' suffix, newer versions are also accepted."));
1759 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); 1803 printf(" %s\n", "--sni");
1760 printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]"); 1804 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
1761 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443")); 1805 printf(" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
1762 printf (" %s\n", _("(when this option is used the URL is not checked by default. You can use")); 1806 printf(" %s\n",
1763 printf (" %s\n", _(" --continue-after-certificate to override this behavior)")); 1807 _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1764 printf (" %s\n", "--continue-after-certificate"); 1808 printf(" %s\n",
1765 printf (" %s\n", _("Allows the HTTP check to continue after performing the certificate check.")); 1809 _("(when this option is used the URL is not checked by default. You can use"));
1766 printf (" %s\n", _("Does nothing unless -C is used.")); 1810 printf(" %s\n", _(" --continue-after-certificate to override this behavior)"));
1767 printf (" %s\n", "-J, --client-cert=FILE"); 1811 printf(" %s\n", "--continue-after-certificate");
1768 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)")); 1812 printf(" %s\n",
1769 printf (" %s\n", _("to be used in establishing the SSL session")); 1813 _("Allows the HTTP check to continue after performing the certificate check."));
1770 printf (" %s\n", "-K, --private-key=FILE"); 1814 printf(" %s\n", _("Does nothing unless -C is used."));
1771 printf (" %s\n", _("Name of file containing the private key (PEM format)")); 1815 printf(" %s\n", "-J, --client-cert=FILE");
1772 printf (" %s\n", _("matching the client certificate")); 1816 printf(" %s\n", _("Name of file that contains the client certificate (PEM format)"));
1817 printf(" %s\n", _("to be used in establishing the SSL session"));
1818 printf(" %s\n", "-K, --private-key=FILE");
1819 printf(" %s\n", _("Name of file containing the private key (PEM format)"));
1820 printf(" %s\n", _("matching the client certificate"));
1773#endif 1821#endif
1774 1822
1775 printf (" %s\n", "-e, --expect=STRING"); 1823 printf(" %s\n", "-e, --expect=STRING");
1776 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in")); 1824 printf(" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
1777 printf (" %s", _("the first (status) line of the server response (default: ")); 1825 printf(" %s", _("the first (status) line of the server response (default: "));
1778 printf ("%s)\n", HTTP_EXPECT); 1826 printf("%s)\n", HTTP_EXPECT);
1779 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)")); 1827 printf(" %s\n",
1780 printf (" %s\n", "-d, --header-string=STRING"); 1828 _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1781 printf (" %s\n", _("String to expect in the response headers")); 1829 printf(" %s\n", "-d, --header-string=STRING");
1782 printf (" %s\n", "-s, --string=STRING"); 1830 printf(" %s\n", _("String to expect in the response headers"));
1783 printf (" %s\n", _("String to expect in the content")); 1831 printf(" %s\n", "-s, --string=STRING");
1784 printf (" %s\n", "-u, --url=PATH"); 1832 printf(" %s\n", _("String to expect in the content"));
1785 printf (" %s\n", _("URL to GET or POST (default: /)")); 1833 printf(" %s\n", "-u, --url=PATH");
1786 printf (" %s\n", "-P, --post=STRING"); 1834 printf(" %s\n", _("URL to GET or POST (default: /)"));
1787 printf (" %s\n", _("URL decoded http POST data")); 1835 printf(" %s\n", "-P, --post=STRING");
1788 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT, CONNECT:POST)"); 1836 printf(" %s\n", _("URL decoded http POST data"));
1789 printf (" %s\n", _("Set HTTP method.")); 1837 printf(" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, "
1790 printf (" %s\n", "-N, --no-body"); 1838 "CONNECT, CONNECT:POST)");
1791 printf (" %s\n", _("Don't wait for document body: stop reading after headers.")); 1839 printf(" %s\n", _("Set HTTP method."));
1792 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)")); 1840 printf(" %s\n", "-N, --no-body");
1793 printf (" %s\n", "-M, --max-age=SECONDS"); 1841 printf(" %s\n", _("Don't wait for document body: stop reading after headers."));
1794 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of")); 1842 printf(" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1795 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days.")); 1843 printf(" %s\n", "-M, --max-age=SECONDS");
1796 printf (" %s\n", "-T, --content-type=STRING"); 1844 printf(" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1797 printf (" %s\n", _("specify Content-Type header media type when POSTing\n")); 1845 printf(" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1798 1846 printf(" %s\n", "-T, --content-type=STRING");
1799 printf (" %s\n", "-l, --linespan"); 1847 printf(" %s\n", _("specify Content-Type header media type when POSTing\n"));
1800 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)")); 1848
1801 printf (" %s\n", "-r, --regex, --ereg=STRING"); 1849 printf(" %s\n", "-l, --linespan");
1802 printf (" %s\n", _("Search page for regex STRING")); 1850 printf(" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1803 printf (" %s\n", "-R, --eregi=STRING"); 1851 printf(" %s\n", "-r, --regex, --ereg=STRING");
1804 printf (" %s\n", _("Search page for case-insensitive regex STRING")); 1852 printf(" %s\n", _("Search page for regex STRING"));
1805 printf (" %s\n", "--invert-regex"); 1853 printf(" %s\n", "-R, --eregi=STRING");
1806 printf (" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)")); 1854 printf(" %s\n", _("Search page for case-insensitive regex STRING"));
1807 printf (" %s\n", _("can be changed with --state--regex)")); 1855 printf(" %s\n", "--invert-regex");
1808 printf (" %s\n", "--state-regex=STATE"); 1856 printf(" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)"));
1809 printf (" %s\n", _("Return STATE if regex is found, OK if not\n")); 1857 printf(" %s\n", _("can be changed with --state--regex)"));
1810 1858 printf(" %s\n", "--state-regex=STATE");
1811 printf (" %s\n", "-a, --authorization=AUTH_PAIR"); 1859 printf(" %s\n", _("Return STATE if regex is found, OK if not\n"));
1812 printf (" %s\n", _("Username:password on sites with basic authentication")); 1860
1813 printf (" %s\n", "-b, --proxy-authorization=AUTH_PAIR"); 1861 printf(" %s\n", "-a, --authorization=AUTH_PAIR");
1814 printf (" %s\n", _("Username:password on proxy-servers with basic authentication")); 1862 printf(" %s\n", _("Username:password on sites with basic authentication"));
1815 printf (" %s\n", "-A, --useragent=STRING"); 1863 printf(" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
1816 printf (" %s\n", _("String to be sent in http header as \"User Agent\"")); 1864 printf(" %s\n", _("Username:password on proxy-servers with basic authentication"));
1817 printf (" %s\n", "-k, --header=STRING"); 1865 printf(" %s\n", "-A, --useragent=STRING");
1818 printf (" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers")); 1866 printf(" %s\n", _("String to be sent in http header as \"User Agent\""));
1819 printf (" %s\n", "-E, --extended-perfdata"); 1867 printf(" %s\n", "-k, --header=STRING");
1820 printf (" %s\n", _("Print additional performance data")); 1868 printf(
1821 printf (" %s\n", "-B, --show-body"); 1869 " %s\n",
1822 printf (" %s\n", _("Print body content below status line")); 1870 _("Any other tags to be sent in http header. Use multiple times for additional headers"));
1823 printf (" %s\n", "-L, --link"); 1871 printf(" %s\n", "-E, --extended-perfdata");
1824 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)")); 1872 printf(" %s\n", _("Print additional performance data"));
1825 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>"); 1873 printf(" %s\n", "-B, --show-body");
1826 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the")); 1874 printf(" %s\n", _("Print body content below status line"));
1827 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same.")); 1875 printf(" %s\n", "-L, --link");
1828 printf (" %s\n", "--max-redirs=INTEGER"); 1876 printf(" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1829 printf (" %s", _("Maximal number of redirects (default: ")); 1877 printf(" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>");
1830 printf ("%d)\n", DEFAULT_MAX_REDIRS); 1878 printf(" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
1831 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>"); 1879 printf(" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
1832 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)")); 1880 printf(" %s\n", "--max-redirs=INTEGER");
1833 printf (UT_WARN_CRIT); 1881 printf(" %s", _("Maximal number of redirects (default: "));
1834 1882 printf("%d)\n", DEFAULT_MAX_REDIRS);
1835 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 1883 printf(" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1836 1884 printf(" %s\n",
1837 printf (UT_VERBOSE); 1885 _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1838 1886 printf(UT_WARN_CRIT);
1839 printf ("\n"); 1887
1840 printf ("%s\n", _("Notes:")); 1888 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1841 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host.")); 1889
1842 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL")); 1890 printf(UT_VERBOSE);
1843 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response")); 1891
1844 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are")); 1892 printf("\n");
1845 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN")); 1893 printf("%s\n", _("Notes:"));
1846 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument.")); 1894 printf(" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1895 printf(" %s\n",
1896 _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1897 printf(" %s\n",
1898 _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response"));
1899 printf(" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
1900 printf(" %s\n",
1901 _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1902 printf(" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1847 1903
1848#ifdef HAVE_SSL 1904#ifdef HAVE_SSL
1849 printf ("\n"); 1905 printf("\n");
1850 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to")); 1906 printf(" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1851 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 ")); 1907 printf(" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1852 printf (" %s\n", _("certificate is still valid for the specified number of days.")); 1908 printf(" %s\n", _("certificate is still valid for the specified number of days."));
1853 printf ("\n"); 1909 printf("\n");
1854 printf (" %s\n", _("Please note that this plugin does not check if the presented server")); 1910 printf(" %s\n", _("Please note that this plugin does not check if the presented server"));
1855 printf (" %s\n", _("certificate matches the hostname of the server, or if the certificate")); 1911 printf(" %s\n", _("certificate matches the hostname of the server, or if the certificate"));
1856 printf (" %s\n", _("has a valid chain of trust to one of the locally installed CAs.")); 1912 printf(" %s\n", _("has a valid chain of trust to one of the locally installed CAs."));
1857 printf ("\n"); 1913 printf("\n");
1858 printf ("%s\n", _("Examples:")); 1914 printf("%s\n", _("Examples:"));
1859 printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com"); 1915 printf(" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1860 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,")); 1916 printf(" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1861 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 1917 printf(" %s\n",
1862 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 1918 _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1863 printf (" %s\n", _("a STATE_CRITICAL will be returned.")); 1919 printf(" %s\n",
1864 printf ("\n"); 1920 _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1865 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14"); 1921 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
1866 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,")); 1922 printf("\n");
1867 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 1923 printf(" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1868 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when")); 1924 printf(" %s\n",
1869 printf (" %s\n\n", _("the certificate is expired.")); 1925 _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1870 printf ("\n"); 1926 printf(" %s\n",
1871 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 30,14"); 1927 _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1872 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 30 days,")); 1928 printf(" %s\n",
1873 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 1929 _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1874 printf (" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned.")); 1930 printf(" %s\n\n", _("the certificate is expired."));
1875 printf (" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days")); 1931 printf("\n");
1876 1932 printf(" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 30,14");
1877 printf (" %s\n\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: "); 1933 printf(" %s\n",
1878 printf (" %s\n", _("check_http -I 192.168.100.35 -p 80 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com ")); 1934 _("When the certificate of 'www.verisign.com' is valid for more than 30 days,"));
1879 printf (" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>")); 1935 printf(" %s\n",
1880 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 1936 _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1881 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 1937 printf(" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned."));
1882 printf (" %s\n", _("a STATE_CRITICAL will be returned. By adding a colon to the method you can set the method used")); 1938 printf(" %s\n",
1883 printf (" %s\n", _("inside the proxied connection: -j CONNECT:POST")); 1939 _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days"));
1940
1941 printf(" %s\n\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: ");
1942 printf(" %s\n", _("check_http -I 192.168.100.35 -p 80 -u https://www.verisign.com/ -S -j "
1943 "CONNECT -H www.verisign.com "));
1944 printf(" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> "
1945 "-S(sl) -j CONNECT -H <webserver>"));
1946 printf(" %s\n",
1947 _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1948 printf(" %s\n",
1949 _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1950 printf(" %s\n", _("a STATE_CRITICAL will be returned. By adding a colon to the method you can "
1951 "set the method used"));
1952 printf(" %s\n", _("inside the proxied connection: -j CONNECT:POST"));
1884 1953
1885#endif 1954#endif
1886 1955
1887 printf (UT_SUPPORT); 1956 printf(UT_SUPPORT);
1888
1889} 1957}
1890 1958
1891 1959void print_usage(void) {
1892 1960 printf("%s\n", _("Usage:"));
1893void 1961 printf(" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n", progname);
1894print_usage (void) 1962 printf(" [-J <client certificate file>] [-K <private key>]\n");
1895{ 1963 printf(" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
1896 printf ("%s\n", _("Usage:")); 1964 printf(" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport>]\n");
1897 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname); 1965 printf(" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive "
1898 printf (" [-J <client certificate file>] [-K <private key>]\n"); 1966 "regex>]\n");
1899 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n"); 1967 printf(" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
1900 printf (" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport>]\n"); 1968 printf(" [-A string] [-k string] [-S <version>] [--sni]\n");
1901 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n"); 1969 printf(" [-T <content-type>] [-j method]\n");
1902 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n"); 1970 printf(" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n", progname);
1903 printf (" [-A string] [-k string] [-S <version>] [--sni]\n"); 1971 printf(" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
1904 printf (" [-T <content-type>] [-j method]\n");
1905 printf (" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n",progname);
1906 printf (" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
1907} 1972}
diff --git a/plugins/check_ide_smart.c b/plugins/check_ide_smart.c
index 9640ef70..16fe3d01 100644
--- a/plugins/check_ide_smart.c
+++ b/plugins/check_ide_smart.c
@@ -56,7 +56,6 @@ void print_usage(void);
56# include <sys/device.h> 56# include <sys/device.h>
57# include <sys/param.h> 57# include <sys/param.h>
58# include <sys/sysctl.h> 58# include <sys/sysctl.h>
59# include <sys/videoio.h> /* for __u8 and friends */
60# include <sys/scsiio.h> 59# include <sys/scsiio.h>
61# include <sys/ataio.h> 60# include <sys/ataio.h>
62# include <dev/ata/atareg.h> 61# include <dev/ata/atareg.h>
@@ -79,48 +78,47 @@ void print_usage(void);
79#define UNKNOWN -1 78#define UNKNOWN -1
80 79
81typedef struct threshold_s { 80typedef struct threshold_s {
82 __u8 id; 81 uint8_t id;
83 __u8 threshold; 82 uint8_t threshold;
84 __u8 reserved[10]; 83 uint8_t reserved[10];
85} __attribute__((packed)) threshold_t; 84} __attribute__((packed)) threshold_t;
86 85
87typedef struct thresholds_s { 86typedef struct thresholds_s {
88 __u16 revision; 87 uint16_t revision;
89 threshold_t thresholds[NR_ATTRIBUTES]; 88 threshold_t thresholds[NR_ATTRIBUTES];
90 __u8 reserved[18]; 89 uint8_t reserved[18];
91 __u8 vendor[131]; 90 uint8_t vendor[131];
92 __u8 checksum; 91 uint8_t checksum;
93} __attribute__((packed)) thresholds_t; 92} __attribute__((packed)) thresholds_t;
94 93
95typedef struct value_s { 94typedef struct value_s {
96 __u8 id; 95 uint8_t id;
97 __u16 status; 96 uint16_t status;
98 __u8 value; 97 uint8_t value;
99 __u8 vendor[8]; 98 uint8_t vendor[8];
100} __attribute__((packed)) value_t; 99} __attribute__((packed)) value_t;
101 100
102typedef struct values_s { 101typedef struct values_s {
103 __u16 revision; 102 uint16_t revision;
104 value_t values[NR_ATTRIBUTES]; 103 value_t values[NR_ATTRIBUTES];
105 __u8 offline_status; 104 uint8_t offline_status;
106 __u8 vendor1; 105 uint8_t vendor1;
107 __u16 offline_timeout; 106 uint16_t offline_timeout;
108 __u8 vendor2; 107 uint8_t vendor2;
109 __u8 offline_capability; 108 uint8_t offline_capability;
110 __u16 smart_capability; 109 uint16_t smart_capability;
111 __u8 reserved[16]; 110 uint8_t reserved[16];
112 __u8 vendor[125]; 111 uint8_t vendor[125];
113 __u8 checksum; 112 uint8_t checksum;
114} __attribute__((packed)) values_t; 113} __attribute__((packed)) values_t;
115 114
116static struct { 115static struct {
117 __u8 value; 116 uint8_t value;
118 char *text; 117 char *text;
119} offline_status_text[] = {{0x00, "NeverStarted"}, {0x02, "Completed"}, {0x04, "Suspended"}, 118} offline_status_text[] = {{0x00, "NeverStarted"}, {0x02, "Completed"}, {0x04, "Suspended"}, {0x05, "Aborted"}, {0x06, "Failed"}, {0, 0}};
120 {0x05, "Aborted"}, {0x06, "Failed"}, {0, 0}};
121 119
122static struct { 120static struct {
123 __u8 value; 121 uint8_t value;
124 char *text; 122 char *text;
125} smart_command[] = {{SMART_ENABLE, "SMART_ENABLE"}, 123} smart_command[] = {{SMART_ENABLE, "SMART_ENABLE"},
126 {SMART_DISABLE, "SMART_DISABLE"}, 124 {SMART_DISABLE, "SMART_DISABLE"},
@@ -140,7 +138,7 @@ static int smart_read_values(int, values_t *);
140static int nagios(values_t *, thresholds_t *); 138static int nagios(values_t *, thresholds_t *);
141static void print_value(value_t *, threshold_t *); 139static void print_value(value_t *, threshold_t *);
142static void print_values(values_t *, thresholds_t *); 140static void print_values(values_t *, thresholds_t *);
143static int smart_cmd_simple(int, enum SmartCommand, __u8, bool); 141static int smart_cmd_simple(int, enum SmartCommand, uint8_t, bool);
144static int smart_read_thresholds(int, thresholds_t *); 142static int smart_read_thresholds(int, thresholds_t *);
145static bool verbose = false; 143static bool verbose = false;
146 144
@@ -175,8 +173,9 @@ int main(int argc, char *argv[]) {
175 173
176 o = getopt_long(argc, argv, "+d:iq10nhVv", longopts, &longindex); 174 o = getopt_long(argc, argv, "+d:iq10nhVv", longopts, &longindex);
177 175
178 if (o == -1 || o == EOF || o == 1) 176 if (o == -1 || o == EOF || o == 1) {
179 break; 177 break;
178 }
180 179
181 switch (o) { 180 switch (o) {
182 case 'd': 181 case 'd':
@@ -234,8 +233,9 @@ int main(int argc, char *argv[]) {
234 smart_read_values(fd, &values); 233 smart_read_values(fd, &values);
235 smart_read_thresholds(fd, &thresholds); 234 smart_read_thresholds(fd, &thresholds);
236 retval = nagios(&values, &thresholds); 235 retval = nagios(&values, &thresholds);
237 if (verbose) 236 if (verbose) {
238 print_values(&values, &thresholds); 237 print_values(&values, &thresholds);
238 }
239 239
240 close(fd); 240 close(fd);
241 return retval; 241 return retval;
@@ -254,7 +254,7 @@ char *get_offline_text(int status) {
254int smart_read_values(int fd, values_t *values) { 254int smart_read_values(int fd, values_t *values) {
255#ifdef __linux__ 255#ifdef __linux__
256 int e; 256 int e;
257 __u8 args[4 + 512]; 257 uint8_t args[4 + 512];
258 args[0] = WIN_SMART; 258 args[0] = WIN_SMART;
259 args[1] = 0; 259 args[1] = 0;
260 args[2] = SMART_READ_VALUES; 260 args[2] = SMART_READ_VALUES;
@@ -282,8 +282,9 @@ int smart_read_values(int fd, values_t *values) {
282 req.cylinder = WDSMART_CYL; 282 req.cylinder = WDSMART_CYL;
283 283
284 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) { 284 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
285 if (req.retsts != ATACMD_OK) 285 if (req.retsts != ATACMD_OK) {
286 errno = ENODEV; 286 errno = ENODEV;
287 }
287 } 288 }
288 289
289 if (errno != 0) { 290 if (errno != 0) {
@@ -370,22 +371,24 @@ void print_values(values_t *p, thresholds_t *t) {
370 p->smart_capability & 1 ? "SaveOnStandBy" : "", p->smart_capability & 2 ? "AutoSave" : ""); 371 p->smart_capability & 1 ? "SaveOnStandBy" : "", p->smart_capability & 2 ? "AutoSave" : "");
371} 372}
372 373
373int smart_cmd_simple(int fd, enum SmartCommand command, __u8 val0, bool show_error) { 374int smart_cmd_simple(int fd, enum SmartCommand command, uint8_t val0, bool show_error) {
374 int e = STATE_UNKNOWN; 375 int e = STATE_UNKNOWN;
375#ifdef __linux__ 376#ifdef __linux__
376 __u8 args[4]; 377 uint8_t args[4];
377 args[0] = WIN_SMART; 378 args[0] = WIN_SMART;
378 args[1] = val0; 379 args[1] = val0;
379 args[2] = smart_command[command].value; 380 args[2] = smart_command[command].value;
380 args[3] = 0; 381 args[3] = 0;
381 if (ioctl(fd, HDIO_DRIVE_CMD, &args)) { 382 if (ioctl(fd, HDIO_DRIVE_CMD, &args)) {
382 e = STATE_CRITICAL; 383 e = STATE_CRITICAL;
383 if (show_error) 384 if (show_error) {
384 printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno)); 385 printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno));
386 }
385 } else { 387 } else {
386 e = STATE_OK; 388 e = STATE_OK;
387 if (show_error) 389 if (show_error) {
388 printf(_("OK - Command sent (%s)\n"), smart_command[command].text); 390 printf(_("OK - Command sent (%s)\n"), smart_command[command].text);
391 }
389 } 392 }
390 393
391#endif /* __linux__ */ 394#endif /* __linux__ */
@@ -401,20 +404,24 @@ int smart_cmd_simple(int fd, enum SmartCommand command, __u8 val0, bool show_err
401 req.sec_count = val0; 404 req.sec_count = val0;
402 405
403 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) { 406 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
404 if (req.retsts != ATACMD_OK) 407 if (req.retsts != ATACMD_OK) {
405 errno = ENODEV; 408 errno = ENODEV;
406 if (req.cylinder != WDSMART_CYL) 409 }
410 if (req.cylinder != WDSMART_CYL) {
407 errno = ENODEV; 411 errno = ENODEV;
412 }
408 } 413 }
409 414
410 if (errno != 0) { 415 if (errno != 0) {
411 e = STATE_CRITICAL; 416 e = STATE_CRITICAL;
412 if (show_error) 417 if (show_error) {
413 printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno)); 418 printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno));
419 }
414 } else { 420 } else {
415 e = STATE_OK; 421 e = STATE_OK;
416 if (show_error) 422 if (show_error) {
417 printf(_("OK - Command sent (%s)\n"), smart_command[command].text); 423 printf(_("OK - Command sent (%s)\n"), smart_command[command].text);
424 }
418 } 425 }
419 426
420#endif /* __NetBSD__ */ 427#endif /* __NetBSD__ */
@@ -424,7 +431,7 @@ int smart_cmd_simple(int fd, enum SmartCommand command, __u8 val0, bool show_err
424int smart_read_thresholds(int fd, thresholds_t *thresholds) { 431int smart_read_thresholds(int fd, thresholds_t *thresholds) {
425#ifdef __linux__ 432#ifdef __linux__
426 int e; 433 int e;
427 __u8 args[4 + 512]; 434 uint8_t args[4 + 512];
428 args[0] = WIN_SMART; 435 args[0] = WIN_SMART;
429 args[1] = 0; 436 args[1] = 0;
430 args[2] = SMART_READ_THRESHOLDS; 437 args[2] = SMART_READ_THRESHOLDS;
@@ -452,8 +459,9 @@ int smart_read_thresholds(int fd, thresholds_t *thresholds) {
452 req.cylinder = WDSMART_CYL; 459 req.cylinder = WDSMART_CYL;
453 460
454 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) { 461 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
455 if (req.retsts != ATACMD_OK) 462 if (req.retsts != ATACMD_OK) {
456 errno = ENODEV; 463 errno = ENODEV;
464 }
457 } 465 }
458 466
459 if (errno != 0) { 467 if (errno != 0) {
diff --git a/plugins/check_ldap.c b/plugins/check_ldap.c
index 597644bd..1b2e2826 100644
--- a/plugins/check_ldap.c
+++ b/plugins/check_ldap.c
@@ -27,12 +27,11 @@
27 *****************************************************************************/ 27 *****************************************************************************/
28 28
29/* progname may be check_ldaps */ 29/* progname may be check_ldaps */
30char *progname = "check_ldap"; 30#include "output.h"
31const char *copyright = "2000-2024";
32const char *email = "devel@monitoring-plugins.org";
33
34#include "common.h" 31#include "common.h"
35#include "netutils.h" 32#include "netutils.h"
33#include "perfdata.h"
34#include "thresholds.h"
36#include "utils.h" 35#include "utils.h"
37#include "check_ldap.d/config.h" 36#include "check_ldap.d/config.h"
38 37
@@ -41,6 +40,10 @@ const char *email = "devel@monitoring-plugins.org";
41#define LDAP_DEPRECATED 1 40#define LDAP_DEPRECATED 1
42#include <ldap.h> 41#include <ldap.h>
43 42
43char *progname = "check_ldap";
44const char *copyright = "2000-2024";
45const char *email = "devel@monitoring-plugins.org";
46
44enum { 47enum {
45 DEFAULT_PORT = 389 48 DEFAULT_PORT = 389
46}; 49};
@@ -79,6 +82,10 @@ int main(int argc, char *argv[]) {
79 82
80 const check_ldap_config config = tmp_config.config; 83 const check_ldap_config config = tmp_config.config;
81 84
85 if (config.output_format_is_set) {
86 mp_set_format(config.output_format);
87 }
88
82 /* initialize alarm signal handling */ 89 /* initialize alarm signal handling */
83 signal(SIGALRM, socket_timeout_alarm_handler); 90 signal(SIGALRM, socket_timeout_alarm_handler);
84 91
@@ -89,96 +96,172 @@ int main(int argc, char *argv[]) {
89 struct timeval start_time; 96 struct timeval start_time;
90 gettimeofday(&start_time, NULL); 97 gettimeofday(&start_time, NULL);
91 98
99 mp_check overall = mp_check_init();
100
92 LDAP *ldap_connection; 101 LDAP *ldap_connection;
93 /* initialize ldap */ 102 /* initialize ldap */
103 {
94#ifdef HAVE_LDAP_INIT 104#ifdef HAVE_LDAP_INIT
95 if (!(ldap_connection = ldap_init(config.ld_host, config.ld_port))) { 105 mp_subcheck sc_ldap_init = mp_subcheck_init();
96 printf("Could not connect to the server at port %i\n", config.ld_port); 106 if (!(ldap_connection = ldap_init(config.ld_host, config.ld_port))) {
97 return STATE_CRITICAL; 107 xasprintf(&sc_ldap_init.output, "could not connect to the server at port %i",
98 } 108 config.ld_port);
109 sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_CRITICAL);
110 mp_add_subcheck_to_check(&overall, sc_ldap_init);
111 mp_exit(overall);
112 } else {
113 xasprintf(&sc_ldap_init.output, "connected to the server at port %i", config.ld_port);
114 sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_OK);
115 mp_add_subcheck_to_check(&overall, sc_ldap_init);
116 }
99#else 117#else
100 if (!(ld = ldap_open(config.ld_host, config.ld_port))) { 118 mp_subcheck sc_ldap_init = mp_subcheck_init();
101 if (verbose) { 119 if (!(ld = ldap_open(config.ld_host, config.ld_port))) {
102 ldap_perror(ldap_connection, "ldap_open"); 120 if (verbose) {
121 ldap_perror(ldap_connection, "ldap_open");
122 }
123 xasprintf(&sc_ldap_init.output, "Could not connect to the server at port %i"), config.ld_port);
124 sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_CRITICAL);
125 mp_add_subcheck_to_check(&overall, sc_ldap_init);
126 mp_exit(overall);
127 } else {
128 xasprintf(&sc_ldap_init.output, "connected to the server at port %i", config.ld_port);
129 sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_OK);
130 mp_add_subcheck_to_check(&overall, sc_ldap_init);
103 } 131 }
104 printf(_("Could not connect to the server at port %i\n"), config.ld_port);
105 return STATE_CRITICAL;
106 }
107#endif /* HAVE_LDAP_INIT */ 132#endif /* HAVE_LDAP_INIT */
133 }
108 134
109#ifdef HAVE_LDAP_SET_OPTION 135#ifdef HAVE_LDAP_SET_OPTION
110 /* set ldap options */ 136 /* set ldap options */
111 if (ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &config.ld_protocol) != LDAP_OPT_SUCCESS) { 137 mp_subcheck sc_ldap_set_opts = mp_subcheck_init();
112 printf(_("Could not set protocol version %d\n"), config.ld_protocol); 138 if (ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &config.ld_protocol) !=
113 return STATE_CRITICAL; 139 LDAP_OPT_SUCCESS) {
140 xasprintf(&sc_ldap_set_opts.output, "Could not set protocol version %d",
141 config.ld_protocol);
142 sc_ldap_set_opts = mp_set_subcheck_state(sc_ldap_set_opts, STATE_CRITICAL);
143 mp_add_subcheck_to_check(&overall, sc_ldap_set_opts);
144 mp_exit(overall);
145 } else {
146 xasprintf(&sc_ldap_set_opts.output, "set protocol version %d", config.ld_protocol);
147 sc_ldap_set_opts = mp_set_subcheck_state(sc_ldap_set_opts, STATE_OK);
148 mp_add_subcheck_to_check(&overall, sc_ldap_set_opts);
114 } 149 }
115#endif 150#endif
116 151
117 int version = 3; 152 int version = 3;
118 int tls; 153 int tls;
119 if (config.ld_port == LDAPS_PORT || config.ssl_on_connect) { 154 {
155 if (config.ld_port == LDAPS_PORT || config.ssl_on_connect) {
120#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS) 156#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
121 /* ldaps: set option tls */ 157 /* ldaps: set option tls */
122 tls = LDAP_OPT_X_TLS_HARD; 158 tls = LDAP_OPT_X_TLS_HARD;
123 159
124 if (ldap_set_option(ldap_connection, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) { 160 mp_subcheck sc_ldap_tls_init = mp_subcheck_init();
125 if (verbose) { 161 if (ldap_set_option(ldap_connection, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) {
126 ldap_perror(ldap_connection, "ldaps_option"); 162 if (verbose) {
163 ldap_perror(ldap_connection, "ldaps_option");
164 }
165 xasprintf(&sc_ldap_tls_init.output, "could not init TLS at port %i!",
166 config.ld_port);
167 sc_ldap_tls_init = mp_set_subcheck_state(sc_ldap_tls_init, STATE_CRITICAL);
168 mp_add_subcheck_to_check(&overall, sc_ldap_tls_init);
169 mp_exit(overall);
170 } else {
171 xasprintf(&sc_ldap_tls_init.output, "initiated TLS at port %i!", config.ld_port);
172 sc_ldap_tls_init = mp_set_subcheck_state(sc_ldap_tls_init, STATE_OK);
173 mp_add_subcheck_to_check(&overall, sc_ldap_tls_init);
127 } 174 }
128 printf(_("Could not init TLS at port %i!\n"), config.ld_port);
129 return STATE_CRITICAL;
130 }
131#else 175#else
132 printf(_("TLS not supported by the libraries!\n")); 176 printf(_("TLS not supported by the libraries!\n"));
133 return STATE_CRITICAL; 177 exit(STATE_CRITICAL);
134#endif /* LDAP_OPT_X_TLS */ 178#endif /* LDAP_OPT_X_TLS */
135 } else if (config.starttls) { 179 } else if (config.starttls) {
136#if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S) 180#if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S)
137 /* ldap with startTLS: set option version */ 181 /* ldap with startTLS: set option version */
138 if (ldap_get_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) { 182 if (ldap_get_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version) ==
139 if (version < LDAP_VERSION3) { 183 LDAP_OPT_SUCCESS) {
140 version = LDAP_VERSION3; 184 if (version < LDAP_VERSION3) {
141 ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version); 185 version = LDAP_VERSION3;
186 ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version);
187 }
142 } 188 }
143 } 189 /* call start_tls */
144 /* call start_tls */ 190 mp_subcheck sc_ldap_starttls = mp_subcheck_init();
145 if (ldap_start_tls_s(ldap_connection, NULL, NULL) != LDAP_SUCCESS) { 191 if (ldap_start_tls_s(ldap_connection, NULL, NULL) != LDAP_SUCCESS) {
146 if (verbose) { 192 if (verbose) {
147 ldap_perror(ldap_connection, "ldap_start_tls"); 193 ldap_perror(ldap_connection, "ldap_start_tls");
194 }
195 xasprintf(&sc_ldap_starttls.output, "could not init STARTTLS at port %i!",
196 config.ld_port);
197 sc_ldap_starttls = mp_set_subcheck_state(sc_ldap_starttls, STATE_CRITICAL);
198 mp_add_subcheck_to_check(&overall, sc_ldap_starttls);
199 mp_exit(overall);
200 } else {
201 xasprintf(&sc_ldap_starttls.output, "initiated STARTTLS at port %i!",
202 config.ld_port);
203 sc_ldap_starttls = mp_set_subcheck_state(sc_ldap_starttls, STATE_OK);
204 mp_add_subcheck_to_check(&overall, sc_ldap_starttls);
148 } 205 }
149 printf(_("Could not init startTLS at port %i!\n"), config.ld_port);
150 return STATE_CRITICAL;
151 }
152#else 206#else
153 printf(_("startTLS not supported by the library, needs LDAPv3!\n")); 207 printf(_("startTLS not supported by the library, needs LDAPv3!\n"));
154 return STATE_CRITICAL; 208 exit(STATE_CRITICAL);
155#endif /* HAVE_LDAP_START_TLS_S */ 209#endif /* HAVE_LDAP_START_TLS_S */
210 }
156 } 211 }
157 212
158 /* bind to the ldap server */ 213 /* bind to the ldap server */
159 if (ldap_bind_s(ldap_connection, config.ld_binddn, config.ld_passwd, LDAP_AUTH_SIMPLE) != LDAP_SUCCESS) { 214 {
160 if (verbose) { 215 mp_subcheck sc_ldap_bind = mp_subcheck_init();
161 ldap_perror(ldap_connection, "ldap_bind"); 216 int ldap_error =
217 ldap_bind_s(ldap_connection, config.ld_binddn, config.ld_passwd, LDAP_AUTH_SIMPLE);
218 if (ldap_error != LDAP_SUCCESS) {
219 if (verbose) {
220 ldap_perror(ldap_connection, "ldap_bind");
221 }
222
223 xasprintf(&sc_ldap_bind.output, "could not bind to the LDAP server: %s",
224 ldap_err2string(ldap_error));
225 sc_ldap_bind = mp_set_subcheck_state(sc_ldap_bind, STATE_CRITICAL);
226 mp_add_subcheck_to_check(&overall, sc_ldap_bind);
227 mp_exit(overall);
228 } else {
229 xasprintf(&sc_ldap_bind.output, "execute bind to the LDAP server");
230 sc_ldap_bind = mp_set_subcheck_state(sc_ldap_bind, STATE_OK);
231 mp_add_subcheck_to_check(&overall, sc_ldap_bind);
162 } 232 }
163 printf(_("Could not bind to the LDAP server\n"));
164 return STATE_CRITICAL;
165 } 233 }
166 234
167 LDAPMessage *result; 235 LDAPMessage *result;
168 int num_entries = 0;
169 /* do a search of all objectclasses in the base dn */ 236 /* do a search of all objectclasses in the base dn */
170 if (ldap_search_s(ldap_connection, config.ld_base, 237 {
171 (config.crit_entries != NULL || config.warn_entries != NULL) ? LDAP_SCOPE_SUBTREE : LDAP_SCOPE_BASE, config.ld_attr, 238 mp_subcheck sc_ldap_search = mp_subcheck_init();
172 NULL, 0, &result) != LDAP_SUCCESS) { 239 int ldap_error = ldap_search_s(
173 if (verbose) { 240 ldap_connection, config.ld_base,
174 ldap_perror(ldap_connection, "ldap_search"); 241 (config.entries_thresholds.warning_is_set || config.entries_thresholds.critical_is_set)
242 ? LDAP_SCOPE_SUBTREE
243 : LDAP_SCOPE_BASE,
244 config.ld_attr, NULL, 0, &result);
245
246 if (ldap_error != LDAP_SUCCESS) {
247 if (verbose) {
248 ldap_perror(ldap_connection, "ldap_search");
249 }
250 xasprintf(&sc_ldap_search.output, "could not search/find objectclasses in %s: %s",
251 config.ld_base, ldap_err2string(ldap_error));
252 sc_ldap_search = mp_set_subcheck_state(sc_ldap_search, STATE_CRITICAL);
253 mp_add_subcheck_to_check(&overall, sc_ldap_search);
254 mp_exit(overall);
255 } else {
256 xasprintf(&sc_ldap_search.output, "search/find objectclasses in %s", config.ld_base);
257 sc_ldap_search = mp_set_subcheck_state(sc_ldap_search, STATE_OK);
258 mp_add_subcheck_to_check(&overall, sc_ldap_search);
175 } 259 }
176 printf(_("Could not search/find objectclasses in %s\n"), config.ld_base);
177 return STATE_CRITICAL;
178 } 260 }
179 261
180 if (config.crit_entries != NULL || config.warn_entries != NULL) { 262 int num_entries = ldap_count_entries(ldap_connection, result);
181 num_entries = ldap_count_entries(ldap_connection, result); 263 if (verbose) {
264 printf("entries found: %d\n", num_entries);
182 } 265 }
183 266
184 /* unbind from the ldap server */ 267 /* unbind from the ldap server */
@@ -188,48 +271,50 @@ int main(int argc, char *argv[]) {
188 alarm(0); 271 alarm(0);
189 272
190 /* calculate the elapsed time and compare to thresholds */ 273 /* calculate the elapsed time and compare to thresholds */
191
192 long microsec = deltime(start_time); 274 long microsec = deltime(start_time);
193 double elapsed_time = (double)microsec / 1.0e6; 275 double elapsed_time = (double)microsec / 1.0e6;
194 mp_state_enum status = STATE_UNKNOWN; 276 mp_perfdata pd_connection_time = perfdata_init();
195 if (config.crit_time_set && elapsed_time > config.crit_time) { 277 pd_connection_time.label = "time";
196 status = STATE_CRITICAL; 278 pd_connection_time.value = mp_create_pd_value(elapsed_time);
197 } else if (config.warn_time_set && elapsed_time > config.warn_time) { 279 pd_connection_time = mp_pd_set_thresholds(pd_connection_time, config.connection_time_threshold);
198 status = STATE_WARNING;
199 } else {
200 status = STATE_OK;
201 }
202 280
203 if (config.entries_thresholds != NULL) { 281 mp_subcheck sc_connection_time = mp_subcheck_init();
204 if (verbose) { 282 mp_add_perfdata_to_subcheck(&sc_connection_time, pd_connection_time);
205 printf("entries found: %d\n", num_entries); 283
206 print_thresholds("entry thresholds", config.entries_thresholds); 284 mp_state_enum connection_time_state = mp_get_pd_status(pd_connection_time);
207 } 285 sc_connection_time = mp_set_subcheck_state(sc_connection_time, connection_time_state);
208 mp_state_enum status_entries = get_status(num_entries, config.entries_thresholds);
209 if (status_entries == STATE_CRITICAL) {
210 status = STATE_CRITICAL;
211 } else if (status != STATE_CRITICAL) {
212 status = status_entries;
213 }
214 }
215 286
216 /* print out the result */ 287 if (connection_time_state == STATE_OK) {
217 if (config.crit_entries != NULL || config.warn_entries != NULL) { 288 xasprintf(&sc_connection_time.output, "connection time %.3fs is within thresholds",
218 printf(_("LDAP %s - found %d entries in %.3f seconds|%s %s\n"), state_text(status), num_entries, elapsed_time, 289 elapsed_time);
219 fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time, config.crit_time_set, config.crit_time, true, 0,
220 false, 0),
221 sperfdata("entries", (double)num_entries, "", config.warn_entries, config.crit_entries, true, 0.0, false, 0.0));
222 } else { 290 } else {
223 printf(_("LDAP %s - %.3f seconds response time|%s\n"), state_text(status), elapsed_time, 291 xasprintf(&sc_connection_time.output, "connection time %.3fs is violating thresholds",
224 fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time, config.crit_time_set, config.crit_time, true, 0, 292 elapsed_time);
225 false, 0));
226 } 293 }
227 294
228 exit(status); 295 mp_add_subcheck_to_check(&overall, sc_connection_time);
296
297 mp_perfdata pd_num_entries = perfdata_init();
298 pd_num_entries.label = "entries";
299 pd_num_entries.value = mp_create_pd_value(num_entries);
300 pd_num_entries = mp_pd_set_thresholds(pd_num_entries, config.entries_thresholds);
301
302 mp_subcheck sc_num_entries = mp_subcheck_init();
303 mp_add_perfdata_to_subcheck(&sc_num_entries, pd_num_entries);
304 xasprintf(&sc_num_entries.output, "found %d entries", num_entries);
305 sc_num_entries = mp_set_subcheck_state(sc_num_entries, mp_get_pd_status(pd_num_entries));
306
307 mp_add_subcheck_to_check(&overall, sc_num_entries);
308
309 mp_exit(overall);
229} 310}
230 311
231/* process command-line arguments */ 312/* process command-line arguments */
232check_ldap_config_wrapper process_arguments(int argc, char **argv) { 313check_ldap_config_wrapper process_arguments(int argc, char **argv) {
314 enum {
315 output_format_index = CHAR_MAX + 1,
316 };
317
233 /* initialize the long option struct */ 318 /* initialize the long option struct */
234 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, 319 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
235 {"version", no_argument, 0, 'V'}, 320 {"version", no_argument, 0, 'V'},
@@ -253,6 +338,7 @@ check_ldap_config_wrapper process_arguments(int argc, char **argv) {
253 {"warn-entries", required_argument, 0, 'W'}, 338 {"warn-entries", required_argument, 0, 'W'},
254 {"crit-entries", required_argument, 0, 'C'}, 339 {"crit-entries", required_argument, 0, 'C'},
255 {"verbose", no_argument, 0, 'v'}, 340 {"verbose", no_argument, 0, 'v'},
341 {"output-format", required_argument, 0, output_format_index},
256 {0, 0, 0, 0}}; 342 {0, 0, 0, 0}};
257 343
258 check_ldap_config_wrapper result = { 344 check_ldap_config_wrapper result = {
@@ -273,7 +359,8 @@ check_ldap_config_wrapper process_arguments(int argc, char **argv) {
273 359
274 int option = 0; 360 int option = 0;
275 while (true) { 361 while (true) {
276 int option_index = getopt_long(argc, argv, "hvV234TS6t:c:w:H:b:p:a:D:P:C:W:", longopts, &option); 362 int option_index =
363 getopt_long(argc, argv, "hvV234TS6t:c:w:H:b:p:a:D:P:C:W:", longopts, &option);
277 364
278 if (option_index == -1 || option_index == EOF) { 365 if (option_index == -1 || option_index == EOF) {
279 break; 366 break;
@@ -311,20 +398,38 @@ check_ldap_config_wrapper process_arguments(int argc, char **argv) {
311 case 'P': 398 case 'P':
312 result.config.ld_passwd = optarg; 399 result.config.ld_passwd = optarg;
313 break; 400 break;
314 case 'w': 401 case 'w': {
315 result.config.warn_time_set = true; 402 mp_range_parsed tmp = mp_parse_range_string(optarg);
316 result.config.warn_time = strtod(optarg, NULL); 403 if (tmp.error != MP_PARSING_SUCCES) {
317 break; 404 die(STATE_UNKNOWN, "failed to parse warning connection time threshold");
318 case 'c': 405 }
319 result.config.crit_time_set = true; 406 result.config.connection_time_threshold =
320 result.config.crit_time = strtod(optarg, NULL); 407 mp_thresholds_set_warn(result.config.connection_time_threshold, tmp.range);
321 break; 408 } break;
322 case 'W': 409 case 'c': {
323 result.config.warn_entries = optarg; 410 mp_range_parsed tmp = mp_parse_range_string(optarg);
324 break; 411 if (tmp.error != MP_PARSING_SUCCES) {
325 case 'C': 412 die(STATE_UNKNOWN, "failed to parse critical connection time threshold");
326 result.config.crit_entries = optarg; 413 }
327 break; 414 result.config.connection_time_threshold =
415 mp_thresholds_set_crit(result.config.connection_time_threshold, tmp.range);
416 } break;
417 case 'W': {
418 mp_range_parsed tmp = mp_parse_range_string(optarg);
419 if (tmp.error != MP_PARSING_SUCCES) {
420 die(STATE_UNKNOWN, "failed to parse number of entries warning threshold");
421 }
422 result.config.entries_thresholds =
423 mp_thresholds_set_warn(result.config.entries_thresholds, tmp.range);
424 } break;
425 case 'C': {
426 mp_range_parsed tmp = mp_parse_range_string(optarg);
427 if (tmp.error != MP_PARSING_SUCCES) {
428 die(STATE_UNKNOWN, "failed to parse number of entries critical threshold");
429 }
430 result.config.entries_thresholds =
431 mp_thresholds_set_crit(result.config.entries_thresholds, tmp.range);
432 } break;
328#ifdef HAVE_LDAP_SET_OPTION 433#ifdef HAVE_LDAP_SET_OPTION
329 case '2': 434 case '2':
330 result.config.ld_protocol = 2; 435 result.config.ld_protocol = 2;
@@ -363,6 +468,18 @@ check_ldap_config_wrapper process_arguments(int argc, char **argv) {
363 usage(_("IPv6 support not available\n")); 468 usage(_("IPv6 support not available\n"));
364#endif 469#endif
365 break; 470 break;
471 case output_format_index: {
472 parsed_output_format parser = mp_parse_output_format(optarg);
473 if (!parser.parsing_success) {
474 // TODO List all available formats here, maybe add anothoer usage function
475 printf("Invalid output format: %s\n", optarg);
476 exit(STATE_UNKNOWN);
477 }
478
479 result.config.output_format_is_set = true;
480 result.config.output_format = parser.output_format;
481 break;
482 }
366 default: 483 default:
367 usage5(); 484 usage5();
368 } 485 }
@@ -381,7 +498,8 @@ check_ldap_config_wrapper process_arguments(int argc, char **argv) {
381 result.config.ld_port = DEFAULT_PORT; 498 result.config.ld_port = DEFAULT_PORT;
382 } 499 }
383 500
384 if (strstr(argv[0], "check_ldaps") && !result.config.starttls && !result.config.ssl_on_connect) { 501 if (strstr(argv[0], "check_ldaps") && !result.config.starttls &&
502 !result.config.ssl_on_connect) {
385 result.config.starttls = true; 503 result.config.starttls = true;
386 } 504 }
387 505
@@ -397,10 +515,6 @@ check_ldap_config_wrapper validate_arguments(check_ldap_config_wrapper config_wr
397 usage4(_("Please specify the LDAP base\n")); 515 usage4(_("Please specify the LDAP base\n"));
398 } 516 }
399 517
400 if (config_wrapper.config.crit_entries != NULL || config_wrapper.config.warn_entries != NULL) {
401 set_thresholds(&config_wrapper.config.entries_thresholds, config_wrapper.config.warn_entries, config_wrapper.config.crit_entries);
402 }
403
404 if (config_wrapper.config.ld_passwd == NULL) { 518 if (config_wrapper.config.ld_passwd == NULL) {
405 config_wrapper.config.ld_passwd = getenv("LDAP_PASSWORD"); 519 config_wrapper.config.ld_passwd = getenv("LDAP_PASSWORD");
406 } 520 }
@@ -435,11 +549,13 @@ void print_help(void) {
435 printf(" %s\n", "-D [--bind]"); 549 printf(" %s\n", "-D [--bind]");
436 printf(" %s\n", _("ldap bind DN (if required)")); 550 printf(" %s\n", _("ldap bind DN (if required)"));
437 printf(" %s\n", "-P [--pass]"); 551 printf(" %s\n", "-P [--pass]");
438 printf(" %s\n", _("ldap password (if required, or set the password through environment variable 'LDAP_PASSWORD')")); 552 printf(" %s\n", _("ldap password (if required, or set the password through environment "
553 "variable 'LDAP_PASSWORD')"));
439 printf(" %s\n", "-T [--starttls]"); 554 printf(" %s\n", "-T [--starttls]");
440 printf(" %s\n", _("use starttls mechanism introduced in protocol version 3")); 555 printf(" %s\n", _("use starttls mechanism introduced in protocol version 3"));
441 printf(" %s\n", "-S [--ssl]"); 556 printf(" %s\n", "-S [--ssl]");
442 printf(" %s %i\n", _("use ldaps (ldap v2 ssl method). this also sets the default port to"), LDAPS_PORT); 557 printf(" %s %i\n", _("use ldaps (ldap v2 ssl method). this also sets the default port to"),
558 LDAPS_PORT);
443 559
444#ifdef HAVE_LDAP_SET_OPTION 560#ifdef HAVE_LDAP_SET_OPTION
445 printf(" %s\n", "-2 [--ver2]"); 561 printf(" %s\n", "-2 [--ver2]");
@@ -459,13 +575,16 @@ void print_help(void) {
459 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 575 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
460 576
461 printf(UT_VERBOSE); 577 printf(UT_VERBOSE);
578 printf(UT_OUTPUT_FORMAT);
462 579
463 printf("\n"); 580 printf("\n");
464 printf("%s\n", _("Notes:")); 581 printf("%s\n", _("Notes:"));
465 printf(" %s\n", _("If this plugin is called via 'check_ldaps', method 'STARTTLS' will be")); 582 printf(" %s\n", _("If this plugin is called via 'check_ldaps', method 'STARTTLS' will be"));
466 printf(_(" implied (using default port %i) unless --port=636 is specified. In that case\n"), DEFAULT_PORT); 583 printf(_(" implied (using default port %i) unless --port=636 is specified. In that case\n"),
584 DEFAULT_PORT);
467 printf(" %s\n", _("'SSL on connect' will be used no matter how the plugin was called.")); 585 printf(" %s\n", _("'SSL on connect' will be used no matter how the plugin was called."));
468 printf(" %s\n", _("This detection is deprecated, please use 'check_ldap' with the '--starttls' or '--ssl' flags")); 586 printf(" %s\n", _("This detection is deprecated, please use 'check_ldap' with the '--starttls' "
587 "or '--ssl' flags"));
469 printf(" %s\n", _("to define the behaviour explicitly instead.")); 588 printf(" %s\n", _("to define the behaviour explicitly instead."));
470 printf(" %s\n", _("The parameters --warn-entries and --crit-entries are optional.")); 589 printf(" %s\n", _("The parameters --warn-entries and --crit-entries are optional."));
471 590
diff --git a/plugins/check_ldap.d/config.h b/plugins/check_ldap.d/config.h
index c8a40610..50191725 100644
--- a/plugins/check_ldap.d/config.h
+++ b/plugins/check_ldap.d/config.h
@@ -1,6 +1,7 @@
1#pragma once 1#pragma once
2 2
3#include "../../config.h" 3#include "../../config.h"
4#include "output.h"
4#include "thresholds.h" 5#include "thresholds.h"
5#include <stddef.h> 6#include <stddef.h>
6 7
@@ -25,13 +26,11 @@ typedef struct {
25 int ld_protocol; 26 int ld_protocol;
26#endif 27#endif
27 28
28 char *warn_entries; 29 mp_thresholds entries_thresholds;
29 char *crit_entries; 30 mp_thresholds connection_time_threshold;
30 thresholds *entries_thresholds; 31
31 bool warn_time_set; 32 bool output_format_is_set;
32 double warn_time; 33 mp_output_format output_format;
33 bool crit_time_set;
34 double crit_time;
35} check_ldap_config; 34} check_ldap_config;
36 35
37check_ldap_config check_ldap_config_init() { 36check_ldap_config check_ldap_config_init() {
@@ -48,13 +47,10 @@ check_ldap_config check_ldap_config_init() {
48 .ld_protocol = DEFAULT_PROTOCOL, 47 .ld_protocol = DEFAULT_PROTOCOL,
49#endif 48#endif
50 49
51 .warn_entries = NULL, 50 .entries_thresholds = mp_thresholds_init(),
52 .crit_entries = NULL, 51 .connection_time_threshold = mp_thresholds_init(),
53 .entries_thresholds = NULL, 52
54 .warn_time_set = false, 53 .output_format_is_set = false,
55 .warn_time = 0,
56 .crit_time_set = false,
57 .crit_time = 0,
58 }; 54 };
59 return tmp; 55 return tmp;
60} 56}
diff --git a/plugins/check_load.c b/plugins/check_load.c
index 1431d130..644cd604 100644
--- a/plugins/check_load.c
+++ b/plugins/check_load.c
@@ -1,350 +1,430 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_load plugin 3 * Monitoring check_load plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2007 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_load plugin 10 * This file contains the check_load plugin
11* 11 *
12* This plugin tests the current system load average. 12 * This plugin tests the current system load average.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31const char *progname = "check_load"; 31const char *progname = "check_load";
32const char *copyright = "1999-2022"; 32const char *copyright = "1999-2022";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "./common.h" 35#include "./common.h"
36#include <string.h>
36#include "./runcmd.h" 37#include "./runcmd.h"
37#include "./utils.h" 38#include "./utils.h"
38#include "./popen.h" 39#include "./popen.h"
40#include "../lib/states.h"
41#include "../lib/output.h"
42#include "../lib/perfdata.h"
43#include "../lib/thresholds.h"
44#include "check_load.d/config.h"
39 45
40#include <string.h> 46// getloadavg comes from gnulib
41 47#include "../gl/stdlib.h"
42#ifdef HAVE_SYS_LOADAVG_H
43#include <sys/loadavg.h>
44#endif
45 48
46/* needed for compilation under NetBSD, as suggested by Andy Doran */ 49/* needed for compilation under NetBSD, as suggested by Andy Doran */
47#ifndef LOADAVG_1MIN 50#ifndef LOADAVG_1MIN
48#define LOADAVG_1MIN 0 51# define LOADAVG_1MIN 0
49#define LOADAVG_5MIN 1 52# define LOADAVG_5MIN 1
50#define LOADAVG_15MIN 2 53# define LOADAVG_15MIN 2
51#endif /* !defined LOADAVG_1MIN */ 54#endif /* !defined LOADAVG_1MIN */
52 55
56typedef struct {
57 int errorcode;
58 check_load_config config;
59} check_load_config_wrapper;
60static check_load_config_wrapper process_arguments(int argc, char **argv);
61
62void print_help(void);
63void print_usage(void);
64typedef struct {
65 int errorcode;
66 char **top_processes;
67} top_processes_result;
68static top_processes_result print_top_consuming_processes(unsigned long n_procs_to_show);
69
70typedef struct {
71 mp_range load[3];
72} parsed_thresholds;
73static parsed_thresholds get_threshold(char *arg) {
74 size_t index;
75 char *str = arg;
76 char *tmp_pointer;
77 bool valid = false;
78
79 parsed_thresholds result = {
80 .load =
81 {
82 mp_range_init(),
83 mp_range_init(),
84 mp_range_init(),
85 },
86 };
53 87
54static int process_arguments (int argc, char **argv); 88 size_t arg_length = strlen(arg);
55static int validate_arguments (void); 89 for (index = 0; index < 3; index++) {
56void print_help (void); 90 double tmp = strtod(str, &tmp_pointer);
57void print_usage (void); 91 if (tmp_pointer == str) {
58static int print_top_consuming_processes(); 92 break;
59 93 }
60static int n_procs_to_show = 0;
61
62/* strictly for pretty-print usage in loops */
63static const int nums[3] = { 1, 5, 15 };
64
65/* provide some fairly sane defaults */
66double wload[3] = { 0.0, 0.0, 0.0 };
67double cload[3] = { 0.0, 0.0, 0.0 };
68#define la1 la[0]
69#define la5 la[1]
70#define la15 la[2]
71
72char *status_line;
73bool take_into_account_cpus = false;
74
75static void
76get_threshold(char *arg, double *th)
77{
78 size_t i, n;
79 int valid = 0;
80 char *str = arg, *p;
81 94
82 n = strlen(arg); 95 result.load[index] = mp_range_set_end(result.load[index], mp_create_pd_value(tmp));
83 for(i = 0; i < 3; i++) {
84 th[i] = strtod(str, &p);
85 if(p == str) break;
86 96
87 valid = 1; 97 valid = true;
88 str = p + 1; 98 str = tmp_pointer + 1;
89 if(n <= (size_t)(str - arg)) break; 99 if (arg_length <= (size_t)(str - arg)) {
100 break;
101 }
90 } 102 }
91 103
92 /* empty argument or non-floatish, so warn about it and die */ 104 /* empty argument or non-floatish, so warn about it and die */
93 if(!i && !valid) usage (_("Warning threshold must be float or float triplet!\n")); 105 if (!index && !valid) {
106 usage(_("Warning threshold must be float or float triplet!\n"));
107 }
94 108
95 if(i != 2) { 109 if (index != 2) {
96 /* one or more numbers were given, so fill array with last 110 /* one or more numbers were given, so fill array with last
97 * we got (most likely to NOT produce the least expected result) */ 111 * we got (most likely to NOT produce the least expected result) */
98 for(n = i; n < 3; n++) th[n] = th[i]; 112 for (size_t tmp_index = index; tmp_index < 3; tmp_index++) {
113 result.load[tmp_index] = result.load[index];
114 }
99 } 115 }
116 return result;
100} 117}
101 118
102 119int main(int argc, char **argv) {
103int 120 setlocale(LC_ALL, "");
104main (int argc, char **argv) 121 bindtextdomain(PACKAGE, LOCALEDIR);
105{ 122 textdomain(PACKAGE);
106 int result = -1;
107 int i;
108 long numcpus;
109
110 double la[3] = { 0.0, 0.0, 0.0 }; /* NetBSD complains about uninitialized arrays */
111#ifndef HAVE_GETLOADAVG
112 char input_buffer[MAX_INPUT_BUFFER];
113#endif
114
115 setlocale (LC_ALL, "");
116 bindtextdomain (PACKAGE, LOCALEDIR);
117 textdomain (PACKAGE);
118 setlocale(LC_NUMERIC, "POSIX"); 123 setlocale(LC_NUMERIC, "POSIX");
119 124
120 /* Parse extra opts if any */ 125 /* Parse extra opts if any */
121 argv = np_extra_opts (&argc, argv, progname); 126 argv = np_extra_opts(&argc, argv, progname);
122 127
123 if (process_arguments (argc, argv) == ERROR) 128 check_load_config_wrapper tmp_config = process_arguments(argc, argv);
124 usage4 (_("Could not parse arguments")); 129 if (tmp_config.errorcode == ERROR) {
125 130 usage4(_("Could not parse arguments"));
126#ifdef HAVE_GETLOADAVG
127 result = getloadavg (la, 3);
128 if (result != 3)
129 return STATE_UNKNOWN;
130#else
131 child_process = spopen (PATH_TO_UPTIME);
132 if (child_process == NULL) {
133 printf (_("Error opening %s\n"), PATH_TO_UPTIME);
134 return STATE_UNKNOWN;
135 }
136 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
137 if (child_stderr == NULL) {
138 printf (_("Could not open stderr for %s\n"), PATH_TO_UPTIME);
139 }
140 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
141 if(strstr(input_buffer, "load average:")) {
142 sscanf (input_buffer, "%*[^l]load average: %lf, %lf, %lf", &la1, &la5, &la15);
143 }
144 else if(strstr(input_buffer, "load averages:")) {
145 sscanf (input_buffer, "%*[^l]load averages: %lf, %lf, %lf", &la1, &la5, &la15);
146 }
147 else {
148 printf (_("could not parse load from uptime %s: %d\n"), PATH_TO_UPTIME, result);
149 return STATE_UNKNOWN;
150 }
151
152 result = spclose (child_process);
153 if (result) {
154 printf (_("Error code %d returned in %s\n"), result, PATH_TO_UPTIME);
155 return STATE_UNKNOWN;
156 }
157#endif
158
159 if ((la[0] < 0.0) || (la[1] < 0.0) || (la[2] < 0.0)) {
160#ifdef HAVE_GETLOADAVG
161 printf (_("Error in getloadavg()\n"));
162#else
163 printf (_("Error processing %s\n"), PATH_TO_UPTIME);
164#endif
165 return STATE_UNKNOWN;
166 } 131 }
167 132
168 /* we got this far, so assume OK until we've measured */ 133 const check_load_config config = tmp_config.config;
169 result = STATE_OK; 134
135 double load_values[3] = {0, 0, 0};
170 136
171 xasprintf(&status_line, _("load average: %.2f, %.2f, %.2f"), la1, la5, la15); 137 // this should be getloadavg from gnulib, should work everywhereâ„¢
172 xasprintf(&status_line, ("total %s"), status_line); 138 int error = getloadavg(load_values, 3);
139 if (error != 3) {
140 die(STATE_UNKNOWN, _("Failed to retrieve load values"));
141 }
173 142
143 mp_check overall = mp_check_init();
144 if (config.output_format_set) {
145 mp_set_format(config.output_format);
146 }
174 147
175 double scaled_la[3] = { 0.0, 0.0, 0.0 };
176 bool is_using_scaled_load_values = false; 148 bool is_using_scaled_load_values = false;
177 149 long numcpus;
178 if (take_into_account_cpus == true && (numcpus = GET_NUMBER_OF_CPUS()) > 0) { 150 if (config.take_into_account_cpus && ((numcpus = GET_NUMBER_OF_CPUS()) > 0)) {
179 is_using_scaled_load_values = true; 151 is_using_scaled_load_values = true;
180 152
181 scaled_la[0] = la[0] / numcpus; 153 double scaled_la[3] = {
182 scaled_la[1] = la[1] / numcpus; 154 load_values[0] / numcpus,
183 scaled_la[2] = la[2] / numcpus; 155 load_values[1] / numcpus,
156 load_values[2] / numcpus,
157 };
158
159 mp_subcheck scaled_load_sc = mp_subcheck_init();
160 scaled_load_sc = mp_set_subcheck_default_state(scaled_load_sc, STATE_OK);
161 scaled_load_sc.output = "Scaled Load (divided by number of CPUs";
162
163 mp_perfdata pd_scaled_load1 = perfdata_init();
164 pd_scaled_load1.label = "scaled_load1";
165 pd_scaled_load1 = mp_set_pd_value(pd_scaled_load1, scaled_la[0]);
166 pd_scaled_load1 = mp_pd_set_thresholds(pd_scaled_load1, config.th_load[0]);
167
168 mp_subcheck scaled_load_sc1 = mp_subcheck_init();
169 scaled_load_sc1 = mp_set_subcheck_state(scaled_load_sc1, mp_get_pd_status(pd_scaled_load1));
170 mp_add_perfdata_to_subcheck(&scaled_load_sc1, pd_scaled_load1);
171 xasprintf(&scaled_load_sc1.output, "1 Minute: %s",
172 pd_value_to_string(pd_scaled_load1.value));
173 mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc1);
174
175 mp_perfdata pd_scaled_load5 = perfdata_init();
176 pd_scaled_load5.label = "scaled_load5";
177 pd_scaled_load5 = mp_set_pd_value(pd_scaled_load5, scaled_la[1]);
178 pd_scaled_load5 = mp_pd_set_thresholds(pd_scaled_load5, config.th_load[1]);
179
180 mp_subcheck scaled_load_sc5 = mp_subcheck_init();
181 scaled_load_sc5 = mp_set_subcheck_state(scaled_load_sc5, mp_get_pd_status(pd_scaled_load5));
182 mp_add_perfdata_to_subcheck(&scaled_load_sc5, pd_scaled_load5);
183 xasprintf(&scaled_load_sc5.output, "5 Minutes: %s",
184 pd_value_to_string(pd_scaled_load5.value));
185 mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc5);
186
187 mp_perfdata pd_scaled_load15 = perfdata_init();
188 pd_scaled_load15.label = "scaled_load15";
189 pd_scaled_load15 = mp_set_pd_value(pd_scaled_load15, scaled_la[2]);
190 pd_scaled_load15 = mp_pd_set_thresholds(pd_scaled_load15, config.th_load[2]);
191
192 mp_subcheck scaled_load_sc15 = mp_subcheck_init();
193 scaled_load_sc15 =
194 mp_set_subcheck_state(scaled_load_sc15, mp_get_pd_status(pd_scaled_load15));
195 mp_add_perfdata_to_subcheck(&scaled_load_sc15, pd_scaled_load15);
196 xasprintf(&scaled_load_sc15.output, "15 Minutes: %s",
197 pd_value_to_string(pd_scaled_load15.value));
198 mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc15);
199
200 mp_add_subcheck_to_check(&overall, scaled_load_sc);
201 }
202
203 mp_subcheck load_sc = mp_subcheck_init();
204 load_sc = mp_set_subcheck_default_state(load_sc, STATE_OK);
205 load_sc.output = "Total Load";
184 206
185 char *tmp = NULL; 207 mp_perfdata pd_load1 = perfdata_init();
186 xasprintf(&tmp, _("load average: %.2f, %.2f, %.2f"), scaled_la[0], scaled_la[1], scaled_la[2]); 208 pd_load1.label = "load1";
187 xasprintf(&status_line, "scaled %s - %s", tmp, status_line); 209 pd_load1 = mp_set_pd_value(pd_load1, load_values[0]);
210 if (!is_using_scaled_load_values) {
211 pd_load1 = mp_pd_set_thresholds(pd_load1, config.th_load[0]);
188 } 212 }
189 213
190 for(i = 0; i < 3; i++) { 214 mp_subcheck load_sc1 = mp_subcheck_init();
191 if (is_using_scaled_load_values) { 215 load_sc1 = mp_set_subcheck_state(load_sc1, mp_get_pd_status(pd_load1));
192 if(scaled_la[i] > cload[i]) { 216 mp_add_perfdata_to_subcheck(&load_sc1, pd_load1);
193 result = STATE_CRITICAL; 217 xasprintf(&load_sc1.output, "1 Minute: %s", pd_value_to_string(pd_load1.value));
194 break; 218 mp_add_subcheck_to_subcheck(&load_sc, load_sc1);
195 } 219
196 else if(scaled_la[i] > wload[i]) result = STATE_WARNING; 220 mp_perfdata pd_load5 = perfdata_init();
197 } else { 221 pd_load5.label = "load5";
198 if(la[i] > cload[i]) { 222 pd_load5 = mp_set_pd_value(pd_load5, load_values[1]);
199 result = STATE_CRITICAL; 223 if (!is_using_scaled_load_values) {
200 break; 224 pd_load5 = mp_pd_set_thresholds(pd_load5, config.th_load[1]);
201 }
202 else if(la[i] > wload[i]) result = STATE_WARNING;
203 }
204 } 225 }
205 226
206 printf("LOAD %s - %s|", state_text(result), status_line); 227 mp_subcheck load_sc5 = mp_subcheck_init();
207 for(i = 0; i < 3; i++) { 228 load_sc5 = mp_set_subcheck_state(load_sc5, mp_get_pd_status(pd_load5));
208 if (is_using_scaled_load_values) { 229 mp_add_perfdata_to_subcheck(&load_sc5, pd_load5);
209 printf("load%d=%.3f;;;0; ", nums[i], la[i]); 230 xasprintf(&load_sc5.output, "5 Minutes: %s", pd_value_to_string(pd_load5.value));
210 printf("scaled_load%d=%.3f;%.3f;%.3f;0; ", nums[i], scaled_la[i], wload[i], cload[i]); 231 mp_add_subcheck_to_subcheck(&load_sc, load_sc5);
211 } else { 232
212 printf("load%d=%.3f;%.3f;%.3f;0; ", nums[i], la[i], wload[i], cload[i]); 233 mp_perfdata pd_load15 = perfdata_init();
213 } 234 pd_load15.label = "load15";
235 pd_load15 = mp_set_pd_value(pd_load15, load_values[2]);
236 if (!is_using_scaled_load_values) {
237 pd_load15 = mp_pd_set_thresholds(pd_load15, config.th_load[2]);
214 } 238 }
215 239
216 putchar('\n'); 240 mp_subcheck load_sc15 = mp_subcheck_init();
217 if (n_procs_to_show > 0) { 241 load_sc15 = mp_set_subcheck_state(load_sc15, mp_get_pd_status(pd_load15));
218 print_top_consuming_processes(); 242 mp_add_perfdata_to_subcheck(&load_sc15, pd_load15);
243 xasprintf(&load_sc15.output, "15 Minutes: %s", pd_value_to_string(pd_load15.value));
244 mp_add_subcheck_to_subcheck(&load_sc, load_sc15);
245
246 mp_add_subcheck_to_check(&overall, load_sc);
247
248 if (config.n_procs_to_show > 0) {
249 mp_subcheck top_proc_sc = mp_subcheck_init();
250 top_proc_sc = mp_set_subcheck_state(top_proc_sc, STATE_OK);
251 top_processes_result top_proc = print_top_consuming_processes(config.n_procs_to_show);
252 xasprintf(&top_proc_sc.output, "Top %lu CPU time consuming processes",
253 config.n_procs_to_show);
254
255 if (top_proc.errorcode == OK) {
256 for (unsigned long i = 0; i < config.n_procs_to_show; i++) {
257 xasprintf(&top_proc_sc.output, "%s\n%s", top_proc_sc.output,
258 top_proc.top_processes[i]);
259 }
260 }
261
262 mp_add_subcheck_to_check(&overall, top_proc_sc);
219 } 263 }
220 return result;
221}
222 264
265 mp_exit(overall);
266}
223 267
224/* process command-line arguments */ 268/* process command-line arguments */
225static int 269static check_load_config_wrapper process_arguments(int argc, char **argv) {
226process_arguments (int argc, char **argv) 270
227{ 271 enum {
228 int c = 0; 272 output_format_index = CHAR_MAX + 1,
229
230 int option = 0;
231 static struct option longopts[] = {
232 {"warning", required_argument, 0, 'w'},
233 {"critical", required_argument, 0, 'c'},
234 {"percpu", no_argument, 0, 'r'},
235 {"version", no_argument, 0, 'V'},
236 {"help", no_argument, 0, 'h'},
237 {"procs-to-show", required_argument, 0, 'n'},
238 {0, 0, 0, 0}
239 }; 273 };
240 274
241 if (argc < 2) 275 static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
242 return ERROR; 276 {"critical", required_argument, 0, 'c'},
277 {"percpu", no_argument, 0, 'r'},
278 {"version", no_argument, 0, 'V'},
279 {"help", no_argument, 0, 'h'},
280 {"procs-to-show", required_argument, 0, 'n'},
281 {"output-format", required_argument, 0, output_format_index},
282 {0, 0, 0, 0}};
283
284 check_load_config_wrapper result = {
285 .errorcode = OK,
286 .config = check_load_config_init(),
287 };
243 288
244 while (1) { 289 if (argc < 2) {
245 c = getopt_long (argc, argv, "Vhrc:w:n:", longopts, &option); 290 result.errorcode = ERROR;
291 return result;
292 }
246 293
247 if (c == -1 || c == EOF) 294 while (true) {
248 break; 295 int option = 0;
296 int option_index = getopt_long(argc, argv, "Vhrc:w:n:", longopts, &option);
249 297
250 switch (c) { 298 if (option_index == -1 || option_index == EOF) {
251 case 'w': /* warning time threshold */
252 get_threshold(optarg, wload);
253 break; 299 break;
254 case 'c': /* critical time threshold */ 300 }
255 get_threshold(optarg, cload); 301
302 switch (option_index) {
303 case output_format_index: {
304 parsed_output_format parser = mp_parse_output_format(optarg);
305 if (!parser.parsing_success) {
306 printf("Invalid output format: %s\n", optarg);
307 exit(STATE_UNKNOWN);
308 }
309
310 result.config.output_format_set = true;
311 result.config.output_format = parser.output_format;
256 break; 312 break;
313 }
314 case 'w': /* warning time threshold */ {
315 parsed_thresholds warning_range = get_threshold(optarg);
316 result.config.th_load[0].warning = warning_range.load[0];
317 result.config.th_load[0].warning_is_set = true;
318
319 result.config.th_load[1].warning = warning_range.load[1];
320 result.config.th_load[1].warning_is_set = true;
321
322 result.config.th_load[2].warning = warning_range.load[2];
323 result.config.th_load[2].warning_is_set = true;
324 } break;
325 case 'c': /* critical time threshold */ {
326 parsed_thresholds critical_range = get_threshold(optarg);
327 result.config.th_load[0].critical = critical_range.load[0];
328 result.config.th_load[0].critical_is_set = true;
329
330 result.config.th_load[1].critical = critical_range.load[1];
331 result.config.th_load[1].critical_is_set = true;
332
333 result.config.th_load[2].critical = critical_range.load[2];
334 result.config.th_load[2].critical_is_set = true;
335 } break;
257 case 'r': /* Divide load average by number of CPUs */ 336 case 'r': /* Divide load average by number of CPUs */
258 take_into_account_cpus = true; 337 result.config.take_into_account_cpus = true;
259 break; 338 break;
260 case 'V': /* version */ 339 case 'V': /* version */
261 print_revision (progname, NP_VERSION); 340 print_revision(progname, NP_VERSION);
262 exit (STATE_UNKNOWN); 341 exit(STATE_UNKNOWN);
263 case 'h': /* help */ 342 case 'h': /* help */
264 print_help (); 343 print_help();
265 exit (STATE_UNKNOWN); 344 exit(STATE_UNKNOWN);
266 case 'n': 345 case 'n':
267 n_procs_to_show = atoi(optarg); 346 result.config.n_procs_to_show = (unsigned long)atol(optarg);
268 break; 347 break;
269 case '?': /* help */ 348 case '?': /* help */
270 usage5 (); 349 usage5();
271 } 350 }
272 } 351 }
273 352
274 c = optind; 353 int index = optind;
275 if (c == argc) 354 if (index == argc) {
276 return validate_arguments (); 355 return result;
356 }
277 357
278 /* handle the case if both arguments are missing, 358 /* handle the case if both arguments are missing,
279 * but not if only one is given without -c or -w flag */ 359 * but not if only one is given without -c or -w flag */
280 if(c - argc == 2) { 360 if (index - argc == 2) {
281 get_threshold(argv[c++], wload); 361 parsed_thresholds warning_range = get_threshold(argv[index++]);
282 get_threshold(argv[c++], cload); 362 result.config.th_load[0].warning = warning_range.load[0];
283 } 363 result.config.th_load[0].warning_is_set = true;
284 else if(c - argc == 1) { 364
285 get_threshold(argv[c++], cload); 365 result.config.th_load[1].warning = warning_range.load[1];
286 } 366 result.config.th_load[1].warning_is_set = true;
287 367
288 return validate_arguments (); 368 result.config.th_load[2].warning = warning_range.load[2];
289} 369 result.config.th_load[2].warning_is_set = true;
290 370 parsed_thresholds critical_range = get_threshold(argv[index++]);
291 371 result.config.th_load[0].critical = critical_range.load[0];
292static int 372 result.config.th_load[0].critical_is_set = true;
293validate_arguments (void) 373
294{ 374 result.config.th_load[1].critical = critical_range.load[1];
295 int i = 0; 375 result.config.th_load[1].critical_is_set = true;
296 376
297 /* match cload first, as it will give the most friendly error message 377 result.config.th_load[2].critical = critical_range.load[2];
298 * if user hasn't given the -c switch properly */ 378 result.config.th_load[2].critical_is_set = true;
299 for(i = 0; i < 3; i++) { 379 } else if (index - argc == 1) {
300 if(cload[i] < 0) 380 parsed_thresholds critical_range = get_threshold(argv[index++]);
301 die (STATE_UNKNOWN, _("Critical threshold for %d-minute load average is not specified\n"), nums[i]); 381 result.config.th_load[0].critical = critical_range.load[0];
302 if(wload[i] < 0) 382 result.config.th_load[0].critical_is_set = true;
303 die (STATE_UNKNOWN, _("Warning threshold for %d-minute load average is not specified\n"), nums[i]); 383
304 if(wload[i] > cload[i]) 384 result.config.th_load[1].critical = critical_range.load[1];
305 die (STATE_UNKNOWN, _("Parameter inconsistency: %d-minute \"warning load\" is greater than \"critical load\"\n"), nums[i]); 385 result.config.th_load[1].critical_is_set = true;
386
387 result.config.th_load[2].critical = critical_range.load[2];
388 result.config.th_load[2].critical_is_set = true;
306 } 389 }
307 390
308 return OK; 391 return result;
309} 392}
310 393
394void print_help(void) {
395 print_revision(progname, NP_VERSION);
311 396
312void 397 printf("Copyright (c) 1999 Felipe Gustavo de Almeida <galmeida@linux.ime.usp.br>\n");
313print_help (void) 398 printf(COPYRIGHT, copyright, email);
314{
315 print_revision (progname, NP_VERSION);
316 399
317 printf ("Copyright (c) 1999 Felipe Gustavo de Almeida <galmeida@linux.ime.usp.br>\n"); 400 printf(_("This plugin tests the current system load average."));
318 printf (COPYRIGHT, copyright, email);
319 401
320 printf (_("This plugin tests the current system load average.")); 402 printf("\n\n");
321 403
322 printf ("\n\n"); 404 print_usage();
323 405
324 print_usage (); 406 printf(UT_HELP_VRSN);
407 printf(UT_EXTRA_OPTS);
325 408
326 printf (UT_HELP_VRSN); 409 printf(" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15");
327 printf (UT_EXTRA_OPTS); 410 printf(" %s\n", _("Exit with WARNING status if load average exceeds WLOADn"));
411 printf(" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15");
412 printf(" %s\n", _("Exit with CRITICAL status if load average exceed CLOADn"));
413 printf(" %s\n", _("the load average format is the same used by \"uptime\" and \"w\""));
414 printf(" %s\n", "-r, --percpu");
415 printf(" %s\n", _("Divide the load averages by the number of CPUs (when possible)"));
416 printf(" %s\n", "-n, --procs-to-show=NUMBER_OF_PROCS");
417 printf(" %s\n", _("Number of processes to show when printing the top consuming processes."));
418 printf(" %s\n", _("NUMBER_OF_PROCS=0 disables this feature. Default value is 0"));
328 419
329 printf (" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15"); 420 printf(UT_OUTPUT_FORMAT);
330 printf (" %s\n", _("Exit with WARNING status if load average exceeds WLOADn")); 421 printf(UT_SUPPORT);
331 printf (" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15");
332 printf (" %s\n", _("Exit with CRITICAL status if load average exceed CLOADn"));
333 printf (" %s\n", _("the load average format is the same used by \"uptime\" and \"w\""));
334 printf (" %s\n", "-r, --percpu");
335 printf (" %s\n", _("Divide the load averages by the number of CPUs (when possible)"));
336 printf (" %s\n", "-n, --procs-to-show=NUMBER_OF_PROCS");
337 printf (" %s\n", _("Number of processes to show when printing the top consuming processes."));
338 printf (" %s\n", _("NUMBER_OF_PROCS=0 disables this feature. Default value is 0"));
339
340 printf (UT_SUPPORT);
341} 422}
342 423
343void 424void print_usage(void) {
344print_usage (void) 425 printf("%s\n", _("Usage:"));
345{ 426 printf("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15 [-n NUMBER_OF_PROCS]\n",
346 printf ("%s\n", _("Usage:")); 427 progname);
347 printf ("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15 [-n NUMBER_OF_PROCS]\n", progname);
348} 428}
349 429
350#ifdef PS_USES_PROCPCPU 430#ifdef PS_USES_PROCPCPU
@@ -356,36 +436,52 @@ int cmpstringp(const void *p1, const void *p2) {
356 int procrss = 0; 436 int procrss = 0;
357 float procpcpu = 0; 437 float procpcpu = 0;
358 char procstat[8]; 438 char procstat[8];
359#ifdef PS_USES_PROCETIME 439# ifdef PS_USES_PROCETIME
360 char procetime[MAX_INPUT_BUFFER]; 440 char procetime[MAX_INPUT_BUFFER];
361#endif /* PS_USES_PROCETIME */ 441# endif /* PS_USES_PROCETIME */
362 char procprog[MAX_INPUT_BUFFER]; 442 char procprog[MAX_INPUT_BUFFER];
363 int pos; 443 int pos;
364 sscanf (* (char * const *) p1, PS_FORMAT, PS_VARLIST); 444 sscanf(*(char *const *)p1, PS_FORMAT, PS_VARLIST);
365 float procpcpu1 = procpcpu; 445 float procpcpu1 = procpcpu;
366 sscanf (* (char * const *) p2, PS_FORMAT, PS_VARLIST); 446 sscanf(*(char *const *)p2, PS_FORMAT, PS_VARLIST);
367 return procpcpu1 < procpcpu; 447 return procpcpu1 < procpcpu;
368} 448}
369#endif /* PS_USES_PROCPCPU */ 449#endif /* PS_USES_PROCPCPU */
370 450
371static int print_top_consuming_processes() { 451static top_processes_result print_top_consuming_processes(unsigned long n_procs_to_show) {
372 int i = 0; 452 top_processes_result result = {
373 struct output chld_out, chld_err; 453 .errorcode = OK,
374 if(np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0){ 454 };
455 output chld_out;
456 output chld_err;
457 if (np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0) {
375 fprintf(stderr, _("'%s' exited with non-zero status.\n"), PS_COMMAND); 458 fprintf(stderr, _("'%s' exited with non-zero status.\n"), PS_COMMAND);
376 return STATE_UNKNOWN; 459 result.errorcode = ERROR;
460 return result;
377 } 461 }
462
378 if (chld_out.lines < 2) { 463 if (chld_out.lines < 2) {
379 fprintf(stderr, _("some error occurred getting procs list.\n")); 464 fprintf(stderr, _("some error occurred getting procs list.\n"));
380 return STATE_UNKNOWN; 465 result.errorcode = ERROR;
466 return result;
381 } 467 }
468
382#ifdef PS_USES_PROCPCPU 469#ifdef PS_USES_PROCPCPU
383 qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char*), cmpstringp); 470 qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char *), cmpstringp);
384#endif /* PS_USES_PROCPCPU */ 471#endif /* PS_USES_PROCPCPU */
385 int lines_to_show = chld_out.lines < (size_t)(n_procs_to_show + 1) 472 unsigned long lines_to_show =
386 ? (int)chld_out.lines : n_procs_to_show + 1; 473 chld_out.lines < (size_t)(n_procs_to_show + 1) ? chld_out.lines : n_procs_to_show + 1;
387 for (i = 0; i < lines_to_show; i += 1) { 474
388 printf("%s\n", chld_out.line[i]); 475 result.top_processes = calloc(lines_to_show, sizeof(char *));
476 if (result.top_processes == NULL) {
477 // Failed allocation
478 result.errorcode = ERROR;
479 return result;
389 } 480 }
390 return OK; 481
482 for (unsigned long i = 0; i < lines_to_show; i += 1) {
483 xasprintf(&result.top_processes[i], "%s", chld_out.line[i]);
484 }
485
486 return result;
391} 487}
diff --git a/plugins/check_load.d/config.h b/plugins/check_load.d/config.h
new file mode 100644
index 00000000..fd735455
--- /dev/null
+++ b/plugins/check_load.d/config.h
@@ -0,0 +1,30 @@
1#pragma once
2
3#include "output.h"
4#include "thresholds.h"
5typedef struct {
6 mp_thresholds th_load[3];
7
8 bool take_into_account_cpus;
9 unsigned long n_procs_to_show;
10
11 mp_output_format output_format;
12 bool output_format_set;
13} check_load_config;
14
15check_load_config check_load_config_init() {
16 check_load_config tmp = {
17 .th_load =
18 {
19 mp_thresholds_init(),
20 mp_thresholds_init(),
21 mp_thresholds_init(),
22 },
23
24 .take_into_account_cpus = false,
25 .n_procs_to_show = 0,
26
27 .output_format_set = false,
28 };
29 return tmp;
30}
diff --git a/plugins/check_mrtg.c b/plugins/check_mrtg.c
index 5bd276dc..cdc2a035 100644
--- a/plugins/check_mrtg.c
+++ b/plugins/check_mrtg.c
@@ -29,14 +29,18 @@
29 * 29 *
30 *****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_mrtg";
33const char *copyright = "1999-2024";
34const char *email = "devel@monitoring-plugins.org";
35
36#include "common.h" 32#include "common.h"
33#include "output.h"
34#include "perfdata.h"
35#include "states.h"
36#include "thresholds.h"
37#include "utils.h" 37#include "utils.h"
38#include "check_mrtg.d/config.h" 38#include "check_mrtg.d/config.h"
39 39
40const char *progname = "check_mrtg";
41const char *copyright = "1999-2024";
42const char *email = "devel@monitoring-plugins.org";
43
40typedef struct { 44typedef struct {
41 int errorcode; 45 int errorcode;
42 check_mrtg_config config; 46 check_mrtg_config config;
@@ -62,11 +66,24 @@ int main(int argc, char **argv) {
62 66
63 const check_mrtg_config config = tmp_config.config; 67 const check_mrtg_config config = tmp_config.config;
64 68
69 if (config.output_format_is_set) {
70 mp_set_format(config.output_format);
71 }
72
73 mp_check overall = mp_check_init();
74
65 /* open the MRTG log file for reading */ 75 /* open the MRTG log file for reading */
76 mp_subcheck sc_open_mrtg_log_file = mp_subcheck_init();
66 FILE *mtrg_log_file = fopen(config.log_file, "r"); 77 FILE *mtrg_log_file = fopen(config.log_file, "r");
67 if (mtrg_log_file == NULL) { 78 if (mtrg_log_file == NULL) {
68 printf(_("Unable to open MRTG log file\n")); 79 xasprintf(&sc_open_mrtg_log_file.output, "unable to open MRTG log file");
69 return STATE_UNKNOWN; 80 sc_open_mrtg_log_file = mp_set_subcheck_state(sc_open_mrtg_log_file, STATE_UNKNOWN);
81 mp_add_subcheck_to_check(&overall, sc_open_mrtg_log_file);
82 mp_exit(overall);
83 } else {
84 xasprintf(&sc_open_mrtg_log_file.output, "opened MRTG log file");
85 sc_open_mrtg_log_file = mp_set_subcheck_state(sc_open_mrtg_log_file, STATE_OK);
86 mp_add_subcheck_to_check(&overall, sc_open_mrtg_log_file);
70 } 87 }
71 88
72 time_t timestamp = 0; 89 time_t timestamp = 0;
@@ -120,17 +137,32 @@ int main(int argc, char **argv) {
120 fclose(mtrg_log_file); 137 fclose(mtrg_log_file);
121 138
122 /* if we couldn't read enough data, return an unknown error */ 139 /* if we couldn't read enough data, return an unknown error */
140 mp_subcheck sc_process_mrtg_log_file = mp_subcheck_init();
123 if (line <= 2) { 141 if (line <= 2) {
124 printf(_("Unable to process MRTG log file\n")); 142 xasprintf(&sc_process_mrtg_log_file.output, "unable to process MRTG log file");
125 return STATE_UNKNOWN; 143 sc_process_mrtg_log_file = mp_set_subcheck_state(sc_process_mrtg_log_file, STATE_UNKNOWN);
144 mp_exit(overall);
145 } else {
146 xasprintf(&sc_process_mrtg_log_file.output, "processed MRTG log file");
147 sc_process_mrtg_log_file = mp_set_subcheck_state(sc_process_mrtg_log_file, STATE_OK);
148 mp_add_subcheck_to_check(&overall, sc_process_mrtg_log_file);
126 } 149 }
127 150
128 /* make sure the MRTG data isn't too old */ 151 /* make sure the MRTG data isn't too old */
129 time_t current_time; 152 time_t current_time;
130 time(&current_time); 153 time(&current_time);
154 mp_subcheck sc_data_expired = mp_subcheck_init();
131 if (config.expire_minutes > 0 && (current_time - timestamp) > (config.expire_minutes * 60)) { 155 if (config.expire_minutes > 0 && (current_time - timestamp) > (config.expire_minutes * 60)) {
132 printf(_("MRTG data has expired (%d minutes old)\n"), (int)((current_time - timestamp) / 60)); 156 xasprintf(&sc_data_expired.output, "MRTG data has expired (%d minutes old)",
133 return STATE_WARNING; 157 (int)((current_time - timestamp) / 60));
158 sc_data_expired = mp_set_subcheck_state(sc_data_expired, STATE_WARNING);
159 mp_add_subcheck_to_check(&overall, sc_data_expired);
160 mp_exit(overall);
161 } else {
162 xasprintf(&sc_data_expired.output, "MRTG data should be valid (%d minutes old)",
163 (int)((current_time - timestamp) / 60));
164 sc_data_expired = mp_set_subcheck_state(sc_data_expired, STATE_OK);
165 mp_add_subcheck_to_check(&overall, sc_data_expired);
134 } 166 }
135 167
136 unsigned long rate = 0L; 168 unsigned long rate = 0L;
@@ -141,27 +173,40 @@ int main(int argc, char **argv) {
141 rate = maximum_value_rate; 173 rate = maximum_value_rate;
142 } 174 }
143 175
144 int result = STATE_OK; 176 mp_subcheck sc_values = mp_subcheck_init();
145 if (config.value_critical_threshold_set && rate > config.value_critical_threshold) { 177 mp_perfdata pd_value = perfdata_init();
146 result = STATE_CRITICAL; 178 pd_value = mp_set_pd_value(pd_value, rate);
147 } else if (config.value_warning_threshold_set && rate > config.value_warning_threshold) { 179 pd_value.label = config.label;
148 result = STATE_WARNING; 180 pd_value = mp_pd_set_thresholds(pd_value, config.values_threshold);
149 }
150 181
151 printf("%s. %s = %lu %s|%s\n", (config.use_average) ? _("Avg") : _("Max"), config.label, rate, config.units, 182 sc_values = mp_set_subcheck_state(sc_values, mp_get_pd_status(pd_value));
152 perfdata(config.label, (long)rate, config.units, config.value_warning_threshold_set, (long)config.value_warning_threshold, 183 xasprintf(&sc_values.output, "%s. %s = %lu %s", (config.use_average) ? _("Avg") : _("Max"),
153 config.value_critical_threshold_set, (long)config.value_critical_threshold, 0, 0, 0, 0)); 184 config.label, rate, config.units);
154 185
155 return result; 186 mp_add_subcheck_to_check(&overall, sc_values);
187
188 mp_exit(overall);
156} 189}
157 190
158/* process command-line arguments */ 191/* process command-line arguments */
159check_mrtg_config_wrapper process_arguments(int argc, char **argv) { 192check_mrtg_config_wrapper process_arguments(int argc, char **argv) {
160 static struct option longopts[] = { 193 enum {
161 {"logfile", required_argument, 0, 'F'}, {"expires", required_argument, 0, 'e'}, {"aggregation", required_argument, 0, 'a'}, 194 output_format_index,
162 {"variable", required_argument, 0, 'v'}, {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'}, 195 };
163 {"label", required_argument, 0, 'l'}, {"units", required_argument, 0, 'u'}, {"variable", required_argument, 0, 'v'}, 196
164 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}}; 197 static struct option longopts[] = {{"logfile", required_argument, 0, 'F'},
198 {"expires", required_argument, 0, 'e'},
199 {"aggregation", required_argument, 0, 'a'},
200 {"variable", required_argument, 0, 'v'},
201 {"critical", required_argument, 0, 'c'},
202 {"warning", required_argument, 0, 'w'},
203 {"label", required_argument, 0, 'l'},
204 {"units", required_argument, 0, 'u'},
205 {"variable", required_argument, 0, 'v'},
206 {"version", no_argument, 0, 'V'},
207 {"help", no_argument, 0, 'h'},
208 {"output-format", required_argument, 0, output_format_index},
209 {0, 0, 0, 0}};
165 210
166 check_mrtg_config_wrapper result = { 211 check_mrtg_config_wrapper result = {
167 .errorcode = OK, 212 .errorcode = OK,
@@ -208,14 +253,22 @@ check_mrtg_config_wrapper process_arguments(int argc, char **argv) {
208 usage4(_("Invalid variable number")); 253 usage4(_("Invalid variable number"));
209 } 254 }
210 break; 255 break;
211 case 'w': /* critical time threshold */ 256 case 'w': /* critical time threshold */ {
212 result.config.value_warning_threshold_set = true; 257 mp_range_parsed tmp = mp_parse_range_string(optarg);
213 result.config.value_warning_threshold = strtoul(optarg, NULL, 10); 258 if (tmp.error != MP_PARSING_SUCCES) {
214 break; 259 die(STATE_UNKNOWN, "failed to parse warning threshold");
215 case 'c': /* warning time threshold */ 260 }
216 result.config.value_critical_threshold_set = true; 261 result.config.values_threshold =
217 result.config.value_critical_threshold = strtoul(optarg, NULL, 10); 262 mp_thresholds_set_warn(result.config.values_threshold, tmp.range);
218 break; 263 } break;
264 case 'c': /* warning time threshold */ {
265 mp_range_parsed tmp = mp_parse_range_string(optarg);
266 if (tmp.error != MP_PARSING_SUCCES) {
267 die(STATE_UNKNOWN, "failed to parse critical threshold");
268 }
269 result.config.values_threshold =
270 mp_thresholds_set_crit(result.config.values_threshold, tmp.range);
271 } break;
219 case 'l': /* label */ 272 case 'l': /* label */
220 result.config.label = optarg; 273 result.config.label = optarg;
221 break; 274 break;
@@ -230,6 +283,17 @@ check_mrtg_config_wrapper process_arguments(int argc, char **argv) {
230 exit(STATE_UNKNOWN); 283 exit(STATE_UNKNOWN);
231 case '?': /* help */ 284 case '?': /* help */
232 usage5(); 285 usage5();
286 case output_format_index: {
287 parsed_output_format parser = mp_parse_output_format(optarg);
288 if (!parser.parsing_success) {
289 printf("Invalid output format: %s\n", optarg);
290 exit(STATE_UNKNOWN);
291 }
292
293 result.config.output_format_is_set = true;
294 result.config.output_format = parser.output_format;
295 break;
296 }
233 } 297 }
234 } 298 }
235 299
@@ -242,7 +306,9 @@ check_mrtg_config_wrapper process_arguments(int argc, char **argv) {
242 if (is_intpos(argv[option_char])) { 306 if (is_intpos(argv[option_char])) {
243 result.config.expire_minutes = atoi(argv[option_char++]); 307 result.config.expire_minutes = atoi(argv[option_char++]);
244 } else { 308 } else {
245 die(STATE_UNKNOWN, _("%s is not a valid expiration time\nUse '%s -h' for additional help\n"), argv[option_char], progname); 309 die(STATE_UNKNOWN,
310 _("%s is not a valid expiration time\nUse '%s -h' for additional help\n"),
311 argv[option_char], progname);
246 } 312 }
247 } 313 }
248 314
@@ -262,14 +328,22 @@ check_mrtg_config_wrapper process_arguments(int argc, char **argv) {
262 } 328 }
263 } 329 }
264 330
265 if (argc > option_char && !result.config.value_warning_threshold_set) { 331 if (argc > option_char && !result.config.values_threshold.warning_is_set) {
266 result.config.value_warning_threshold_set = true; 332 mp_range_parsed tmp = mp_parse_range_string(argv[option_char++]);
267 result.config.value_warning_threshold = strtoul(argv[option_char++], NULL, 10); 333 if (tmp.error != MP_PARSING_SUCCES) {
334 die(STATE_UNKNOWN, "failed to parse warning threshold");
335 }
336 result.config.values_threshold =
337 mp_thresholds_set_warn(result.config.values_threshold, tmp.range);
268 } 338 }
269 339
270 if (argc > option_char && !result.config.value_critical_threshold_set) { 340 if (argc > option_char && !result.config.values_threshold.critical_is_set) {
271 result.config.value_critical_threshold_set = true; 341 mp_range_parsed tmp = mp_parse_range_string(argv[option_char++]);
272 result.config.value_critical_threshold = strtoul(argv[option_char++], NULL, 10); 342 if (tmp.error != MP_PARSING_SUCCES) {
343 die(STATE_UNKNOWN, "failed to parse critical threshold");
344 }
345 result.config.values_threshold =
346 mp_thresholds_set_crit(result.config.values_threshold, tmp.range);
273 } 347 }
274 348
275 if (argc > option_char && strlen(result.config.label) == 0) { 349 if (argc > option_char && strlen(result.config.label) == 0) {
@@ -333,26 +407,35 @@ void print_help(void) {
333 printf(" %s\n", _("Option units label for data (Example: Packets/Sec, Errors/Sec,")); 407 printf(" %s\n", _("Option units label for data (Example: Packets/Sec, Errors/Sec,"));
334 printf(" %s\n", _("\"Bytes Per Second\", \"%% Utilization\")")); 408 printf(" %s\n", _("\"Bytes Per Second\", \"%% Utilization\")"));
335 409
410 printf(UT_OUTPUT_FORMAT);
411
336 printf("\n"); 412 printf("\n");
337 printf(" %s\n", _("If the value exceeds the <vwl> threshold, a WARNING status is returned. If")); 413 printf(" %s\n",
414 _("If the value exceeds the <vwl> threshold, a WARNING status is returned. If"));
338 printf(" %s\n", _("the value exceeds the <vcl> threshold, a CRITICAL status is returned. If")); 415 printf(" %s\n", _("the value exceeds the <vcl> threshold, a CRITICAL status is returned. If"));
339 printf(" %s\n", _("the data in the log file is older than <expire_minutes> old, a WARNING")); 416 printf(" %s\n", _("the data in the log file is older than <expire_minutes> old, a WARNING"));
340 printf(" %s\n", _("status is returned and a warning message is printed.")); 417 printf(" %s\n", _("status is returned and a warning message is printed."));
341 418
342 printf("\n"); 419 printf("\n");
343 printf(" %s\n", _("This plugin is useful for monitoring MRTG data that does not correspond to")); 420 printf(" %s\n",
344 printf(" %s\n", _("bandwidth usage. (Use the check_mrtgtraf plugin for monitoring bandwidth).")); 421 _("This plugin is useful for monitoring MRTG data that does not correspond to"));
345 printf(" %s\n", _("It can be used to monitor any kind of data that MRTG is monitoring - errors,")); 422 printf(" %s\n",
346 printf(" %s\n", _("packets/sec, etc. I use MRTG in conjunction with the Novell NLM that allows")); 423 _("bandwidth usage. (Use the check_mrtgtraf plugin for monitoring bandwidth)."));
424 printf(" %s\n",
425 _("It can be used to monitor any kind of data that MRTG is monitoring - errors,"));
426 printf(" %s\n",
427 _("packets/sec, etc. I use MRTG in conjunction with the Novell NLM that allows"));
347 printf(" %s\n", _("me to track processor utilization, user connections, drive space, etc and")); 428 printf(" %s\n", _("me to track processor utilization, user connections, drive space, etc and"));
348 printf(" %s\n\n", _("this plugin works well for monitoring that kind of data as well.")); 429 printf(" %s\n\n", _("this plugin works well for monitoring that kind of data as well."));
349 430
350 printf("%s\n", _("Notes:")); 431 printf("%s\n", _("Notes:"));
351 printf(" %s\n", _("- This plugin only monitors one of the two variables stored in the MRTG log")); 432 printf(" %s\n",
433 _("- This plugin only monitors one of the two variables stored in the MRTG log"));
352 printf(" %s\n", _("file. If you want to monitor both values you will have to define two")); 434 printf(" %s\n", _("file. If you want to monitor both values you will have to define two"));
353 printf(" %s\n", _("commands with different values for the <variable> argument. Of course,")); 435 printf(" %s\n", _("commands with different values for the <variable> argument. Of course,"));
354 printf(" %s\n", _("you can always hack the code to make this plugin work for you...")); 436 printf(" %s\n", _("you can always hack the code to make this plugin work for you..."));
355 printf(" %s\n", _("- MRTG stands for the Multi Router Traffic Grapher. It can be downloaded from")); 437 printf(" %s\n",
438 _("- MRTG stands for the Multi Router Traffic Grapher. It can be downloaded from"));
356 printf(" %s\n", "http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html"); 439 printf(" %s\n", "http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html");
357 440
358 printf(UT_SUPPORT); 441 printf(UT_SUPPORT);
diff --git a/plugins/check_mrtg.d/config.h b/plugins/check_mrtg.d/config.h
index 96b849a2..4a5b5595 100644
--- a/plugins/check_mrtg.d/config.h
+++ b/plugins/check_mrtg.d/config.h
@@ -1,6 +1,8 @@
1#pragma once 1#pragma once
2 2
3#include "../../config.h" 3#include "../../config.h"
4#include "output.h"
5#include "thresholds.h"
4#include <stddef.h> 6#include <stddef.h>
5#include <stdlib.h> 7#include <stdlib.h>
6 8
@@ -12,10 +14,10 @@ typedef struct {
12 char *units; 14 char *units;
13 char *log_file; 15 char *log_file;
14 16
15 bool value_warning_threshold_set; 17 mp_thresholds values_threshold;
16 unsigned long value_warning_threshold; 18
17 bool value_critical_threshold_set; 19 bool output_format_is_set;
18 unsigned long value_critical_threshold; 20 mp_output_format output_format;
19} check_mrtg_config; 21} check_mrtg_config;
20 22
21check_mrtg_config check_mrtg_config_init() { 23check_mrtg_config check_mrtg_config_init() {
@@ -27,10 +29,9 @@ check_mrtg_config check_mrtg_config_init() {
27 .units = NULL, 29 .units = NULL,
28 .log_file = NULL, 30 .log_file = NULL,
29 31
30 .value_warning_threshold_set = false, 32 .values_threshold = mp_thresholds_init(),
31 .value_warning_threshold = 0, 33
32 .value_critical_threshold_set = false, 34 .output_format_is_set = false,
33 .value_critical_threshold = 0,
34 }; 35 };
35 return tmp; 36 return tmp;
36} 37}
diff --git a/plugins/check_mrtgtraf.c b/plugins/check_mrtgtraf.c
index 8c7cf8aa..46b94f57 100644
--- a/plugins/check_mrtgtraf.c
+++ b/plugins/check_mrtgtraf.c
@@ -29,14 +29,18 @@
29 * 29 *
30 *****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_mrtgtraf";
33const char *copyright = "1999-2024";
34const char *email = "devel@monitoring-plugins.org";
35
36#include "check_mrtgtraf.d/config.h" 32#include "check_mrtgtraf.d/config.h"
37#include "common.h" 33#include "common.h"
34#include "output.h"
35#include "perfdata.h"
36#include "states.h"
37#include "thresholds.h"
38#include "utils.h" 38#include "utils.h"
39 39
40const char *progname = "check_mrtgtraf";
41const char *copyright = "1999-2024";
42const char *email = "devel@monitoring-plugins.org";
43
40typedef struct { 44typedef struct {
41 int errorcode; 45 int errorcode;
42 check_mrtgtraf_config config; 46 check_mrtgtraf_config config;
@@ -61,10 +65,24 @@ int main(int argc, char **argv) {
61 65
62 const check_mrtgtraf_config config = tmp_config.config; 66 const check_mrtgtraf_config config = tmp_config.config;
63 67
68 if (config.output_format_is_set) {
69 mp_set_format(config.output_format);
70 }
71
72 mp_check overall = mp_check_init();
73 mp_subcheck sc_open_mrtg_log_file = mp_subcheck_init();
74
64 /* open the MRTG log file for reading */ 75 /* open the MRTG log file for reading */
65 FILE *mrtg_log_file_ptr = fopen(config.log_file, "r"); 76 FILE *mrtg_log_file_ptr = fopen(config.log_file, "r");
66 if (mrtg_log_file_ptr == NULL) { 77 if (mrtg_log_file_ptr == NULL) {
67 usage4(_("Unable to open MRTG log file")); 78 sc_open_mrtg_log_file = mp_set_subcheck_state(sc_open_mrtg_log_file, STATE_UNKNOWN);
79 xasprintf(&sc_open_mrtg_log_file.output, "unable to open MRTG log file");
80 mp_add_subcheck_to_check(&overall, sc_open_mrtg_log_file);
81 mp_exit(overall);
82 } else {
83 sc_open_mrtg_log_file = mp_set_subcheck_state(sc_open_mrtg_log_file, STATE_OK);
84 xasprintf(&sc_open_mrtg_log_file.output, "opened MRTG log file");
85 mp_add_subcheck_to_check(&overall, sc_open_mrtg_log_file);
68 } 86 }
69 87
70 time_t timestamp = 0L; 88 time_t timestamp = 0L;
@@ -75,7 +93,6 @@ int main(int argc, char **argv) {
75 unsigned long maximum_outgoing_rate = 0L; 93 unsigned long maximum_outgoing_rate = 0L;
76 int line = 0; 94 int line = 0;
77 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, mrtg_log_file_ptr)) { 95 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, mrtg_log_file_ptr)) {
78
79 line++; 96 line++;
80 97
81 /* skip the first line of the log file */ 98 /* skip the first line of the log file */
@@ -121,10 +138,20 @@ int main(int argc, char **argv) {
121 /* make sure the MRTG data isn't too old */ 138 /* make sure the MRTG data isn't too old */
122 time_t current_time; 139 time_t current_time;
123 time(&current_time); 140 time(&current_time);
141 mp_subcheck sc_expired = mp_subcheck_init();
124 if ((config.expire_minutes > 0) && (current_time - timestamp) > (config.expire_minutes * 60)) { 142 if ((config.expire_minutes > 0) && (current_time - timestamp) > (config.expire_minutes * 60)) {
125 die(STATE_WARNING, _("MRTG data has expired (%d minutes old)\n"), (int)((current_time - timestamp) / 60)); 143 xasprintf(&sc_expired.output, "MRTG data has expired (%d minutes old)",
144 (int)((current_time - timestamp) / 60));
145 sc_expired = mp_set_subcheck_state(sc_expired, STATE_WARNING);
146 mp_add_subcheck_to_check(&overall, sc_expired);
147 mp_exit(overall);
126 } 148 }
127 149
150 xasprintf(&sc_expired.output, "MRTG data should be valid (%d minutes old)",
151 (int)((current_time - timestamp) / 60));
152 sc_expired = mp_set_subcheck_state(sc_expired, STATE_WARNING);
153 mp_add_subcheck_to_check(&overall, sc_expired);
154
128 unsigned long incoming_rate = 0L; 155 unsigned long incoming_rate = 0L;
129 unsigned long outgoing_rate = 0L; 156 unsigned long outgoing_rate = 0L;
130 /* else check the incoming/outgoing rates */ 157 /* else check the incoming/outgoing rates */
@@ -147,60 +174,72 @@ int main(int argc, char **argv) {
147 /* report incoming traffic in KBytes/sec */ 174 /* report incoming traffic in KBytes/sec */
148 else if (incoming_rate < (1024 * 1024)) { 175 else if (incoming_rate < (1024 * 1024)) {
149 strcpy(incoming_speed_rating, "KB"); 176 strcpy(incoming_speed_rating, "KB");
150 adjusted_incoming_rate = (double)(incoming_rate / 1024.0); 177 adjusted_incoming_rate = ((double)incoming_rate / 1024.0);
151 } 178 }
152 179
153 /* report incoming traffic in MBytes/sec */ 180 /* report incoming traffic in MBytes/sec */
154 else { 181 else {
155 strcpy(incoming_speed_rating, "MB"); 182 strcpy(incoming_speed_rating, "MB");
156 adjusted_incoming_rate = (double)(incoming_rate / 1024.0 / 1024.0); 183 adjusted_incoming_rate = ((double)incoming_rate / 1024.0 / 1024.0);
157 } 184 }
158 185
159 double adjusted_outgoing_rate = 0.0; 186 double adjusted_outgoing_rate = 0.0;
160 char outgoing_speed_rating[8]; 187 char outgoing_speed_rating[8];
161 /* report outgoing traffic in Bytes/sec */
162 if (outgoing_rate < 1024) { 188 if (outgoing_rate < 1024) {
189 /* report outgoing traffic in Bytes/sec */
163 strcpy(outgoing_speed_rating, "B"); 190 strcpy(outgoing_speed_rating, "B");
164 adjusted_outgoing_rate = (double)outgoing_rate; 191 adjusted_outgoing_rate = (double)outgoing_rate;
165 } 192 } else if (outgoing_rate < (1024 * 1024)) {
166 193 /* report outgoing traffic in KBytes/sec */
167 /* report outgoing traffic in KBytes/sec */
168 else if (outgoing_rate < (1024 * 1024)) {
169 strcpy(outgoing_speed_rating, "KB"); 194 strcpy(outgoing_speed_rating, "KB");
170 adjusted_outgoing_rate = (double)(outgoing_rate / 1024.0); 195 adjusted_outgoing_rate = ((double)outgoing_rate / 1024.0);
171 } 196 } else {
172 197 /* report outgoing traffic in MBytes/sec */
173 /* report outgoing traffic in MBytes/sec */
174 else {
175 strcpy(outgoing_speed_rating, "MB"); 198 strcpy(outgoing_speed_rating, "MB");
176 adjusted_outgoing_rate = (outgoing_rate / 1024.0 / 1024.0); 199 adjusted_outgoing_rate = ((double)outgoing_rate / 1024.0 / 1024.0);
177 }
178
179 int result = STATE_OK;
180 if (incoming_rate > config.incoming_critical_threshold || outgoing_rate > config.outgoing_critical_threshold) {
181 result = STATE_CRITICAL;
182 } else if (incoming_rate > config.incoming_warning_threshold || outgoing_rate > config.outgoing_warning_threshold) {
183 result = STATE_WARNING;
184 } 200 }
185 201
186 char *error_message; 202 mp_perfdata pd_rate_in = perfdata_init();
187 xasprintf(&error_message, _("%s. In = %0.1f %s/s, %s. Out = %0.1f %s/s|%s %s\n"), (config.use_average) ? _("Avg") : _("Max"), 203 pd_rate_in.label = "in";
188 adjusted_incoming_rate, incoming_speed_rating, (config.use_average) ? _("Avg") : _("Max"), adjusted_outgoing_rate, 204 pd_rate_in = mp_set_pd_value(pd_rate_in, incoming_rate);
189 outgoing_speed_rating, 205 pd_rate_in.uom = "B";
190 fperfdata("in", adjusted_incoming_rate, incoming_speed_rating, (int)config.incoming_warning_threshold, 206 pd_rate_in = mp_pd_set_thresholds(pd_rate_in, config.incoming_thresholds);
191 config.incoming_warning_threshold, (int)config.incoming_critical_threshold, config.incoming_critical_threshold, 207
192 true, 0, false, 0), 208 mp_perfdata pd_rate_out = perfdata_init();
193 fperfdata("out", adjusted_outgoing_rate, outgoing_speed_rating, (int)config.outgoing_warning_threshold, 209 pd_rate_out.label = "out";
194 config.outgoing_warning_threshold, (int)config.outgoing_critical_threshold, config.outgoing_critical_threshold, 210 pd_rate_out = mp_set_pd_value(pd_rate_out, outgoing_rate);
195 true, 0, false, 0)); 211 pd_rate_out.uom = "B";
196 212 pd_rate_out = mp_pd_set_thresholds(pd_rate_out, config.outgoing_thresholds);
197 printf(_("Traffic %s - %s\n"), state_text(result), error_message); 213
198 214 mp_subcheck sc_rate_in = mp_subcheck_init();
199 return result; 215 sc_rate_in = mp_set_subcheck_state(sc_rate_in, mp_get_pd_status(pd_rate_in));
216 mp_add_perfdata_to_subcheck(&sc_rate_in, pd_rate_in);
217 xasprintf(&sc_rate_in.output, "%s. In = %0.1f %s/s", (config.use_average) ? _("Avg") : _("Max"),
218 adjusted_incoming_rate, incoming_speed_rating);
219
220 mp_subcheck sc_rate_out = mp_subcheck_init();
221 sc_rate_out = mp_set_subcheck_state(sc_rate_out, mp_get_pd_status(pd_rate_out));
222 mp_add_perfdata_to_subcheck(&sc_rate_out, pd_rate_out);
223 xasprintf(&sc_rate_out.output, "%s. Out = %0.1f %s/s",
224 (config.use_average) ? _("Avg") : _("Max"), adjusted_outgoing_rate,
225 outgoing_speed_rating);
226
227 mp_subcheck sc_rate = mp_subcheck_init();
228 xasprintf(&sc_rate.output, "Traffic");
229 mp_add_subcheck_to_subcheck(&sc_rate, sc_rate_in);
230 mp_add_subcheck_to_subcheck(&sc_rate, sc_rate_out);
231
232 mp_add_subcheck_to_check(&overall, sc_rate);
233
234 mp_exit(overall);
200} 235}
201 236
202/* process command-line arguments */ 237/* process command-line arguments */
203check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) { 238check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) {
239 enum {
240 output_format_index = CHAR_MAX + 1,
241 };
242
204 static struct option longopts[] = {{"filename", required_argument, 0, 'F'}, 243 static struct option longopts[] = {{"filename", required_argument, 0, 'F'},
205 {"expires", required_argument, 0, 'e'}, 244 {"expires", required_argument, 0, 'e'},
206 {"aggregation", required_argument, 0, 'a'}, 245 {"aggregation", required_argument, 0, 'a'},
@@ -208,6 +247,7 @@ check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) {
208 {"warning", required_argument, 0, 'w'}, 247 {"warning", required_argument, 0, 'w'},
209 {"version", no_argument, 0, 'V'}, 248 {"version", no_argument, 0, 'V'},
210 {"help", no_argument, 0, 'h'}, 249 {"help", no_argument, 0, 'h'},
250 {"output-format", required_argument, 0, output_format_index},
211 {0, 0, 0, 0}}; 251 {0, 0, 0, 0}};
212 252
213 check_mrtgtraf_config_wrapper result = { 253 check_mrtgtraf_config_wrapper result = {
@@ -231,6 +271,14 @@ check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) {
231 271
232 int option_char; 272 int option_char;
233 int option = 0; 273 int option = 0;
274 unsigned long incoming_warning_threshold = 0;
275 unsigned long incoming_critical_threshold = 0;
276 unsigned long outgoing_warning_threshold = 0;
277 unsigned long outgoing_critical_threshold = 0;
278 bool incoming_warning_set = false;
279 bool incoming_critical_set = false;
280 bool outgoing_warning_set = false;
281 bool outgoing_critical_set = false;
234 while (true) { 282 while (true) {
235 option_char = getopt_long(argc, argv, "hVF:e:a:c:w:", longopts, &option); 283 option_char = getopt_long(argc, argv, "hVF:e:a:c:w:", longopts, &option);
236 284
@@ -248,11 +296,15 @@ check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) {
248 case 'a': /* aggregation (AVE or MAX) */ 296 case 'a': /* aggregation (AVE or MAX) */
249 result.config.use_average = (bool)(strcmp(optarg, "MAX")); 297 result.config.use_average = (bool)(strcmp(optarg, "MAX"));
250 break; 298 break;
251 case 'c': /* warning threshold */ 299 case 'c': /* critical threshold */
252 sscanf(optarg, "%lu,%lu", &result.config.incoming_critical_threshold, &result.config.outgoing_critical_threshold); 300 sscanf(optarg, "%lu,%lu", &incoming_critical_threshold, &outgoing_critical_threshold);
301 incoming_critical_set = true;
302 outgoing_critical_set = true;
253 break; 303 break;
254 case 'w': /* critical threshold */ 304 case 'w': /* warning threshold */
255 sscanf(optarg, "%lu,%lu", &result.config.incoming_warning_threshold, &result.config.outgoing_warning_threshold); 305 sscanf(optarg, "%lu,%lu", &incoming_warning_threshold, &outgoing_warning_threshold);
306 incoming_warning_set = true;
307 incoming_critical_set = true;
256 break; 308 break;
257 case 'V': /* version */ 309 case 'V': /* version */
258 print_revision(progname, NP_VERSION); 310 print_revision(progname, NP_VERSION);
@@ -262,6 +314,17 @@ check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) {
262 exit(STATE_UNKNOWN); 314 exit(STATE_UNKNOWN);
263 case '?': /* help */ 315 case '?': /* help */
264 usage5(); 316 usage5();
317 case output_format_index: {
318 parsed_output_format parser = mp_parse_output_format(optarg);
319 if (!parser.parsing_success) {
320 printf("Invalid output format: %s\n", optarg);
321 exit(STATE_UNKNOWN);
322 }
323
324 result.config.output_format_is_set = true;
325 result.config.output_format = parser.output_format;
326 break;
327 }
265 } 328 }
266 } 329 }
267 330
@@ -282,22 +345,62 @@ check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) {
282 option_char++; 345 option_char++;
283 } 346 }
284 347
285 if (argc > option_char && result.config.incoming_warning_threshold == 0) { 348 if (argc > option_char && incoming_warning_threshold == 0) {
286 result.config.incoming_warning_threshold = strtoul(argv[option_char++], NULL, 10); 349 incoming_warning_threshold = strtoul(argv[option_char++], NULL, 10);
350 incoming_warning_set = true;
287 } 351 }
288 352
289 if (argc > option_char && result.config.incoming_critical_threshold == 0) { 353 if (argc > option_char && incoming_critical_threshold == 0) {
290 result.config.incoming_critical_threshold = strtoul(argv[option_char++], NULL, 10); 354 incoming_critical_threshold = strtoul(argv[option_char++], NULL, 10);
355 incoming_critical_set = true;
291 } 356 }
292 357
293 if (argc > option_char && result.config.outgoing_warning_threshold == 0) { 358 if (argc > option_char && outgoing_warning_threshold == 0) {
294 result.config.outgoing_warning_threshold = strtoul(argv[option_char++], NULL, 10); 359 outgoing_warning_threshold = strtoul(argv[option_char++], NULL, 10);
360 outgoing_warning_set = true;
295 } 361 }
296 362
297 if (argc > option_char && result.config.outgoing_critical_threshold == 0) { 363 if (argc > option_char && outgoing_critical_threshold == 0) {
298 result.config.outgoing_critical_threshold = strtoul(argv[option_char++], NULL, 10); 364 outgoing_critical_threshold = strtoul(argv[option_char++], NULL, 10);
365 outgoing_critical_set = true;
299 } 366 }
300 367
368 mp_range incoming_warning = mp_range_init();
369 if (incoming_warning_set) {
370 incoming_warning =
371 mp_range_set_end(incoming_warning, mp_create_pd_value(incoming_warning_threshold));
372 }
373
374 result.config.incoming_thresholds =
375 mp_thresholds_set_warn(result.config.incoming_thresholds, incoming_warning);
376
377 mp_range incoming_critical = mp_range_init();
378 if (incoming_critical_set) {
379 incoming_critical =
380 mp_range_set_end(incoming_critical, mp_create_pd_value(incoming_critical_threshold));
381 }
382
383 result.config.incoming_thresholds =
384 mp_thresholds_set_crit(result.config.incoming_thresholds, incoming_critical);
385
386 mp_range outgoing_warning = mp_range_init();
387 if (outgoing_warning_set) {
388 outgoing_warning =
389 mp_range_set_end(outgoing_warning, mp_create_pd_value(outgoing_warning_threshold));
390 }
391
392 result.config.outgoing_thresholds =
393 mp_thresholds_set_warn(result.config.outgoing_thresholds, outgoing_warning);
394
395 mp_range outgoing_critical = mp_range_init();
396 if (outgoing_critical_set) {
397 outgoing_critical =
398 mp_range_set_end(outgoing_critical, mp_create_pd_value(outgoing_critical_threshold));
399 }
400
401 result.config.outgoing_thresholds =
402 mp_thresholds_set_crit(result.config.outgoing_thresholds, outgoing_critical);
403
301 return result; 404 return result;
302} 405}
303 406
@@ -332,6 +435,8 @@ void print_help(void) {
332 printf(" %s\n", "-c, --critical"); 435 printf(" %s\n", "-c, --critical");
333 printf(" %s\n", _("Critical threshold pair <incoming>,<outgoing>")); 436 printf(" %s\n", _("Critical threshold pair <incoming>,<outgoing>"));
334 437
438 printf(UT_OUTPUT_FORMAT);
439
335 printf("\n"); 440 printf("\n");
336 printf("%s\n", _("Notes:")); 441 printf("%s\n", _("Notes:"));
337 printf(" %s\n", _("- MRTG stands for Multi Router Traffic Grapher. It can be downloaded from")); 442 printf(" %s\n", _("- MRTG stands for Multi Router Traffic Grapher. It can be downloaded from"));
diff --git a/plugins/check_mrtgtraf.d/config.h b/plugins/check_mrtgtraf.d/config.h
index 94929ff7..d9737243 100644
--- a/plugins/check_mrtgtraf.d/config.h
+++ b/plugins/check_mrtgtraf.d/config.h
@@ -1,6 +1,8 @@
1#pragma once 1#pragma once
2 2
3#include "../../config.h" 3#include "../../config.h"
4#include "output.h"
5#include "thresholds.h"
4#include <stddef.h> 6#include <stddef.h>
5#include <stdlib.h> 7#include <stdlib.h>
6 8
@@ -8,11 +10,12 @@ typedef struct {
8 char *log_file; 10 char *log_file;
9 int expire_minutes; 11 int expire_minutes;
10 bool use_average; 12 bool use_average;
11 unsigned long incoming_warning_threshold;
12 unsigned long incoming_critical_threshold;
13 unsigned long outgoing_warning_threshold;
14 unsigned long outgoing_critical_threshold;
15 13
14 mp_thresholds incoming_thresholds;
15 mp_thresholds outgoing_thresholds;
16
17 bool output_format_is_set;
18 mp_output_format output_format;
16} check_mrtgtraf_config; 19} check_mrtgtraf_config;
17 20
18check_mrtgtraf_config check_mrtgtraf_config_init() { 21check_mrtgtraf_config check_mrtgtraf_config_init() {
@@ -21,10 +24,10 @@ check_mrtgtraf_config check_mrtgtraf_config_init() {
21 .expire_minutes = -1, 24 .expire_minutes = -1,
22 .use_average = true, 25 .use_average = true,
23 26
24 .incoming_warning_threshold = 0, 27 .incoming_thresholds = mp_thresholds_init(),
25 .incoming_critical_threshold = 0, 28 .outgoing_thresholds = mp_thresholds_init(),
26 .outgoing_warning_threshold = 0, 29
27 .outgoing_critical_threshold = 0, 30 .output_format_is_set = false,
28 }; 31 };
29 return tmp; 32 return tmp;
30} 33}
diff --git a/plugins/check_mysql.c b/plugins/check_mysql.c
index ca3422b5..26730d4c 100644
--- a/plugins/check_mysql.c
+++ b/plugins/check_mysql.c
@@ -30,13 +30,11 @@
30 * 30 *
31 *****************************************************************************/ 31 *****************************************************************************/
32 32
33const char *progname = "check_mysql";
34const char *copyright = "1999-2024";
35const char *email = "devel@monitoring-plugins.org";
36
37#define REPLICA_RESULTSIZE 96
38
39#include "common.h" 33#include "common.h"
34#include "output.h"
35#include "perfdata.h"
36#include "states.h"
37#include "thresholds.h"
40#include "utils.h" 38#include "utils.h"
41#include "utils_base.h" 39#include "utils_base.h"
42#include "netutils.h" 40#include "netutils.h"
@@ -46,19 +44,33 @@ const char *email = "devel@monitoring-plugins.org";
46#include <mysqld_error.h> 44#include <mysqld_error.h>
47#include <errmsg.h> 45#include <errmsg.h>
48 46
47const char *progname = "check_mysql";
48const char *copyright = "1999-2024";
49const char *email = "devel@monitoring-plugins.org";
50
49static int verbose = 0; 51static int verbose = 0;
50 52
53#define REPLICA_RESULTSIZE 96
54
51#define LENGTH_METRIC_UNIT 6 55#define LENGTH_METRIC_UNIT 6
52static const char *metric_unit[LENGTH_METRIC_UNIT] = { 56static const char *metric_unit[LENGTH_METRIC_UNIT] = {
53 "Open_files", "Open_tables", "Qcache_free_memory", "Qcache_queries_in_cache", "Threads_connected", "Threads_running"}; 57 "Open_files", "Open_tables", "Qcache_free_memory", "Qcache_queries_in_cache",
58 "Threads_connected", "Threads_running"};
54 59
55#define LENGTH_METRIC_COUNTER 9 60#define LENGTH_METRIC_COUNTER 9
56static const char *metric_counter[LENGTH_METRIC_COUNTER] = { 61static const char *metric_counter[LENGTH_METRIC_COUNTER] = {"Connections",
57 "Connections", "Qcache_hits", "Qcache_inserts", "Qcache_lowmem_prunes", "Qcache_not_cached", "Queries", 62 "Qcache_hits",
58 "Questions", "Table_locks_waited", "Uptime"}; 63 "Qcache_inserts",
59 64 "Qcache_lowmem_prunes",
60#define MYSQLDUMP_THREADS_QUERY \ 65 "Qcache_not_cached",
61 "SELECT COUNT(1) mysqldumpThreads FROM information_schema.processlist WHERE info LIKE 'SELECT /*!40001 SQL_NO_CACHE */%'" 66 "Queries",
67 "Questions",
68 "Table_locks_waited",
69 "Uptime"};
70
71#define MYSQLDUMP_THREADS_QUERY \
72 "SELECT COUNT(1) mysqldumpThreads FROM information_schema.processlist WHERE info LIKE " \
73 "'SELECT /*!40001 SQL_NO_CACHE */%'"
62 74
63typedef struct { 75typedef struct {
64 int errorcode; 76 int errorcode;
@@ -84,6 +96,10 @@ int main(int argc, char **argv) {
84 96
85 const check_mysql_config config = tmp_config.config; 97 const check_mysql_config config = tmp_config.config;
86 98
99 if (config.output_format_is_set) {
100 mp_set_format(config.output_format);
101 }
102
87 MYSQL mysql; 103 MYSQL mysql;
88 /* initialize mysql */ 104 /* initialize mysql */
89 mysql_init(&mysql); 105 mysql_init(&mysql);
@@ -99,82 +115,130 @@ int main(int argc, char **argv) {
99 } 115 }
100 116
101 if (config.ssl) { 117 if (config.ssl) {
102 mysql_ssl_set(&mysql, config.key, config.cert, config.ca_cert, config.ca_dir, config.ciphers); 118 mysql_ssl_set(&mysql, config.key, config.cert, config.ca_cert, config.ca_dir,
119 config.ciphers);
103 } 120 }
104 /* establish a connection to the server and error checking */ 121
105 if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, config.db_port, config.db_socket, 0)) { 122 mp_check overall = mp_check_init();
123
124 mp_subcheck sc_connection = mp_subcheck_init();
125 /* establish a connection to the server and check for errors */
126 if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db,
127 config.db_port, config.db_socket, 0)) {
106 /* Depending on internally-selected auth plugin MySQL might return */ 128 /* Depending on internally-selected auth plugin MySQL might return */
107 /* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */ 129 /* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */
108 /* Semantically these errors are the same. */ 130 /* Semantically these errors are the same. */
109 if (config.ignore_auth && 131 if (config.ignore_auth && (mysql_errno(&mysql) == ER_ACCESS_DENIED_ERROR ||
110 (mysql_errno(&mysql) == ER_ACCESS_DENIED_ERROR || mysql_errno(&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) { 132 mysql_errno(&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) {
111 printf("MySQL OK - Version: %s (protocol %d)\n", mysql_get_server_info(&mysql), mysql_get_proto_info(&mysql)); 133 xasprintf(&sc_connection.output, "Version: %s (protocol %d)",
112 mysql_close(&mysql); 134 mysql_get_server_info(&mysql), mysql_get_proto_info(&mysql));
113 return STATE_OK; 135 sc_connection = mp_set_subcheck_state(sc_connection, STATE_OK);
114 }
115 136
116 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) { 137 mysql_close(&mysql);
117 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
118 } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
119 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
120 } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) {
121 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
122 } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) {
123 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
124 } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) {
125 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
126 } else { 138 } else {
127 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); 139 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
140 sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING);
141 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
142 } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
143 sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING);
144 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
145 } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) {
146 sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING);
147 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
148 } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) {
149 sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING);
150 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
151 } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) {
152 sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING);
153 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
154 } else {
155 sc_connection = mp_set_subcheck_state(sc_connection, STATE_CRITICAL);
156 xasprintf(&sc_connection.output, "%s", mysql_error(&mysql));
157 }
128 } 158 }
159
160 mp_add_subcheck_to_check(&overall, sc_connection);
161 mp_exit(overall);
162 } else {
163 // successful connection
164 sc_connection = mp_set_subcheck_state(sc_connection, STATE_OK);
165 xasprintf(&sc_connection.output, "Version: %s (protocol %d)", mysql_get_server_info(&mysql),
166 mysql_get_proto_info(&mysql));
167 mp_add_subcheck_to_check(&overall, sc_connection);
129 } 168 }
130 169
131 /* get the server stats */ 170 /* get the server stats */
132 char *result = strdup(mysql_stat(&mysql)); 171 char *mysql_stats = strdup(mysql_stat(&mysql));
172
173 mp_subcheck sc_stats = mp_subcheck_init();
174 sc_stats = mp_set_subcheck_default_state(sc_stats, STATE_OK);
133 175
134 /* error checking once more */ 176 /* error checking once more */
135 if (mysql_error(&mysql)) { 177 if (mysql_errno(&mysql) != 0) {
136 if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) { 178 if ((mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) ||
137 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); 179 (mysql_errno(&mysql) == CR_SERVER_LOST) || (mysql_errno(&mysql) == CR_UNKNOWN_ERROR)) {
138 } else if (mysql_errno(&mysql) == CR_SERVER_LOST) { 180 sc_stats = mp_set_subcheck_state(sc_stats, STATE_CRITICAL);
139 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); 181 xasprintf(&sc_stats.output, "Retrieving stats failed: %s", mysql_error(&mysql));
140 } else if (mysql_errno(&mysql) == CR_UNKNOWN_ERROR) { 182 } else {
141 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); 183 // not sure which error modes occur here, but mysql_error indicates an error
184 sc_stats = mp_set_subcheck_state(sc_stats, STATE_WARNING);
185 xasprintf(&sc_stats.output, "retrieving stats caused an error: %s",
186 mysql_error(&mysql));
142 } 187 }
188
189 mp_add_subcheck_to_check(&overall, sc_stats);
190 mp_exit(overall);
191 } else {
192 xasprintf(&sc_stats.output, "retrieved stats: %s", mysql_stats);
193 sc_stats = mp_set_subcheck_state(sc_stats, STATE_OK);
194 mp_add_subcheck_to_check(&overall, sc_stats);
143 } 195 }
144 196
145 char *perf = strdup("");
146 char *error = NULL;
147 MYSQL_RES *res; 197 MYSQL_RES *res;
148 MYSQL_ROW row; 198 MYSQL_ROW row;
199 mp_subcheck sc_query = mp_subcheck_init();
149 /* try to fetch some perf data */ 200 /* try to fetch some perf data */
150 if (mysql_query(&mysql, "show global status") == 0) { 201 if (mysql_query(&mysql, "show global status") == 0) {
151 if ((res = mysql_store_result(&mysql)) == NULL) { 202 if ((res = mysql_store_result(&mysql)) == NULL) {
152 error = strdup(mysql_error(&mysql)); 203 xasprintf(&sc_connection.output, "query failed - status store_result error: %s",
204 mysql_error(&mysql));
153 mysql_close(&mysql); 205 mysql_close(&mysql);
154 die(STATE_CRITICAL, _("status store_result error: %s\n"), error); 206
207 sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
208 mp_add_subcheck_to_check(&overall, sc_query);
209 mp_exit(overall);
155 } 210 }
156 211
157 while ((row = mysql_fetch_row(res)) != NULL) { 212 while ((row = mysql_fetch_row(res)) != NULL) {
158 for (int i = 0; i < LENGTH_METRIC_UNIT; i++) { 213 for (int i = 0; i < LENGTH_METRIC_UNIT; i++) {
159 if (strcmp(row[0], metric_unit[i]) == 0) { 214 if (strcmp(row[0], metric_unit[i]) == 0) {
160 xasprintf(&perf, "%s%s ", perf, perfdata(metric_unit[i], atol(row[1]), "", false, 0, false, 0, false, 0, false, 0)); 215 mp_perfdata pd_mysql_stat = perfdata_init();
216 pd_mysql_stat.label = (char *)metric_unit[i];
217 pd_mysql_stat.value = mp_create_pd_value(atol(row[1]));
218 mp_add_perfdata_to_subcheck(&sc_stats, pd_mysql_stat);
161 continue; 219 continue;
162 } 220 }
163 } 221 }
222
164 for (int i = 0; i < LENGTH_METRIC_COUNTER; i++) { 223 for (int i = 0; i < LENGTH_METRIC_COUNTER; i++) {
165 if (strcmp(row[0], metric_counter[i]) == 0) { 224 if (strcmp(row[0], metric_counter[i]) == 0) {
166 xasprintf(&perf, "%s%s ", perf, perfdata(metric_counter[i], atol(row[1]), "c", false, 0, false, 0, false, 0, false, 0)); 225 mp_perfdata pd_mysql_stat = perfdata_init();
226 pd_mysql_stat.label = (char *)metric_counter[i];
227 pd_mysql_stat.value = mp_create_pd_value(atol(row[1]));
228 pd_mysql_stat.uom = "c";
229 mp_add_perfdata_to_subcheck(&sc_stats, pd_mysql_stat);
167 continue; 230 continue;
168 } 231 }
169 } 232 }
170 } 233 }
171 /* remove trailing space */ 234 } else {
172 if (strlen(perf) > 0) { 235 // Query failed!
173 perf[strlen(perf) - 1] = '\0'; 236 xasprintf(&sc_connection.output, "query failed");
174 } 237 sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
238 mp_add_subcheck_to_check(&overall, sc_query);
239 mp_exit(overall);
175 } 240 }
176 241
177 char replica_result[REPLICA_RESULTSIZE] = {0};
178 if (config.check_replica) { 242 if (config.check_replica) {
179 // Detect which version we are, on older version 243 // Detect which version we are, on older version
180 // "show slave status" should work, on newer ones 244 // "show slave status" should work, on newer ones
@@ -188,9 +252,11 @@ int main(int argc, char **argv) {
188 unsigned long major_version = server_verion_int / 10000; 252 unsigned long major_version = server_verion_int / 10000;
189 unsigned long minor_version = (server_verion_int % 10000) / 100; 253 unsigned long minor_version = (server_verion_int % 10000) / 100;
190 unsigned long patch_version = (server_verion_int % 100); 254 unsigned long patch_version = (server_verion_int % 100);
255
191 if (verbose) { 256 if (verbose) {
192 printf("Found MariaDB: %s, main version: %lu, minor version: %lu, patch version: %lu\n", server_version, major_version, 257 printf("Found MariaDB/MySQL: %s, main version: %lu, minor version: %lu, patch version: "
193 minor_version, patch_version); 258 "%lu\n",
259 server_version, major_version, minor_version, patch_version);
194 } 260 }
195 261
196 if (strstr(server_version, "MariaDB") != NULL) { 262 if (strstr(server_version, "MariaDB") != NULL) {
@@ -204,16 +270,13 @@ int main(int argc, char **argv) {
204 use_deprecated_slave_status = true; 270 use_deprecated_slave_status = true;
205 } 271 }
206 } 272 }
207 } else if (strstr(server_version, "MySQL") != NULL) { 273 } else {
208 // Looks like MySQL 274 // Looks like MySQL or at least not like MariaDB
209 if (major_version < 8) { 275 if (major_version < 8) {
210 use_deprecated_slave_status = true; 276 use_deprecated_slave_status = true;
211 } else if (major_version == 10 && minor_version < 4) { 277 } else if (major_version == 10 && minor_version < 4) {
212 use_deprecated_slave_status = true; 278 use_deprecated_slave_status = true;
213 } 279 }
214 } else {
215 printf("Not a known sever implementation: %s\n", server_version);
216 exit(STATE_UNKNOWN);
217 } 280 }
218 281
219 char *replica_query = NULL; 282 char *replica_query = NULL;
@@ -223,62 +286,80 @@ int main(int argc, char **argv) {
223 replica_query = "show replica status"; 286 replica_query = "show replica status";
224 } 287 }
225 288
289 mp_subcheck sc_replica = mp_subcheck_init();
290
226 /* check the replica status */ 291 /* check the replica status */
227 if (mysql_query(&mysql, replica_query) != 0) { 292 if (mysql_query(&mysql, replica_query) != 0) {
228 error = strdup(mysql_error(&mysql)); 293 xasprintf(&sc_replica.output, "replica query error: %s", mysql_error(&mysql));
229 mysql_close(&mysql); 294 mysql_close(&mysql);
230 die(STATE_CRITICAL, _("replica query error: %s\n"), error); 295
296 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
297 mp_add_subcheck_to_check(&overall, sc_replica);
298 mp_exit(overall);
231 } 299 }
232 300
233 /* store the result */ 301 /* store the result */
234 if ((res = mysql_store_result(&mysql)) == NULL) { 302 if ((res = mysql_store_result(&mysql)) == NULL) {
235 error = strdup(mysql_error(&mysql)); 303 xasprintf(&sc_replica.output, "replica store_result error: %s", mysql_error(&mysql));
236 mysql_close(&mysql); 304 mysql_close(&mysql);
237 die(STATE_CRITICAL, _("replica store_result error: %s\n"), error); 305
306 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
307 mp_add_subcheck_to_check(&overall, sc_replica);
308 mp_exit(overall);
238 } 309 }
239 310
240 /* Check there is some data */ 311 /* Check there is some data */
241 if (mysql_num_rows(res) == 0) { 312 if (mysql_num_rows(res) == 0) {
242 mysql_close(&mysql); 313 mysql_close(&mysql);
243 die(STATE_WARNING, "%s\n", _("No replicas defined")); 314
315 xasprintf(&sc_replica.output, "no replicas defined");
316 sc_replica = mp_set_subcheck_state(sc_replica, STATE_WARNING);
317 mp_add_subcheck_to_check(&overall, sc_replica);
318 mp_exit(overall);
244 } 319 }
245 320
246 /* fetch the first row */ 321 /* fetch the first row */
247 if ((row = mysql_fetch_row(res)) == NULL) { 322 if ((row = mysql_fetch_row(res)) == NULL) {
248 error = strdup(mysql_error(&mysql)); 323 xasprintf(&sc_replica.output, "replica fetch row error: %s", mysql_error(&mysql));
249 mysql_free_result(res); 324 mysql_free_result(res);
250 mysql_close(&mysql); 325 mysql_close(&mysql);
251 die(STATE_CRITICAL, _("replica fetch row error: %s\n"), error); 326
327 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
328 mp_add_subcheck_to_check(&overall, sc_replica);
329 mp_exit(overall);
252 } 330 }
253 331
254 if (mysql_field_count(&mysql) == 12) { 332 if (mysql_field_count(&mysql) == 12) {
255 /* mysql 3.23.x */ 333 /* mysql 3.23.x */
256 snprintf(replica_result, REPLICA_RESULTSIZE, _("Replica running: %s"), row[6]); 334 xasprintf(&sc_replica.output, "Replica running: %s", row[6]);
257 if (strcmp(row[6], "Yes") != 0) { 335 if (strcmp(row[6], "Yes") != 0) {
258 mysql_free_result(res); 336 mysql_free_result(res);
259 mysql_close(&mysql); 337 mysql_close(&mysql);
260 die(STATE_CRITICAL, "%s\n", replica_result);
261 }
262 338
339 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
340 mp_add_subcheck_to_check(&overall, sc_replica);
341 mp_exit(overall);
342 }
263 } else { 343 } else {
264 /* mysql 4.x.x and mysql 5.x.x */ 344 /* mysql 4.x.x and mysql 5.x.x */
265 int replica_io_field = -1; 345 int replica_io_field = -1;
266 int replica_sql_field = -1; 346 int replica_sql_field = -1;
267 int seconds_behind_field = -1; 347 int seconds_behind_field = -1;
268 int num_fields; 348 unsigned int num_fields = mysql_num_fields(res);
269 MYSQL_FIELD *fields; 349 MYSQL_FIELD *fields = mysql_fetch_fields(res);
270 num_fields = mysql_num_fields(res); 350 for (int i = 0; i < (int)num_fields; i++) {
271 fields = mysql_fetch_fields(res); 351 if ((strcasecmp(fields[i].name, "Slave_IO_Running") == 0) ||
272 for (int i = 0; i < num_fields; i++) { 352 (strcasecmp(fields[i].name, "Replica_IO_Running") == 0)) {
273 if (strcmp(fields[i].name, "Slave_IO_Running") == 0) {
274 replica_io_field = i; 353 replica_io_field = i;
275 continue; 354 continue;
276 } 355 }
277 if (strcmp(fields[i].name, "Slave_SQL_Running") == 0) { 356 if ((strcasecmp(fields[i].name, "Slave_SQL_Running") == 0) ||
357 (strcasecmp(fields[i].name, "Replica_SQL_Running") == 0)) {
278 replica_sql_field = i; 358 replica_sql_field = i;
279 continue; 359 continue;
280 } 360 }
281 if (strcmp(fields[i].name, "Seconds_Behind_Master") == 0) { 361 if ((strcasecmp(fields[i].name, "Seconds_Behind_Master") == 0) ||
362 (strcasecmp(fields[i].name, "Seconds_Behind_Source") == 0)) {
282 seconds_behind_field = i; 363 seconds_behind_field = i;
283 continue; 364 continue;
284 } 365 }
@@ -288,15 +369,23 @@ int main(int argc, char **argv) {
288 if ((replica_io_field < 0) || (replica_sql_field < 0) || (num_fields == 0)) { 369 if ((replica_io_field < 0) || (replica_sql_field < 0) || (num_fields == 0)) {
289 mysql_free_result(res); 370 mysql_free_result(res);
290 mysql_close(&mysql); 371 mysql_close(&mysql);
291 die(STATE_CRITICAL, "Replica status unavailable\n"); 372
373 xasprintf(&sc_replica.output, "Replica status unavailable");
374 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
375 mp_add_subcheck_to_check(&overall, sc_replica);
376 mp_exit(overall);
292 } 377 }
293 378
294 /* Save replica status in replica_result */ 379 /* Save replica status in replica_result */
295 snprintf(replica_result, REPLICA_RESULTSIZE, "Replica IO: %s Replica SQL: %s Seconds Behind Master: %s", row[replica_io_field], 380 xasprintf(&sc_replica.output,
296 row[replica_sql_field], seconds_behind_field != -1 ? row[seconds_behind_field] : "Unknown"); 381 "Replica IO: %s Replica SQL: %s Seconds Behind Master: %s",
297 382 row[replica_io_field], row[replica_sql_field],
298 /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no mysqldump threads running */ 383 seconds_behind_field != -1 ? row[seconds_behind_field] : "Unknown");
299 if (strcmp(row[replica_io_field], "Yes") != 0 || strcmp(row[replica_sql_field], "Yes") != 0) { 384
385 /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no
386 * mysqldump threads running */
387 if (strcmp(row[replica_io_field], "Yes") != 0 ||
388 strcmp(row[replica_sql_field], "Yes") != 0) {
300 MYSQL_RES *res_mysqldump; 389 MYSQL_RES *res_mysqldump;
301 MYSQL_ROW row_mysqldump; 390 MYSQL_ROW row_mysqldump;
302 unsigned int mysqldump_threads = 0; 391 unsigned int mysqldump_threads = 0;
@@ -314,10 +403,14 @@ int main(int argc, char **argv) {
314 } 403 }
315 mysql_close(&mysql); 404 mysql_close(&mysql);
316 } 405 }
406
317 if (mysqldump_threads == 0) { 407 if (mysqldump_threads == 0) {
318 die(STATE_CRITICAL, "%s\n", replica_result); 408 sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL);
409 mp_add_subcheck_to_check(&overall, sc_replica);
410 mp_exit(overall);
319 } else { 411 } else {
320 strncat(replica_result, " Mysqldump: in progress", REPLICA_RESULTSIZE - 1); 412 xasprintf(&sc_replica.output, "%s %s", sc_replica.output,
413 " Mysqldump: in progress");
321 } 414 }
322 } 415 }
323 416
@@ -325,27 +418,30 @@ int main(int argc, char **argv) {
325 if (seconds_behind_field == -1) { 418 if (seconds_behind_field == -1) {
326 printf("seconds_behind_field not found\n"); 419 printf("seconds_behind_field not found\n");
327 } else { 420 } else {
328 printf("seconds_behind_field(index %d)=%s\n", seconds_behind_field, row[seconds_behind_field]); 421 printf("seconds_behind_field(index %d)=%s\n", seconds_behind_field,
422 row[seconds_behind_field]);
329 } 423 }
330 } 424 }
331 425
332 /* Check Seconds Behind against threshold */ 426 /* Check Seconds Behind against threshold */
333 if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL && strcmp(row[seconds_behind_field], "NULL") != 0)) { 427 if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL &&
334 double value = atof(row[seconds_behind_field]); 428 strcmp(row[seconds_behind_field], "NULL") != 0)) {
335 int status; 429 mp_perfdata pd_seconds_behind = perfdata_init();
336 430 pd_seconds_behind.label = "seconds behind master";
337 status = get_status(value, config.my_threshold); 431 pd_seconds_behind.value = mp_create_pd_value(atof(row[seconds_behind_field]));
338 432 pd_seconds_behind =
339 xasprintf(&perf, "%s %s", perf, 433 mp_pd_set_thresholds(pd_seconds_behind, config.replica_thresholds);
340 fperfdata("seconds behind master", value, "s", true, (double)config.warning_time, true, 434 pd_seconds_behind.uom = "s";
341 (double)config.critical_time, false, 0, false, 0)); 435 mp_add_perfdata_to_subcheck(&sc_replica, pd_seconds_behind);
342 436
343 if (status == STATE_WARNING) { 437 mp_state_enum status = mp_get_pd_status(pd_seconds_behind);
344 printf("SLOW_REPLICA %s: %s|%s\n", _("WARNING"), replica_result, perf); 438
345 exit(STATE_WARNING); 439 sc_replica = mp_set_subcheck_state(sc_replica, status);
346 } else if (status == STATE_CRITICAL) { 440
347 printf("SLOW_REPLICA %s: %s|%s\n", _("CRITICAL"), replica_result, perf); 441 if (status != STATE_OK) {
348 exit(STATE_CRITICAL); 442 xasprintf(&sc_replica.output, "slow replica - %s", sc_replica.output);
443 mp_add_subcheck_to_check(&overall, sc_replica);
444 mp_exit(overall);
349 } 445 }
350 } 446 }
351 } 447 }
@@ -357,20 +453,17 @@ int main(int argc, char **argv) {
357 /* close the connection */ 453 /* close the connection */
358 mysql_close(&mysql); 454 mysql_close(&mysql);
359 455
360 /* print out the result of stats */ 456 mp_exit(overall);
361 if (config.check_replica) {
362 printf("%s %s|%s\n", result, replica_result, perf);
363 } else {
364 printf("%s|%s\n", result, perf);
365 }
366
367 return STATE_OK;
368} 457}
369 458
370#define CHECK_REPLICA_OPT CHAR_MAX + 1
371
372/* process command-line arguments */ 459/* process command-line arguments */
373check_mysql_config_wrapper process_arguments(int argc, char **argv) { 460check_mysql_config_wrapper process_arguments(int argc, char **argv) {
461
462 enum {
463 CHECK_REPLICA_OPT = CHAR_MAX + 1,
464 output_format_index,
465 };
466
374 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 467 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
375 {"socket", required_argument, 0, 's'}, 468 {"socket", required_argument, 0, 's'},
376 {"database", required_argument, 0, 'd'}, 469 {"database", required_argument, 0, 'd'},
@@ -393,6 +486,7 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) {
393 {"cert", required_argument, 0, 'a'}, 486 {"cert", required_argument, 0, 'a'},
394 {"ca-dir", required_argument, 0, 'D'}, 487 {"ca-dir", required_argument, 0, 'D'},
395 {"ciphers", required_argument, 0, 'L'}, 488 {"ciphers", required_argument, 0, 'L'},
489 {"output-format", required_argument, 0, output_format_index},
396 {0, 0, 0, 0}}; 490 {0, 0, 0, 0}};
397 491
398 check_mysql_config_wrapper result = { 492 check_mysql_config_wrapper result = {
@@ -405,12 +499,10 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) {
405 return result; 499 return result;
406 } 500 }
407 501
408 char *warning = NULL;
409 char *critical = NULL;
410
411 int option = 0; 502 int option = 0;
412 while (true) { 503 while (true) {
413 int option_index = getopt_long(argc, argv, "hlvVnSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option); 504 int option_index =
505 getopt_long(argc, argv, "hlvVnSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option);
414 506
415 if (option_index == -1 || option_index == EOF) { 507 if (option_index == -1 || option_index == EOF) {
416 break; 508 break;
@@ -478,14 +570,22 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) {
478 case 'n': 570 case 'n':
479 result.config.ignore_auth = true; /* ignore-auth */ 571 result.config.ignore_auth = true; /* ignore-auth */
480 break; 572 break;
481 case 'w': 573 case 'w': {
482 warning = optarg; 574 mp_range_parsed tmp = mp_parse_range_string(optarg);
483 result.config.warning_time = strtod(warning, NULL); 575 if (tmp.error != MP_PARSING_SUCCES) {
484 break; 576 die(STATE_UNKNOWN, "failed to parse warning time threshold");
485 case 'c': 577 }
486 critical = optarg; 578 result.config.replica_thresholds =
487 result.config.critical_time = strtod(critical, NULL); 579 mp_thresholds_set_warn(result.config.replica_thresholds, tmp.range);
488 break; 580 } break;
581 case 'c': {
582 mp_range_parsed tmp = mp_parse_range_string(optarg);
583 if (tmp.error != MP_PARSING_SUCCES) {
584 die(STATE_UNKNOWN, "failed to parse critical time threshold");
585 }
586 result.config.replica_thresholds =
587 mp_thresholds_set_crit(result.config.replica_thresholds, tmp.range);
588 } break;
489 case 'V': /* version */ 589 case 'V': /* version */
490 print_revision(progname, NP_VERSION); 590 print_revision(progname, NP_VERSION);
491 exit(STATE_UNKNOWN); 591 exit(STATE_UNKNOWN);
@@ -497,13 +597,22 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) {
497 break; 597 break;
498 case '?': /* help */ 598 case '?': /* help */
499 usage5(); 599 usage5();
600 case output_format_index: {
601 parsed_output_format parser = mp_parse_output_format(optarg);
602 if (!parser.parsing_success) {
603 printf("Invalid output format: %s\n", optarg);
604 exit(STATE_UNKNOWN);
605 }
606
607 result.config.output_format_is_set = true;
608 result.config.output_format = parser.output_format;
609 break;
610 }
500 } 611 }
501 } 612 }
502 613
503 int index = optind; 614 int index = optind;
504 615
505 set_thresholds(&result.config.my_threshold, warning, critical);
506
507 while (argc > index) { 616 while (argc > index) {
508 if (result.config.db_host == NULL) { 617 if (result.config.db_host == NULL) {
509 if (is_host(argv[index])) { 618 if (is_host(argv[index])) {
@@ -580,15 +689,17 @@ void print_help(void) {
580 printf(" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!")); 689 printf(" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!"));
581 printf(" %s\n", _("Your clear-text password could be visible as a process table entry")); 690 printf(" %s\n", _("Your clear-text password could be visible as a process table entry"));
582 printf(" %s\n", "-S, --check-slave"); 691 printf(" %s\n", "-S, --check-slave");
583 printf(" %s\n", 692 printf(" %s\n", _("Check if the slave thread is running properly. This option is deprecated "
584 _("Check if the slave thread is running properly. This option is deprecated in favour of check-replica, which does the same")); 693 "in favour of check-replica, which does the same"));
585 printf(" %s\n", "--check-replica"); 694 printf(" %s\n", "--check-replica");
586 printf(" %s\n", _("Check if the replica thread is running properly.")); 695 printf(" %s\n", _("Check if the replica thread is running properly."));
587 printf(" %s\n", "-w, --warning"); 696 printf(" %s\n", "-w, --warning");
588 printf(" %s\n", _("Exit with WARNING status if replica server is more than INTEGER seconds")); 697 printf(" %s\n",
698 _("Exit with WARNING status if replica server is more than INTEGER seconds"));
589 printf(" %s\n", _("behind master")); 699 printf(" %s\n", _("behind master"));
590 printf(" %s\n", "-c, --critical"); 700 printf(" %s\n", "-c, --critical");
591 printf(" %s\n", _("Exit with CRITICAL status if replica server is more then INTEGER seconds")); 701 printf(" %s\n",
702 _("Exit with CRITICAL status if replica server is more then INTEGER seconds"));
592 printf(" %s\n", _("behind master")); 703 printf(" %s\n", _("behind master"));
593 printf(" %s\n", "-l, --ssl"); 704 printf(" %s\n", "-l, --ssl");
594 printf(" %s\n", _("Use ssl encryption")); 705 printf(" %s\n", _("Use ssl encryption"));
@@ -603,8 +714,11 @@ void print_help(void) {
603 printf(" %s\n", "-L, --ciphers=STRING"); 714 printf(" %s\n", "-L, --ciphers=STRING");
604 printf(" %s\n", _("List of valid SSL ciphers")); 715 printf(" %s\n", _("List of valid SSL ciphers"));
605 716
717 printf(UT_OUTPUT_FORMAT);
718
606 printf("\n"); 719 printf("\n");
607 printf(" %s\n", _("There are no required arguments. By default, the local database is checked")); 720 printf(" %s\n",
721 _("There are no required arguments. By default, the local database is checked"));
608 printf(" %s\n", _("using the default unix socket. You can force TCP on localhost by using an")); 722 printf(" %s\n", _("using the default unix socket. You can force TCP on localhost by using an"));
609 printf(" %s\n", _("IP address or FQDN ('localhost' will use the socket as well).")); 723 printf(" %s\n", _("IP address or FQDN ('localhost' will use the socket as well)."));
610 724
diff --git a/plugins/check_mysql.d/config.h b/plugins/check_mysql.d/config.h
index 71ddbe8d..1d8c82bb 100644
--- a/plugins/check_mysql.d/config.h
+++ b/plugins/check_mysql.d/config.h
@@ -1,6 +1,7 @@
1#pragma once 1#pragma once
2 2
3#include "../../config.h" 3#include "../../config.h"
4#include "output.h"
4#include "thresholds.h" 5#include "thresholds.h"
5#include <stddef.h> 6#include <stddef.h>
6#include <mysql.h> 7#include <mysql.h>
@@ -24,10 +25,10 @@ typedef struct {
24 bool check_replica; 25 bool check_replica;
25 bool ignore_auth; 26 bool ignore_auth;
26 27
27 double warning_time; 28 mp_thresholds replica_thresholds;
28 double critical_time;
29 thresholds *my_threshold;
30 29
30 bool output_format_is_set;
31 mp_output_format output_format;
31} check_mysql_config; 32} check_mysql_config;
32 33
33check_mysql_config check_mysql_config_init() { 34check_mysql_config check_mysql_config_init() {
@@ -50,9 +51,9 @@ check_mysql_config check_mysql_config_init() {
50 .check_replica = false, 51 .check_replica = false,
51 .ignore_auth = false, 52 .ignore_auth = false,
52 53
53 .warning_time = 0, 54 .replica_thresholds = mp_thresholds_init(),
54 .critical_time = 0, 55
55 .my_threshold = NULL, 56 .output_format_is_set = false,
56 }; 57 };
57 return tmp; 58 return tmp;
58} 59}
diff --git a/plugins/check_mysql_query.c b/plugins/check_mysql_query.c
index 5e04a94b..ae6cc15d 100644
--- a/plugins/check_mysql_query.c
+++ b/plugins/check_mysql_query.c
@@ -29,11 +29,11 @@
29 * 29 *
30 *****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_mysql_query";
33const char *copyright = "1999-2024";
34const char *email = "devel@monitoring-plugins.org";
35
36#include "common.h" 32#include "common.h"
33#include "output.h"
34#include "perfdata.h"
35#include "states.h"
36#include "thresholds.h"
37#include "utils.h" 37#include "utils.h"
38#include "utils_base.h" 38#include "utils_base.h"
39#include "netutils.h" 39#include "netutils.h"
@@ -42,12 +42,17 @@ const char *email = "devel@monitoring-plugins.org";
42#include <mysql.h> 42#include <mysql.h>
43#include <errmsg.h> 43#include <errmsg.h>
44 44
45const char *progname = "check_mysql_query";
46const char *copyright = "1999-2024";
47const char *email = "devel@monitoring-plugins.org";
48
45typedef struct { 49typedef struct {
46 int errorcode; 50 int errorcode;
47 check_mysql_query_config config; 51 check_mysql_query_config config;
48} check_mysql_query_config_wrapper; 52} check_mysql_query_config_wrapper;
49static check_mysql_query_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); 53static check_mysql_query_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50static check_mysql_query_config_wrapper validate_arguments(check_mysql_query_config_wrapper /*config_wrapper*/); 54static check_mysql_query_config_wrapper
55 validate_arguments(check_mysql_query_config_wrapper /*config_wrapper*/);
51static void print_help(void); 56static void print_help(void);
52void print_usage(void); 57void print_usage(void);
53 58
@@ -68,6 +73,10 @@ int main(int argc, char **argv) {
68 73
69 const check_mysql_query_config config = tmp_config.config; 74 const check_mysql_query_config config = tmp_config.config;
70 75
76 if (config.output_format_is_set) {
77 mp_set_format(config.output_format);
78 }
79
71 MYSQL mysql; 80 MYSQL mysql;
72 /* initialize mysql */ 81 /* initialize mysql */
73 mysql_init(&mysql); 82 mysql_init(&mysql);
@@ -82,26 +91,38 @@ int main(int argc, char **argv) {
82 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client"); 91 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client");
83 } 92 }
84 93
94 mp_check overall = mp_check_init();
95 mp_subcheck sc_connect = mp_subcheck_init();
96
85 /* establish a connection to the server and error checking */ 97 /* establish a connection to the server and error checking */
86 if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, config.db_port, config.db_socket, 0)) { 98 if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db,
99 config.db_port, config.db_socket, 0)) {
100 xasprintf(&sc_connect.output, "query failed: %s", mysql_error(&mysql));
101
87 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) { 102 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
88 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); 103 sc_connect = mp_set_subcheck_state(sc_connect, STATE_WARNING);
89 } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) { 104 } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
90 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); 105 sc_connect = mp_set_subcheck_state(sc_connect, STATE_WARNING);
91 } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) { 106 } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) {
92 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); 107 sc_connect = mp_set_subcheck_state(sc_connect, STATE_WARNING);
93 } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) { 108 } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) {
94 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); 109 sc_connect = mp_set_subcheck_state(sc_connect, STATE_WARNING);
95 } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) { 110 } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) {
96 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); 111 sc_connect = mp_set_subcheck_state(sc_connect, STATE_WARNING);
97 } else { 112 } else {
98 die(STATE_CRITICAL, "QUERY %s: %s\n", _("CRITICAL"), mysql_error(&mysql)); 113 sc_connect = mp_set_subcheck_state(sc_connect, STATE_CRITICAL);
99 } 114 }
115
116 mp_add_subcheck_to_check(&overall, sc_connect);
117 mp_exit(overall);
100 } 118 }
101 119
102 char *error = NULL; 120 sc_connect = mp_set_subcheck_state(sc_connect, STATE_OK);
121 xasprintf(&sc_connect.output, "query succeeded");
122 mp_add_subcheck_to_check(&overall, sc_connect);
123
103 if (mysql_query(&mysql, config.sql_query) != 0) { 124 if (mysql_query(&mysql, config.sql_query) != 0) {
104 error = strdup(mysql_error(&mysql)); 125 char *error = strdup(mysql_error(&mysql));
105 mysql_close(&mysql); 126 mysql_close(&mysql);
106 die(STATE_CRITICAL, "QUERY %s: %s - %s\n", _("CRITICAL"), _("Error with query"), error); 127 die(STATE_CRITICAL, "QUERY %s: %s - %s\n", _("CRITICAL"), _("Error with query"), error);
107 } 128 }
@@ -109,7 +130,7 @@ int main(int argc, char **argv) {
109 MYSQL_RES *res; 130 MYSQL_RES *res;
110 /* store the result */ 131 /* store the result */
111 if ((res = mysql_store_result(&mysql)) == NULL) { 132 if ((res = mysql_store_result(&mysql)) == NULL) {
112 error = strdup(mysql_error(&mysql)); 133 char *error = strdup(mysql_error(&mysql));
113 mysql_close(&mysql); 134 mysql_close(&mysql);
114 die(STATE_CRITICAL, "QUERY %s: Error with store_result - %s\n", _("CRITICAL"), error); 135 die(STATE_CRITICAL, "QUERY %s: Error with store_result - %s\n", _("CRITICAL"), error);
115 } 136 }
@@ -120,17 +141,24 @@ int main(int argc, char **argv) {
120 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), _("No rows returned")); 141 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), _("No rows returned"));
121 } 142 }
122 143
144 mp_subcheck sc_value = mp_subcheck_init();
123 MYSQL_ROW row; 145 MYSQL_ROW row;
124 /* fetch the first row */ 146 /* fetch the first row */
125 if ((row = mysql_fetch_row(res)) == NULL) { 147 if ((row = mysql_fetch_row(res)) == NULL) {
126 error = strdup(mysql_error(&mysql)); 148 xasprintf(&sc_value.output, "fetch row error - %s", mysql_error(&mysql));
127 mysql_free_result(res); 149 mysql_free_result(res);
128 mysql_close(&mysql); 150 mysql_close(&mysql);
129 die(STATE_CRITICAL, "QUERY %s: Fetch row error - %s\n", _("CRITICAL"), error); 151
152 sc_value = mp_set_subcheck_state(sc_value, STATE_CRITICAL);
153 mp_add_subcheck_to_check(&overall, sc_value);
154 mp_exit(overall);
130 } 155 }
131 156
132 if (!is_numeric(row[0])) { 157 if (!is_numeric(row[0])) {
133 die(STATE_CRITICAL, "QUERY %s: %s - '%s'\n", _("CRITICAL"), _("Is not a numeric"), row[0]); 158 xasprintf(&sc_value.output, "query result is not numeric");
159 sc_value = mp_set_subcheck_state(sc_value, STATE_CRITICAL);
160 mp_add_subcheck_to_check(&overall, sc_value);
161 mp_exit(overall);
134 } 162 }
135 163
136 double value = strtod(row[0], NULL); 164 double value = strtod(row[0], NULL);
@@ -145,31 +173,42 @@ int main(int argc, char **argv) {
145 printf("mysql result: %f\n", value); 173 printf("mysql result: %f\n", value);
146 } 174 }
147 175
148 int status = get_status(value, config.my_thresholds); 176 mp_perfdata pd_query_result = perfdata_init();
177 pd_query_result = mp_set_pd_value(pd_query_result, value);
178 pd_query_result = mp_pd_set_thresholds(pd_query_result, config.thresholds);
179 pd_query_result.label = "result";
180 mp_add_perfdata_to_subcheck(&sc_value, pd_query_result);
149 181
150 if (status == STATE_OK) { 182 sc_value = mp_set_subcheck_state(sc_value, mp_get_pd_status(pd_query_result));
151 printf("QUERY %s: ", _("OK")); 183 xasprintf(&sc_value.output, "'%s' returned '%f'", config.sql_query, value);
152 } else if (status == STATE_WARNING) { 184
153 printf("QUERY %s: ", _("WARNING")); 185 mp_add_subcheck_to_check(&overall, sc_value);
154 } else if (status == STATE_CRITICAL) {
155 printf("QUERY %s: ", _("CRITICAL"));
156 }
157 printf(_("'%s' returned %f | %s"), config.sql_query, value,
158 fperfdata("result", value, "", config.my_thresholds->warning, config.my_thresholds->warning ? config.my_thresholds->warning->end : 0,
159 config.my_thresholds->critical, config.my_thresholds->critical ? config.my_thresholds->critical->end : 0, false, 0, false, 0));
160 printf("\n");
161 186
162 return status; 187 mp_exit(overall);
163} 188}
164 189
165/* process command-line arguments */ 190/* process command-line arguments */
166check_mysql_query_config_wrapper process_arguments(int argc, char **argv) { 191check_mysql_query_config_wrapper process_arguments(int argc, char **argv) {
167 static struct option longopts[] = { 192 enum {
168 {"hostname", required_argument, 0, 'H'}, {"socket", required_argument, 0, 's'}, {"database", required_argument, 0, 'd'}, 193 output_format_index = CHAR_MAX + 1,
169 {"username", required_argument, 0, 'u'}, {"password", required_argument, 0, 'p'}, {"file", required_argument, 0, 'f'}, 194 };
170 {"group", required_argument, 0, 'g'}, {"port", required_argument, 0, 'P'}, {"verbose", no_argument, 0, 'v'}, 195
171 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"query", required_argument, 0, 'q'}, 196 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
172 {"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'}, {0, 0, 0, 0}}; 197 {"socket", required_argument, 0, 's'},
198 {"database", required_argument, 0, 'd'},
199 {"username", required_argument, 0, 'u'},
200 {"password", required_argument, 0, 'p'},
201 {"file", required_argument, 0, 'f'},
202 {"group", required_argument, 0, 'g'},
203 {"port", required_argument, 0, 'P'},
204 {"verbose", no_argument, 0, 'v'},
205 {"version", no_argument, 0, 'V'},
206 {"help", no_argument, 0, 'h'},
207 {"query", required_argument, 0, 'q'},
208 {"warning", required_argument, 0, 'w'},
209 {"critical", required_argument, 0, 'c'},
210 {"output-format", required_argument, 0, output_format_index},
211 {0, 0, 0, 0}};
173 212
174 check_mysql_query_config_wrapper result = { 213 check_mysql_query_config_wrapper result = {
175 .errorcode = OK, 214 .errorcode = OK,
@@ -181,9 +220,6 @@ check_mysql_query_config_wrapper process_arguments(int argc, char **argv) {
181 return result; 220 return result;
182 } 221 }
183 222
184 char *warning = NULL;
185 char *critical = NULL;
186
187 while (true) { 223 while (true) {
188 int option = 0; 224 int option = 0;
189 int option_char = getopt_long(argc, argv, "hvVP:p:u:d:H:s:q:w:c:f:g:", longopts, &option); 225 int option_char = getopt_long(argc, argv, "hvVP:p:u:d:H:s:q:w:c:f:g:", longopts, &option);
@@ -239,23 +275,41 @@ check_mysql_query_config_wrapper process_arguments(int argc, char **argv) {
239 case 'q': 275 case 'q':
240 xasprintf(&result.config.sql_query, "%s", optarg); 276 xasprintf(&result.config.sql_query, "%s", optarg);
241 break; 277 break;
242 case 'w': 278 case 'w': {
243 warning = optarg; 279 mp_range_parsed tmp = mp_parse_range_string(optarg);
244 break; 280 if (tmp.error != MP_PARSING_SUCCES) {
245 case 'c': 281 die(STATE_UNKNOWN, "failed to parse warning threshold");
246 critical = optarg; 282 }
247 break; 283 result.config.thresholds = mp_thresholds_set_warn(result.config.thresholds, tmp.range);
284 } break;
285 case 'c': {
286 mp_range_parsed tmp = mp_parse_range_string(optarg);
287 if (tmp.error != MP_PARSING_SUCCES) {
288 die(STATE_UNKNOWN, "failed to parse critical threshold");
289 }
290 result.config.thresholds = mp_thresholds_set_crit(result.config.thresholds, tmp.range);
291 } break;
248 case '?': /* help */ 292 case '?': /* help */
249 usage5(); 293 usage5();
294 case output_format_index: {
295 parsed_output_format parser = mp_parse_output_format(optarg);
296 if (!parser.parsing_success) {
297 printf("Invalid output format: %s\n", optarg);
298 exit(STATE_UNKNOWN);
299 }
300
301 result.config.output_format_is_set = true;
302 result.config.output_format = parser.output_format;
303 break;
304 }
250 } 305 }
251 } 306 }
252 307
253 set_thresholds(&result.config.my_thresholds, warning, critical);
254
255 return validate_arguments(result); 308 return validate_arguments(result);
256} 309}
257 310
258check_mysql_query_config_wrapper validate_arguments(check_mysql_query_config_wrapper config_wrapper) { 311check_mysql_query_config_wrapper
312validate_arguments(check_mysql_query_config_wrapper config_wrapper) {
259 if (config_wrapper.config.sql_query == NULL) { 313 if (config_wrapper.config.sql_query == NULL) {
260 usage("Must specify a SQL query to run"); 314 usage("Must specify a SQL query to run");
261 } 315 }
@@ -310,6 +364,8 @@ void print_help(void) {
310 printf(" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!")); 364 printf(" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!"));
311 printf(" %s\n", _("Your clear-text password could be visible as a process table entry")); 365 printf(" %s\n", _("Your clear-text password could be visible as a process table entry"));
312 366
367 printf(UT_OUTPUT_FORMAT);
368
313 printf("\n"); 369 printf("\n");
314 printf(" %s\n", _("A query is required. The result from the query should be numeric.")); 370 printf(" %s\n", _("A query is required. The result from the query should be numeric."));
315 printf(" %s\n", _("For extra security, create a user with minimal access.")); 371 printf(" %s\n", _("For extra security, create a user with minimal access."));
diff --git a/plugins/check_mysql_query.d/config.h b/plugins/check_mysql_query.d/config.h
index be019160..32ab455a 100644
--- a/plugins/check_mysql_query.d/config.h
+++ b/plugins/check_mysql_query.d/config.h
@@ -1,6 +1,7 @@
1#pragma once 1#pragma once
2 2
3#include "../../config.h" 3#include "../../config.h"
4#include "output.h"
4#include "thresholds.h" 5#include "thresholds.h"
5#include <mysql.h> 6#include <mysql.h>
6 7
@@ -15,7 +16,10 @@ typedef struct {
15 unsigned int db_port; 16 unsigned int db_port;
16 17
17 char *sql_query; 18 char *sql_query;
18 thresholds *my_thresholds; 19 mp_thresholds thresholds;
20
21 bool output_format_is_set;
22 mp_output_format output_format;
19} check_mysql_query_config; 23} check_mysql_query_config;
20 24
21check_mysql_query_config check_mysql_query_config_init() { 25check_mysql_query_config check_mysql_query_config_init() {
@@ -30,7 +34,9 @@ check_mysql_query_config check_mysql_query_config_init() {
30 .db_port = MYSQL_PORT, 34 .db_port = MYSQL_PORT,
31 35
32 .sql_query = NULL, 36 .sql_query = NULL,
33 .my_thresholds = NULL, 37 .thresholds = mp_thresholds_init(),
38
39 .output_format_is_set = false,
34 }; 40 };
35 return tmp; 41 return tmp;
36} 42}
diff --git a/plugins/check_nt.c b/plugins/check_nt.c
deleted file mode 100644
index 7dd23e5c..00000000
--- a/plugins/check_nt.c
+++ /dev/null
@@ -1,756 +0,0 @@
1/*****************************************************************************
2 *
3 * Monitoring check_nt plugin
4 *
5 * License: GPL
6 * Copyright (c) 2000-2002 Yves Rubin (rubiyz@yahoo.com)
7 * Copyright (c) 2003-2024 Monitoring Plugins Development Team
8 *
9 * Description:
10 *
11 * This file contains the check_nt plugin
12 *
13 * This plugin collects data from the NSClient service running on a
14 * Windows NT/2000/XP/2003 server.
15 * This plugin requires NSClient software to run on NT
16 * (https://nsclient.org/)
17 *
18 *
19 * This program is free software: you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation, either version 3 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 *
32 *
33 *****************************************************************************/
34
35const char *progname = "check_nt";
36const char *copyright = "2000-2024";
37const char *email = "devel@monitoring-plugins.org";
38
39#include "common.h"
40#include "netutils.h"
41#include "utils.h"
42#include "check_nt.d/config.h"
43
44enum {
45 MAX_VALUE_LIST = 30,
46};
47
48static char recv_buffer[MAX_INPUT_BUFFER];
49
50static void fetch_data(const char *address, int port, const char *sendb);
51
52typedef struct {
53 int errorcode;
54 check_nt_config config;
55} check_nt_config_wrapper;
56static check_nt_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
57
58static void preparelist(char *string);
59static bool strtoularray(unsigned long *array, char *string, const char *delim);
60static void print_help(void);
61void print_usage(void);
62
63int main(int argc, char **argv) {
64 setlocale(LC_ALL, "");
65 bindtextdomain(PACKAGE, LOCALEDIR);
66 textdomain(PACKAGE);
67
68 /* Parse extra opts if any */
69 argv = np_extra_opts(&argc, argv, progname);
70
71 check_nt_config_wrapper tmp_config = process_arguments(argc, argv);
72 if (tmp_config.errorcode == ERROR) {
73 usage4(_("Could not parse arguments"));
74 }
75
76 const check_nt_config config = tmp_config.config;
77
78 /* initialize alarm signal handling */
79 signal(SIGALRM, socket_timeout_alarm_handler);
80
81 /* set socket timeout */
82 alarm(socket_timeout);
83
84 int return_code = STATE_UNKNOWN;
85 char *send_buffer = NULL;
86 char *output_message = NULL;
87 char *perfdata = NULL;
88 char *temp_string = NULL;
89 char *temp_string_perf = NULL;
90 char *description = NULL;
91 char *counter_unit = NULL;
92 char *errcvt = NULL;
93 unsigned long lvalue_list[MAX_VALUE_LIST];
94 switch (config.vars_to_check) {
95 case CHECK_CLIENTVERSION:
96 xasprintf(&send_buffer, "%s&1", config.req_password);
97 fetch_data(config.server_address, config.server_port, send_buffer);
98 if (config.value_list != NULL && strcmp(recv_buffer, config.value_list) != 0) {
99 xasprintf(&output_message, _("Wrong client version - running: %s, required: %s"), recv_buffer, config.value_list);
100 return_code = STATE_WARNING;
101 } else {
102 xasprintf(&output_message, "%s", recv_buffer);
103 return_code = STATE_OK;
104 }
105 break;
106 case CHECK_CPULOAD:
107 if (config.value_list == NULL) {
108 output_message = strdup(_("missing -l parameters"));
109 } else if (!strtoularray(lvalue_list, config.value_list, ",")) {
110 output_message = strdup(_("wrong -l parameter."));
111 } else {
112 /* -l parameters is present with only integers */
113 return_code = STATE_OK;
114 temp_string = strdup(_("CPU Load"));
115 temp_string_perf = strdup(" ");
116
117 /* loop until one of the parameters is wrong or not present */
118 int offset = 0;
119 while (lvalue_list[0 + offset] > (unsigned long)0 && lvalue_list[0 + offset] <= (unsigned long)17280 &&
120 lvalue_list[1 + offset] > (unsigned long)0 && lvalue_list[1 + offset] <= (unsigned long)100 &&
121 lvalue_list[2 + offset] > (unsigned long)0 && lvalue_list[2 + offset] <= (unsigned long)100) {
122
123 /* Send request and retrieve data */
124 xasprintf(&send_buffer, "%s&2&%lu", config.req_password, lvalue_list[0 + offset]);
125 fetch_data(config.server_address, config.server_port, send_buffer);
126
127 unsigned long utilization = strtoul(recv_buffer, NULL, 10);
128
129 /* Check if any of the request is in a warning or critical state */
130 if (utilization >= lvalue_list[2 + offset]) {
131 return_code = STATE_CRITICAL;
132 } else if (utilization >= lvalue_list[1 + offset] && return_code < STATE_WARNING) {
133 return_code = STATE_WARNING;
134 }
135
136 xasprintf(&output_message, _(" %lu%% (%lu min average)"), utilization, lvalue_list[0 + offset]);
137 xasprintf(&temp_string, "%s%s", temp_string, output_message);
138 xasprintf(&perfdata, _(" '%lu min avg Load'=%lu%%;%lu;%lu;0;100"), lvalue_list[0 + offset], utilization,
139 lvalue_list[1 + offset], lvalue_list[2 + offset]);
140 xasprintf(&temp_string_perf, "%s%s", temp_string_perf, perfdata);
141 offset += 3; /* move across the array */
142 }
143
144 if (strlen(temp_string) > 10) { /* we had at least one loop */
145 output_message = strdup(temp_string);
146 perfdata = temp_string_perf;
147 } else {
148 output_message = strdup(_("not enough values for -l parameters"));
149 }
150 }
151 break;
152 case CHECK_UPTIME: {
153 char *tmp_value_list = config.value_list;
154 if (config.value_list == NULL) {
155 tmp_value_list = "minutes";
156 }
157 if (strncmp(tmp_value_list, "seconds", strlen("seconds") + 1) && strncmp(tmp_value_list, "minutes", strlen("minutes") + 1) &&
158 strncmp(config.value_list, "hours", strlen("hours") + 1) && strncmp(tmp_value_list, "days", strlen("days") + 1)) {
159
160 output_message = strdup(_("wrong -l argument"));
161 } else {
162 xasprintf(&send_buffer, "%s&3", config.req_password);
163 fetch_data(config.server_address, config.server_port, send_buffer);
164 unsigned long uptime = strtoul(recv_buffer, NULL, 10);
165 int updays = uptime / 86400;
166 int uphours = (uptime % 86400) / 3600;
167 int upminutes = ((uptime % 86400) % 3600) / 60;
168
169 if (!strncmp(tmp_value_list, "minutes", strlen("minutes"))) {
170 uptime = uptime / 60;
171 } else if (!strncmp(tmp_value_list, "hours", strlen("hours"))) {
172 uptime = uptime / 3600;
173 } else if (!strncmp(tmp_value_list, "days", strlen("days"))) {
174 uptime = uptime / 86400;
175 }
176 /* else uptime in seconds, nothing to do */
177
178 xasprintf(&output_message, _("System Uptime - %u day(s) %u hour(s) %u minute(s) |uptime=%lu"), updays, uphours, upminutes,
179 uptime);
180
181 if (config.check_critical_value && uptime <= config.critical_value) {
182 return_code = STATE_CRITICAL;
183 } else if (config.check_warning_value && uptime <= config.warning_value) {
184 return_code = STATE_WARNING;
185 } else {
186 return_code = STATE_OK;
187 }
188 }
189 } break;
190 case CHECK_USEDDISKSPACE:
191 if (config.value_list == NULL) {
192 output_message = strdup(_("missing -l parameters"));
193 } else if (strlen(config.value_list) != 1) {
194 output_message = strdup(_("wrong -l argument"));
195 } else {
196 xasprintf(&send_buffer, "%s&4&%s", config.req_password, config.value_list);
197 fetch_data(config.server_address, config.server_port, send_buffer);
198 char *fds = strtok(recv_buffer, "&");
199 char *tds = strtok(NULL, "&");
200 double total_disk_space = 0;
201 double free_disk_space = 0;
202 if (fds != NULL) {
203 free_disk_space = atof(fds);
204 }
205 if (tds != NULL) {
206 total_disk_space = atof(tds);
207 }
208
209 if (total_disk_space > 0 && free_disk_space >= 0) {
210 double percent_used_space = ((total_disk_space - free_disk_space) / total_disk_space) * 100;
211 double warning_used_space = ((float)config.warning_value / 100) * total_disk_space;
212 double critical_used_space = ((float)config.critical_value / 100) * total_disk_space;
213
214 xasprintf(&temp_string, _("%s:\\ - total: %.2f Gb - used: %.2f Gb (%.0f%%) - free %.2f Gb (%.0f%%)"), config.value_list,
215 total_disk_space / 1073741824, (total_disk_space - free_disk_space) / 1073741824, percent_used_space,
216 free_disk_space / 1073741824, (free_disk_space / total_disk_space) * 100);
217 xasprintf(&temp_string_perf, _("'%s:\\ Used Space'=%.2fGb;%.2f;%.2f;0.00;%.2f"), config.value_list,
218 (total_disk_space - free_disk_space) / 1073741824, warning_used_space / 1073741824,
219 critical_used_space / 1073741824, total_disk_space / 1073741824);
220
221 if (config.check_critical_value && percent_used_space >= config.critical_value) {
222 return_code = STATE_CRITICAL;
223 } else if (config.check_warning_value && percent_used_space >= config.warning_value) {
224 return_code = STATE_WARNING;
225 } else {
226 return_code = STATE_OK;
227 }
228
229 output_message = strdup(temp_string);
230 perfdata = temp_string_perf;
231 } else {
232 output_message = strdup(_("Free disk space : Invalid drive"));
233 return_code = STATE_UNKNOWN;
234 }
235 }
236 break;
237 case CHECK_SERVICESTATE:
238 case CHECK_PROCSTATE:
239 if (config.value_list == NULL) {
240 output_message = strdup(_("No service/process specified"));
241 } else {
242 preparelist(config.value_list); /* replace , between services with & to send the request */
243 xasprintf(&send_buffer, "%s&%u&%s&%s", config.req_password, (config.vars_to_check == CHECK_SERVICESTATE) ? 5 : 6,
244 (config.show_all) ? "ShowAll" : "ShowFail", config.value_list);
245 fetch_data(config.server_address, config.server_port, send_buffer);
246 char *numstr = strtok(recv_buffer, "&");
247 if (numstr == NULL) {
248 die(STATE_UNKNOWN, _("could not fetch information from server\n"));
249 }
250 return_code = atoi(numstr);
251 temp_string = strtok(NULL, "&");
252 output_message = strdup(temp_string);
253 }
254 break;
255 case CHECK_MEMUSE:
256 xasprintf(&send_buffer, "%s&7", config.req_password);
257 fetch_data(config.server_address, config.server_port, send_buffer);
258 char *numstr = strtok(recv_buffer, "&");
259 if (numstr == NULL) {
260 die(STATE_UNKNOWN, _("could not fetch information from server\n"));
261 }
262 double mem_commitLimit = atof(numstr);
263 numstr = strtok(NULL, "&");
264 if (numstr == NULL) {
265 die(STATE_UNKNOWN, _("could not fetch information from server\n"));
266 }
267 double mem_commitByte = atof(numstr);
268 double percent_used_space = (mem_commitByte / mem_commitLimit) * 100;
269 double warning_used_space = ((float)config.warning_value / 100) * mem_commitLimit;
270 double critical_used_space = ((float)config.critical_value / 100) * mem_commitLimit;
271
272 /* Divisor should be 1048567, not 3044515, as we are measuring "Commit Charge" here,
273 which equals RAM + Pagefiles. */
274 xasprintf(&output_message, _("Memory usage: total:%.2f MB - used: %.2f MB (%.0f%%) - free: %.2f MB (%.0f%%)"),
275 mem_commitLimit / 1048567, mem_commitByte / 1048567, percent_used_space, (mem_commitLimit - mem_commitByte) / 1048567,
276 (mem_commitLimit - mem_commitByte) / mem_commitLimit * 100);
277 xasprintf(&perfdata, _("'Memory usage'=%.2fMB;%.2f;%.2f;0.00;%.2f"), mem_commitByte / 1048567, warning_used_space / 1048567,
278 critical_used_space / 1048567, mem_commitLimit / 1048567);
279
280 return_code = STATE_OK;
281 if (config.check_critical_value && percent_used_space >= config.critical_value) {
282 return_code = STATE_CRITICAL;
283 } else if (config.check_warning_value && percent_used_space >= config.warning_value) {
284 return_code = STATE_WARNING;
285 }
286
287 break;
288 case CHECK_COUNTER: {
289 /*
290 CHECK_COUNTER has been modified to provide extensive perfdata information.
291 In order to do this, some modifications have been done to the code
292 and some constraints have been introduced.
293
294 1) For the sake of simplicity of the code, perfdata information will only be
295 provided when the "description" field is added.
296
297 2) If the counter you're going to measure is percent-based, the code will detect
298 the percent sign in its name and will attribute minimum (0%) and maximum (100%)
299 values automagically, as well the "%" sign to graph units.
300
301 3) OTOH, if the counter is "absolute", you'll have to provide the following
302 the counter unit - that is, the dimensions of the counter you're getting. Examples:
303 pages/s, packets transferred, etc.
304
305 4) If you want, you may provide the minimum and maximum values to expect. They aren't mandatory,
306 but once specified they MUST have the same order of magnitude and units of -w and -c; otherwise.
307 strange things will happen when you make graphs of your data.
308 */
309
310 double counter_value = 0.0;
311 if (config.value_list == NULL) {
312 output_message = strdup(_("No counter specified"));
313 } else {
314 preparelist(config.value_list); /* replace , between services with & to send the request */
315 bool isPercent = (strchr(config.value_list, '%') != NULL);
316
317 strtok(config.value_list, "&"); /* burn the first parameters */
318 description = strtok(NULL, "&");
319 counter_unit = strtok(NULL, "&");
320 xasprintf(&send_buffer, "%s&8&%s", config.req_password, config.value_list);
321 fetch_data(config.server_address, config.server_port, send_buffer);
322 counter_value = atof(recv_buffer);
323
324 bool allRight = false;
325 if (description == NULL) {
326 xasprintf(&output_message, "%.f", counter_value);
327 } else if (isPercent) {
328 counter_unit = strdup("%");
329 allRight = true;
330 }
331
332 char *minval = NULL;
333 char *maxval = NULL;
334 double fminval = 0;
335 double fmaxval = 0;
336 if ((counter_unit != NULL) && (!allRight)) {
337 minval = strtok(NULL, "&");
338 maxval = strtok(NULL, "&");
339
340 /* All parameters specified. Let's check the numbers */
341
342 fminval = (minval != NULL) ? strtod(minval, &errcvt) : -1;
343 fmaxval = (minval != NULL) ? strtod(maxval, &errcvt) : -1;
344
345 if ((fminval == 0) && (minval == errcvt)) {
346 output_message = strdup(_("Minimum value contains non-numbers"));
347 } else {
348 if ((fmaxval == 0) && (maxval == errcvt)) {
349 output_message = strdup(_("Maximum value contains non-numbers"));
350 } else {
351 allRight = true; /* Everything is OK. */
352 }
353 }
354 } else if ((counter_unit == NULL) && (description != NULL)) {
355 output_message = strdup(_("No unit counter specified"));
356 }
357
358 if (allRight) {
359 /* Let's format the output string, finally... */
360 if (strstr(description, "%") == NULL) {
361 xasprintf(&output_message, "%s = %.2f %s", description, counter_value, counter_unit);
362 } else {
363 /* has formatting, will segv if wrong */
364 xasprintf(&output_message, description, counter_value);
365 }
366 xasprintf(&output_message, "%s |", output_message);
367 xasprintf(&output_message, "%s %s", output_message,
368 fperfdata(description, counter_value, counter_unit, 1, config.warning_value, 1, config.critical_value,
369 (!(isPercent) && (minval != NULL)), fminval, (!(isPercent) && (minval != NULL)), fmaxval));
370 }
371 }
372
373 if (config.critical_value > config.warning_value) { /* Normal thresholds */
374 if (config.check_critical_value && counter_value >= config.critical_value) {
375 return_code = STATE_CRITICAL;
376 } else if (config.check_warning_value && counter_value >= config.warning_value) {
377 return_code = STATE_WARNING;
378 } else {
379 return_code = STATE_OK;
380 }
381 } else { /* inverse thresholds */
382 return_code = STATE_OK;
383 if (config.check_critical_value && counter_value <= config.critical_value) {
384 return_code = STATE_CRITICAL;
385 } else if (config.check_warning_value && counter_value <= config.warning_value) {
386 return_code = STATE_WARNING;
387 }
388 }
389 } break;
390 case CHECK_FILEAGE:
391 if (config.value_list == NULL) {
392 output_message = strdup(_("No counter specified"));
393 } else {
394 preparelist(config.value_list); /* replace , between services with & to send the request */
395 xasprintf(&send_buffer, "%s&9&%s", config.req_password, config.value_list);
396 fetch_data(config.server_address, config.server_port, send_buffer);
397 unsigned long age_in_minutes = atoi(strtok(recv_buffer, "&"));
398 description = strtok(NULL, "&");
399 output_message = strdup(description);
400
401 if (config.critical_value > config.warning_value) { /* Normal thresholds */
402 if (config.check_critical_value && age_in_minutes >= config.critical_value) {
403 return_code = STATE_CRITICAL;
404 } else if (config.check_warning_value && age_in_minutes >= config.warning_value) {
405 return_code = STATE_WARNING;
406 } else {
407 return_code = STATE_OK;
408 }
409 } else { /* inverse thresholds */
410 if (config.check_critical_value && age_in_minutes <= config.critical_value) {
411 return_code = STATE_CRITICAL;
412 } else if (config.check_warning_value && age_in_minutes <= config.warning_value) {
413 return_code = STATE_WARNING;
414 } else {
415 return_code = STATE_OK;
416 }
417 }
418 }
419 break;
420
421 case CHECK_INSTANCES:
422 if (config.value_list == NULL) {
423 output_message = strdup(_("No counter specified"));
424 } else {
425 xasprintf(&send_buffer, "%s&10&%s", config.req_password, config.value_list);
426 fetch_data(config.server_address, config.server_port, send_buffer);
427 if (!strncmp(recv_buffer, "ERROR", 5)) {
428 printf("NSClient - %s\n", recv_buffer);
429 exit(STATE_UNKNOWN);
430 }
431 xasprintf(&output_message, "%s", recv_buffer);
432 return_code = STATE_OK;
433 }
434 break;
435
436 case CHECK_NONE:
437 default:
438 usage4(_("Please specify a variable to check"));
439 break;
440 }
441
442 /* reset timeout */
443 alarm(0);
444
445 if (perfdata == NULL) {
446 printf("%s\n", output_message);
447 } else {
448 printf("%s | %s\n", output_message, perfdata);
449 }
450 return return_code;
451}
452
453/* process command-line arguments */
454check_nt_config_wrapper process_arguments(int argc, char **argv) {
455 static struct option longopts[] = {{"port", required_argument, 0, 'p'},
456 {"timeout", required_argument, 0, 't'},
457 {"critical", required_argument, 0, 'c'},
458 {"warning", required_argument, 0, 'w'},
459 {"variable", required_argument, 0, 'v'},
460 {"hostname", required_argument, 0, 'H'},
461 {"params", required_argument, 0, 'l'},
462 {"secret", required_argument, 0, 's'},
463 {"display", required_argument, 0, 'd'},
464 {"unknown-timeout", no_argument, 0, 'u'},
465 {"version", no_argument, 0, 'V'},
466 {"help", no_argument, 0, 'h'},
467 {0, 0, 0, 0}};
468
469 check_nt_config_wrapper result = {
470 .errorcode = OK,
471 .config = check_nt_config_init(),
472 };
473
474 /* no options were supplied */
475 if (argc < 2) {
476 result.errorcode = ERROR;
477 return result;
478 }
479
480 /* backwards compatibility */
481 if (!is_option(argv[1])) {
482 result.config.server_address = strdup(argv[1]);
483 argv[1] = argv[0];
484 argv = &argv[1];
485 argc--;
486 }
487
488 for (int index = 1; index < argc; index++) {
489 if (strcmp("-to", argv[index]) == 0) {
490 strcpy(argv[index], "-t");
491 } else if (strcmp("-wv", argv[index]) == 0) {
492 strcpy(argv[index], "-w");
493 } else if (strcmp("-cv", argv[index]) == 0) {
494 strcpy(argv[index], "-c");
495 }
496 }
497
498 int option = 0;
499 while (true) {
500 int option_index = getopt_long(argc, argv, "+hVH:t:c:w:p:v:l:s:d:u", longopts, &option);
501
502 if (option_index == -1 || option_index == EOF || option_index == 1) {
503 break;
504 }
505
506 switch (option_index) {
507 case '?': /* print short usage statement if args not parsable */
508 usage5();
509 case 'h': /* help */
510 print_help();
511 exit(STATE_UNKNOWN);
512 case 'V': /* version */
513 print_revision(progname, NP_VERSION);
514 exit(STATE_UNKNOWN);
515 case 'H': /* hostname */
516 result.config.server_address = optarg;
517 break;
518 case 's': /* password */
519 result.config.req_password = optarg;
520 break;
521 case 'p': /* port */
522 if (is_intnonneg(optarg)) {
523 result.config.server_port = atoi(optarg);
524 } else {
525 die(STATE_UNKNOWN, _("Server port must be an integer\n"));
526 }
527 break;
528 case 'v':
529 if (strlen(optarg) < 4) {
530 result.errorcode = ERROR;
531 return result;
532 }
533 if (!strcmp(optarg, "CLIENTVERSION")) {
534 result.config.vars_to_check = CHECK_CLIENTVERSION;
535 } else if (!strcmp(optarg, "CPULOAD")) {
536 result.config.vars_to_check = CHECK_CPULOAD;
537 } else if (!strcmp(optarg, "UPTIME")) {
538 result.config.vars_to_check = CHECK_UPTIME;
539 } else if (!strcmp(optarg, "USEDDISKSPACE")) {
540 result.config.vars_to_check = CHECK_USEDDISKSPACE;
541 } else if (!strcmp(optarg, "SERVICESTATE")) {
542 result.config.vars_to_check = CHECK_SERVICESTATE;
543 } else if (!strcmp(optarg, "PROCSTATE")) {
544 result.config.vars_to_check = CHECK_PROCSTATE;
545 } else if (!strcmp(optarg, "MEMUSE")) {
546 result.config.vars_to_check = CHECK_MEMUSE;
547 } else if (!strcmp(optarg, "COUNTER")) {
548 result.config.vars_to_check = CHECK_COUNTER;
549 } else if (!strcmp(optarg, "FILEAGE")) {
550 result.config.vars_to_check = CHECK_FILEAGE;
551 } else if (!strcmp(optarg, "INSTANCES")) {
552 result.config.vars_to_check = CHECK_INSTANCES;
553 } else {
554 result.errorcode = ERROR;
555 return result;
556 }
557 break;
558 case 'l': /* value list */
559 result.config.value_list = optarg;
560 break;
561 case 'w': /* warning threshold */
562 result.config.warning_value = strtoul(optarg, NULL, 10);
563 result.config.check_warning_value = true;
564 break;
565 case 'c': /* critical threshold */
566 result.config.critical_value = strtoul(optarg, NULL, 10);
567 result.config.check_critical_value = true;
568 break;
569 case 'd': /* Display select for services */
570 if (!strcmp(optarg, "SHOWALL")) {
571 result.config.show_all = true;
572 }
573 break;
574 case 'u':
575 socket_timeout_state = STATE_UNKNOWN;
576 break;
577 case 't': /* timeout */
578 socket_timeout = atoi(optarg);
579 if (socket_timeout <= 0) {
580 result.errorcode = ERROR;
581 return result;
582 }
583 }
584 }
585 if (result.config.server_address == NULL) {
586 usage4(_("You must provide a server address or host name"));
587 }
588
589 if (result.config.vars_to_check == CHECK_NONE) {
590 result.errorcode = ERROR;
591 return result;
592 }
593
594 if (result.config.req_password == NULL) {
595 result.config.req_password = strdup(_("None"));
596 }
597
598 return result;
599}
600
601void fetch_data(const char *address, int port, const char *sendb) {
602 int result = process_tcp_request(address, port, sendb, recv_buffer, sizeof(recv_buffer));
603
604 if (result != STATE_OK) {
605 die(result, _("could not fetch information from server\n"));
606 }
607
608 if (!strncmp(recv_buffer, "ERROR", 5)) {
609 die(STATE_UNKNOWN, "NSClient - %s\n", recv_buffer);
610 }
611}
612
613bool strtoularray(unsigned long *array, char *string, const char *delim) {
614 /* split a <delim> delimited string into a long array */
615 for (int idx = 0; idx < MAX_VALUE_LIST; idx++) {
616 array[idx] = 0;
617 }
618
619 int idx = 0;
620 for (char *t1 = strtok(string, delim); t1 != NULL; t1 = strtok(NULL, delim)) {
621 if (is_numeric(t1) && idx < MAX_VALUE_LIST) {
622 array[idx] = strtoul(t1, NULL, 10);
623 idx++;
624 } else {
625 return false;
626 }
627 }
628 return true;
629}
630
631void preparelist(char *string) {
632 /* Replace all , with & which is the delimiter for the request */
633 for (int i = 0; (size_t)i < strlen(string); i++) {
634 if (string[i] == ',') {
635 string[i] = '&';
636 }
637 }
638}
639
640void print_help(void) {
641 print_revision(progname, NP_VERSION);
642
643 printf("Copyright (c) 2000 Yves Rubin (rubiyz@yahoo.com)\n");
644 printf(COPYRIGHT, copyright, email);
645
646 printf("%s\n", _("This plugin collects data from the NSClient service running on a"));
647 printf("%s\n", _("Windows NT/2000/XP/2003 server."));
648
649 printf("\n\n");
650
651 print_usage();
652
653 printf(UT_HELP_VRSN);
654 printf(UT_EXTRA_OPTS);
655
656 printf("%s\n", _("Options:"));
657 printf(" %s\n", "-H, --hostname=HOST");
658 printf(" %s\n", _("Name of the host to check"));
659 printf(" %s\n", "-p, --port=INTEGER");
660 printf(" %s", _("Optional port number (default: "));
661 printf("%d)\n", PORT);
662 printf(" %s\n", "-s, --secret=<password>");
663 printf(" %s\n", _("Password needed for the request"));
664 printf(" %s\n", "-w, --warning=INTEGER");
665 printf(" %s\n", _("Threshold which will result in a warning status"));
666 printf(" %s\n", "-c, --critical=INTEGER");
667 printf(" %s\n", _("Threshold which will result in a critical status"));
668 printf(" %s\n", "-t, --timeout=INTEGER");
669 printf(" %s", _("Seconds before connection attempt times out (default: "));
670 printf(" %s\n", "-l, --params=<parameters>");
671 printf(" %s", _("Parameters passed to specified check (see below)"));
672 printf(" %s\n", "-d, --display={SHOWALL}");
673 printf(" %s", _("Display options (currently only SHOWALL works)"));
674 printf(" %s\n", "-u, --unknown-timeout");
675 printf(" %s", _("Return UNKNOWN on timeouts"));
676 printf("%d)\n", DEFAULT_SOCKET_TIMEOUT);
677 printf(" %s\n", "-h, --help");
678 printf(" %s\n", _("Print this help screen"));
679 printf(" %s\n", "-V, --version");
680 printf(" %s\n", _("Print version information"));
681 printf(" %s\n", "-v, --variable=STRING");
682 printf(" %s\n\n", _("Variable to check"));
683 printf("%s\n", _("Valid variables are:"));
684 printf(" %s", "CLIENTVERSION =");
685 printf(" %s\n", _("Get the NSClient version"));
686 printf(" %s\n", _("If -l <version> is specified, will return warning if versions differ."));
687 printf(" %s\n", "CPULOAD =");
688 printf(" %s\n", _("Average CPU load on last x minutes."));
689 printf(" %s\n", _("Request a -l parameter with the following syntax:"));
690 printf(" %s\n", _("-l <minutes range>,<warning threshold>,<critical threshold>."));
691 printf(" %s\n", _("<minute range> should be less than 24*60."));
692 printf(" %s\n", _("Thresholds are percentage and up to 10 requests can be done in one shot."));
693 printf(" %s\n", "ie: -l 60,90,95,120,90,95");
694 printf(" %s\n", "UPTIME =");
695 printf(" %s\n", _("Get the uptime of the machine."));
696 printf(" %s\n", _("-l <unit> "));
697 printf(" %s\n", _("<unit> = seconds, minutes, hours, or days. (default: minutes)"));
698 printf(" %s\n", _("Thresholds will use the unit specified above."));
699 printf(" %s\n", "USEDDISKSPACE =");
700 printf(" %s\n", _("Size and percentage of disk use."));
701 printf(" %s\n", _("Request a -l parameter containing the drive letter only."));
702 printf(" %s\n", _("Warning and critical thresholds can be specified with -w and -c."));
703 printf(" %s\n", "MEMUSE =");
704 printf(" %s\n", _("Memory use."));
705 printf(" %s\n", _("Warning and critical thresholds can be specified with -w and -c."));
706 printf(" %s\n", "SERVICESTATE =");
707 printf(" %s\n", _("Check the state of one or several services."));
708 printf(" %s\n", _("Request a -l parameters with the following syntax:"));
709 printf(" %s\n", _("-l <service1>,<service2>,<service3>,..."));
710 printf(" %s\n", _("You can specify -d SHOWALL in case you want to see working services"));
711 printf(" %s\n", _("in the returned string."));
712 printf(" %s\n", "PROCSTATE =");
713 printf(" %s\n", _("Check if one or several process are running."));
714 printf(" %s\n", _("Same syntax as SERVICESTATE."));
715 printf(" %s\n", "COUNTER =");
716 printf(" %s\n", _("Check any performance counter of Windows NT/2000."));
717 printf(" %s\n", _("Request a -l parameters with the following syntax:"));
718 printf(" %s\n", _("-l \"\\\\<performance object>\\\\counter\",\"<description>"));
719 printf(" %s\n", _("The <description> parameter is optional and is given to a printf "));
720 printf(" %s\n", _("output command which requires a float parameter."));
721 printf(" %s\n", _("If <description> does not include \"%%\", it is used as a label."));
722 printf(" %s\n", _("Some examples:"));
723 printf(" %s\n", "\"Paging file usage is %%.2f %%%%\"");
724 printf(" %s\n", "\"%%.f %%%% paging file used.\"");
725 printf(" %s\n", "INSTANCES =");
726 printf(" %s\n", _("Check any performance counter object of Windows NT/2000."));
727 printf(" %s\n", _("Syntax: check_nt -H <hostname> -p <port> -v INSTANCES -l <counter object>"));
728 printf(" %s\n", _("<counter object> is a Windows Perfmon Counter object (eg. Process),"));
729 printf(" %s\n", _("if it is two words, it should be enclosed in quotes"));
730 printf(" %s\n", _("The returned results will be a comma-separated list of instances on "));
731 printf(" %s\n", _(" the selected computer for that object."));
732 printf(" %s\n", _("The purpose of this is to be run from command line to determine what instances"));
733 printf(" %s\n", _(" are available for monitoring without having to log onto the Windows server"));
734 printf(" %s\n", _(" to run Perfmon directly."));
735 printf(" %s\n", _("It can also be used in scripts that automatically create the monitoring service"));
736 printf(" %s\n", _(" configuration files."));
737 printf(" %s\n", _("Some examples:"));
738 printf(" %s\n\n", _("check_nt -H 192.168.1.1 -p 1248 -v INSTANCES -l Process"));
739
740 printf("%s\n", _("Notes:"));
741 printf(" %s\n", _("- The NSClient service should be running on the server to get any information"));
742 printf(" %s\n", "(http://nsclient.ready2run.nl).");
743 printf(" %s\n", _("- Critical thresholds should be lower than warning thresholds"));
744 printf(" %s\n", _("- Default port 1248 is sometimes in use by other services. The error"));
745 printf(" %s\n", _("output when this happens contains \"Cannot map xxxxx to protocol number\"."));
746 printf(" %s\n", _("One fix for this is to change the port to something else on check_nt "));
747 printf(" %s\n", _("and on the client service it\'s connecting to."));
748
749 printf(UT_SUPPORT);
750}
751
752void print_usage(void) {
753 printf("%s\n", _("Usage:"));
754 printf("%s -H host -v variable [-p port] [-w warning] [-c critical]\n", progname);
755 printf("[-l params] [-d SHOWALL] [-u] [-t timeout]\n");
756}
diff --git a/plugins/check_nt.d/config.h b/plugins/check_nt.d/config.h
deleted file mode 100644
index 431889cb..00000000
--- a/plugins/check_nt.d/config.h
+++ /dev/null
@@ -1,53 +0,0 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6enum {
7 PORT = 1248,
8};
9
10enum checkvars {
11 CHECK_NONE,
12 CHECK_CLIENTVERSION,
13 CHECK_CPULOAD,
14 CHECK_UPTIME,
15 CHECK_USEDDISKSPACE,
16 CHECK_SERVICESTATE,
17 CHECK_PROCSTATE,
18 CHECK_MEMUSE,
19 CHECK_COUNTER,
20 CHECK_FILEAGE,
21 CHECK_INSTANCES
22};
23
24typedef struct {
25 char *server_address;
26 int server_port;
27 char *req_password;
28 enum checkvars vars_to_check;
29 bool show_all;
30 char *value_list;
31 bool check_warning_value;
32 unsigned long warning_value;
33 bool check_critical_value;
34 unsigned long critical_value;
35} check_nt_config;
36
37check_nt_config check_nt_config_init() {
38 check_nt_config tmp = {
39 .server_address = NULL,
40 .server_port = PORT,
41 .req_password = NULL,
42
43 .vars_to_check = CHECK_NONE,
44 .show_all = false,
45 .value_list = NULL,
46
47 .check_warning_value = false,
48 .warning_value = 0,
49 .check_critical_value = false,
50 .critical_value = 0,
51 };
52 return tmp;
53}
diff --git a/plugins/check_ntp.c b/plugins/check_ntp.c
deleted file mode 100644
index d33f8786..00000000
--- a/plugins/check_ntp.c
+++ /dev/null
@@ -1,901 +0,0 @@
1/*****************************************************************************
2*
3* Monitoring check_ntp plugin
4*
5* License: GPL
6* Copyright (c) 2006 Sean Finney <seanius@seanius.net>
7* Copyright (c) 2006-2024 Monitoring Plugins Development Team
8*
9* Description:
10*
11* This file contains the check_ntp plugin
12*
13* This plugin to check ntp servers independent of any commandline
14* programs or external libraries.
15*
16*
17* This program is free software: you can redistribute it and/or modify
18* it under the terms of the GNU General Public License as published by
19* the Free Software Foundation, either version 3 of the License, or
20* (at your option) any later version.
21*
22* This program is distributed in the hope that it will be useful,
23* but WITHOUT ANY WARRANTY; without even the implied warranty of
24* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25* GNU General Public License for more details.
26*
27* You should have received a copy of the GNU General Public License
28* along with this program. If not, see <http://www.gnu.org/licenses/>.
29*
30*
31*****************************************************************************/
32
33const char *progname = "check_ntp";
34const char *copyright = "2006-2024";
35const char *email = "devel@monitoring-plugins.org";
36
37#include "common.h"
38#include "netutils.h"
39#include "utils.h"
40
41static char *server_address=NULL;
42static int verbose=0;
43static bool do_offset = false;
44static char *owarn="60";
45static char *ocrit="120";
46static bool do_jitter = false;
47static char *jwarn="5000";
48static char *jcrit="10000";
49
50static int process_arguments (int /*argc*/, char ** /*argv*/);
51static thresholds *offset_thresholds = NULL;
52static thresholds *jitter_thresholds = NULL;
53static void print_help (void);
54void print_usage (void);
55
56/* number of times to perform each request to get a good average. */
57#ifndef AVG_NUM
58#define AVG_NUM 4
59#endif
60
61/* max size of control message data */
62#define MAX_CM_SIZE 468
63
64/* this structure holds everything in an ntp request/response as per rfc1305 */
65typedef struct {
66 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
67 uint8_t stratum; /* clock stratum */
68 int8_t poll; /* polling interval */
69 int8_t precision; /* precision of the local clock */
70 int32_t rtdelay; /* total rt delay, as a fixed point num. see macros */
71 uint32_t rtdisp; /* like above, but for max err to primary src */
72 uint32_t refid; /* ref clock identifier */
73 uint64_t refts; /* reference timestamp. local time local clock */
74 uint64_t origts; /* time at which request departed client */
75 uint64_t rxts; /* time at which request arrived at server */
76 uint64_t txts; /* time at which request departed server */
77} ntp_message;
78
79/* this structure holds data about results from querying offset from a peer */
80typedef struct {
81 time_t waiting; /* ts set when we started waiting for a response */
82 int num_responses; /* number of successfully received responses */
83 uint8_t stratum; /* copied verbatim from the ntp_message */
84 double rtdelay; /* converted from the ntp_message */
85 double rtdisp; /* converted from the ntp_message */
86 double offset[AVG_NUM]; /* offsets from each response */
87 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
88} ntp_server_results;
89
90/* this structure holds everything in an ntp control message as per rfc1305 */
91typedef struct {
92 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
93 uint8_t op; /* R,E,M bits and Opcode */
94 uint16_t seq; /* Packet sequence */
95 uint16_t status; /* Clock status */
96 uint16_t assoc; /* Association */
97 uint16_t offset; /* Similar to TCP sequence # */
98 uint16_t count; /* # bytes of data */
99 char data[MAX_CM_SIZE]; /* ASCII data of the request */
100 /* NB: not necessarily NULL terminated! */
101} ntp_control_message;
102
103/* this is an association/status-word pair found in control packet responses */
104typedef struct {
105 uint16_t assoc;
106 uint16_t status;
107} ntp_assoc_status_pair;
108
109/* bits 1,2 are the leap indicator */
110#define LI_MASK 0xc0
111#define LI(x) ((x&LI_MASK)>>6)
112#define LI_SET(x,y) do{ x |= ((y<<6)&LI_MASK); }while(0)
113/* and these are the values of the leap indicator */
114#define LI_NOWARNING 0x00
115#define LI_EXTRASEC 0x01
116#define LI_MISSINGSEC 0x02
117#define LI_ALARM 0x03
118/* bits 3,4,5 are the ntp version */
119#define VN_MASK 0x38
120#define VN(x) ((x&VN_MASK)>>3)
121#define VN_SET(x,y) do{ x |= ((y<<3)&VN_MASK); }while(0)
122#define VN_RESERVED 0x02
123/* bits 6,7,8 are the ntp mode */
124#define MODE_MASK 0x07
125#define MODE(x) (x&MODE_MASK)
126#define MODE_SET(x,y) do{ x |= (y&MODE_MASK); }while(0)
127/* here are some values */
128#define MODE_CLIENT 0x03
129#define MODE_CONTROLMSG 0x06
130/* In control message, bits 8-10 are R,E,M bits */
131#define REM_MASK 0xe0
132#define REM_RESP 0x80
133#define REM_ERROR 0x40
134#define REM_MORE 0x20
135/* In control message, bits 11 - 15 are opcode */
136#define OP_MASK 0x1f
137#define OP_SET(x,y) do{ x |= (y&OP_MASK); }while(0)
138#define OP_READSTAT 0x01
139#define OP_READVAR 0x02
140/* In peer status bytes, bits 6,7,8 determine clock selection status */
141#define PEER_SEL(x) ((ntohs(x)>>8)&0x07)
142#define PEER_INCLUDED 0x04
143#define PEER_SYNCSOURCE 0x06
144
145/**
146 ** a note about the 32-bit "fixed point" numbers:
147 **
148 they are divided into halves, each being a 16-bit int in network byte order:
149 - the first 16 bits are an int on the left side of a decimal point.
150 - the second 16 bits represent a fraction n/(2^16)
151 likewise for the 64-bit "fixed point" numbers with everything doubled :)
152 **/
153
154/* macros to access the left/right 16 bits of a 32-bit ntp "fixed point"
155 number. note that these can be used as lvalues too */
156#define L16(x) (((uint16_t*)&x)[0])
157#define R16(x) (((uint16_t*)&x)[1])
158/* macros to access the left/right 32 bits of a 64-bit ntp "fixed point"
159 number. these too can be used as lvalues */
160#define L32(x) (((uint32_t*)&x)[0])
161#define R32(x) (((uint32_t*)&x)[1])
162
163/* ntp wants seconds since 1/1/00, epoch is 1/1/70. this is the difference */
164#define EPOCHDIFF 0x83aa7e80UL
165
166/* extract a 32-bit ntp fixed point number into a double */
167#define NTP32asDOUBLE(x) (ntohs(L16(x)) + (double)ntohs(R16(x))/65536.0)
168
169/* likewise for a 64-bit ntp fp number */
170#define NTP64asDOUBLE(n) (double)(((uint64_t)n)?\
171 (ntohl(L32(n))-EPOCHDIFF) + \
172 (.00000001*(0.5+(double)(ntohl(R32(n))/42.94967296))):\
173 0)
174
175/* convert a struct timeval to a double */
176#define TVasDOUBLE(x) (double)(x.tv_sec+(0.000001*x.tv_usec))
177
178/* convert an ntp 64-bit fp number to a struct timeval */
179#define NTP64toTV(n,t) \
180 do{ if(!n) t.tv_sec = t.tv_usec = 0; \
181 else { \
182 t.tv_sec=ntohl(L32(n))-EPOCHDIFF; \
183 t.tv_usec=(int)(0.5+(double)(ntohl(R32(n))/4294.967296)); \
184 } \
185 }while(0)
186
187/* convert a struct timeval to an ntp 64-bit fp number */
188#define TVtoNTP64(t,n) \
189 do{ if(!t.tv_usec && !t.tv_sec) n=0x0UL; \
190 else { \
191 L32(n)=htonl(t.tv_sec + EPOCHDIFF); \
192 R32(n)=htonl((uint64_t)((4294.967296*t.tv_usec)+.5)); \
193 } \
194 } while(0)
195
196/* NTP control message header is 12 bytes, plus any data in the data
197 * field, plus null padding to the nearest 32-bit boundary per rfc.
198 */
199#define SIZEOF_NTPCM(m) (12+ntohs(m.count)+((ntohs(m.count)%4)?4-(ntohs(m.count)%4):0))
200
201/* finally, a little helper or two for debugging: */
202#define DBG(x) do{if(verbose>1){ x; }}while(0);
203#define PRINTSOCKADDR(x) \
204 do{ \
205 printf("%u.%u.%u.%u", (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff);\
206 }while(0);
207
208/* calculate the offset of the local clock */
209static inline double calc_offset(const ntp_message *m, const struct timeval *t){
210 double client_tx, peer_rx, peer_tx, client_rx;
211 client_tx = NTP64asDOUBLE(m->origts);
212 peer_rx = NTP64asDOUBLE(m->rxts);
213 peer_tx = NTP64asDOUBLE(m->txts);
214 client_rx=TVasDOUBLE((*t));
215 return (.5*((peer_tx-client_rx)+(peer_rx-client_tx)));
216}
217
218/* print out a ntp packet in human readable/debuggable format */
219void print_ntp_message(const ntp_message *p){
220 struct timeval ref, orig, rx, tx;
221
222 NTP64toTV(p->refts,ref);
223 NTP64toTV(p->origts,orig);
224 NTP64toTV(p->rxts,rx);
225 NTP64toTV(p->txts,tx);
226
227 printf("packet contents:\n");
228 printf("\tflags: 0x%.2x\n", p->flags);
229 printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK);
230 printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK);
231 printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK);
232 printf("\tstratum = %d\n", p->stratum);
233 printf("\tpoll = %g\n", pow(2, p->poll));
234 printf("\tprecision = %g\n", pow(2, p->precision));
235 printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(p->rtdelay));
236 printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(p->rtdisp));
237 printf("\trefid = %x\n", p->refid);
238 printf("\trefts = %-.16g\n", NTP64asDOUBLE(p->refts));
239 printf("\torigts = %-.16g\n", NTP64asDOUBLE(p->origts));
240 printf("\trxts = %-.16g\n", NTP64asDOUBLE(p->rxts));
241 printf("\ttxts = %-.16g\n", NTP64asDOUBLE(p->txts));
242}
243
244void print_ntp_control_message(const ntp_control_message *p){
245 int i=0, numpeers=0;
246 const ntp_assoc_status_pair *peer=NULL;
247
248 printf("control packet contents:\n");
249 printf("\tflags: 0x%.2x , 0x%.2x\n", p->flags, p->op);
250 printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK);
251 printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK);
252 printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK);
253 printf("\t response=%d (0x%.2x)\n", (p->op&REM_RESP)>0, p->op&REM_RESP);
254 printf("\t more=%d (0x%.2x)\n", (p->op&REM_MORE)>0, p->op&REM_MORE);
255 printf("\t error=%d (0x%.2x)\n", (p->op&REM_ERROR)>0, p->op&REM_ERROR);
256 printf("\t op=%d (0x%.2x)\n", p->op&OP_MASK, p->op&OP_MASK);
257 printf("\tsequence: %d (0x%.2x)\n", ntohs(p->seq), ntohs(p->seq));
258 printf("\tstatus: %d (0x%.2x)\n", ntohs(p->status), ntohs(p->status));
259 printf("\tassoc: %d (0x%.2x)\n", ntohs(p->assoc), ntohs(p->assoc));
260 printf("\toffset: %d (0x%.2x)\n", ntohs(p->offset), ntohs(p->offset));
261 printf("\tcount: %d (0x%.2x)\n", ntohs(p->count), ntohs(p->count));
262 numpeers=ntohs(p->count)/(sizeof(ntp_assoc_status_pair));
263 if(p->op&REM_RESP && p->op&OP_READSTAT){
264 peer=(ntp_assoc_status_pair*)p->data;
265 for(i=0;i<numpeers;i++){
266 printf("\tpeer id %.2x status %.2x",
267 ntohs(peer[i].assoc), ntohs(peer[i].status));
268 if (PEER_SEL(peer[i].status) >= PEER_INCLUDED){
269 if(PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE){
270 printf(" <-- current sync source");
271 } else {
272 printf(" <-- current sync candidate");
273 }
274 }
275 printf("\n");
276 }
277 }
278}
279
280void setup_request(ntp_message *p){
281 struct timeval t;
282
283 memset(p, 0, sizeof(ntp_message));
284 LI_SET(p->flags, LI_ALARM);
285 VN_SET(p->flags, 4);
286 MODE_SET(p->flags, MODE_CLIENT);
287 p->poll=4;
288 p->precision=(int8_t)0xfa;
289 L16(p->rtdelay)=htons(1);
290 L16(p->rtdisp)=htons(1);
291
292 gettimeofday(&t, NULL);
293 TVtoNTP64(t,p->txts);
294}
295
296/* select the "best" server from a list of servers, and return its index.
297 * this is done by filtering servers based on stratum, dispersion, and
298 * finally round-trip delay. */
299int best_offset_server(const ntp_server_results *slist, int nservers){
300 int cserver=0, best_server=-1;
301
302 /* for each server */
303 for(cserver=0; cserver<nservers; cserver++){
304 /* We don't want any servers that fails these tests */
305 /* Sort out servers that didn't respond or responede with a 0 stratum;
306 * stratum 0 is for reference clocks so no NTP server should ever report
307 * a stratum 0 */
308 if ( slist[cserver].stratum == 0){
309 if (verbose) printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum);
310 continue;
311 }
312 /* Sort out servers with error flags */
313 if ( LI(slist[cserver].flags) == LI_ALARM ){
314 if (verbose) printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags));
315 continue;
316 }
317
318 /* If we don't have a server yet, use the first one */
319 if (best_server == -1) {
320 best_server = cserver;
321 DBG(printf("using peer %d as our first candidate\n", best_server));
322 continue;
323 }
324
325 /* compare the server to the best one we've seen so far */
326 /* does it have an equal or better stratum? */
327 DBG(printf("comparing peer %d with peer %d\n", cserver, best_server));
328 if(slist[cserver].stratum <= slist[best_server].stratum){
329 DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server));
330 /* does it have an equal or better dispersion? */
331 if(slist[cserver].rtdisp <= slist[best_server].rtdisp){
332 DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server));
333 /* does it have a better rtdelay? */
334 if(slist[cserver].rtdelay < slist[best_server].rtdelay){
335 DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server));
336 best_server = cserver;
337 DBG(printf("peer %d is now our best candidate\n", best_server));
338 }
339 }
340 }
341 }
342
343 if(best_server >= 0) {
344 DBG(printf("best server selected: peer %d\n", best_server));
345 return best_server;
346 } else {
347 DBG(printf("no peers meeting synchronization criteria :(\n"));
348 return -1;
349 }
350}
351
352/* do everything we need to get the total average offset
353 * - we use a certain amount of parallelization with poll() to ensure
354 * we don't waste time sitting around waiting for single packets.
355 * - we also "manually" handle resolving host names and connecting, because
356 * we have to do it in a way that our lazy macros don't handle currently :( */
357double offset_request(const char *host, int *status){
358 int i=0, ga_result=0, num_hosts=0, *socklist=NULL, respnum=0;
359 int servers_completed=0, one_read=0, servers_readable=0, best_index=-1;
360 time_t now_time=0, start_ts=0;
361 ntp_message *req=NULL;
362 double avg_offset=0.;
363 struct timeval recv_time;
364 struct addrinfo *ai=NULL, *ai_tmp=NULL, hints;
365 struct pollfd *ufds=NULL;
366 ntp_server_results *servers=NULL;
367
368 /* setup hints to only return results from getaddrinfo that we'd like */
369 memset(&hints, 0, sizeof(struct addrinfo));
370 hints.ai_family = address_family;
371 hints.ai_protocol = IPPROTO_UDP;
372 hints.ai_socktype = SOCK_DGRAM;
373
374 /* fill in ai with the list of hosts resolved by the host name */
375 ga_result = getaddrinfo(host, "123", &hints, &ai);
376 if(ga_result!=0){
377 die(STATE_UNKNOWN, "error getting address for %s: %s\n",
378 host, gai_strerror(ga_result));
379 }
380
381 /* count the number of returned hosts, and allocate stuff accordingly */
382 for(ai_tmp=ai; ai_tmp!=NULL; ai_tmp=ai_tmp->ai_next){ num_hosts++; }
383 req=(ntp_message*)malloc(sizeof(ntp_message)*num_hosts);
384 if(req==NULL) die(STATE_UNKNOWN, "can not allocate ntp message array");
385 socklist=(int*)malloc(sizeof(int)*num_hosts);
386 if(socklist==NULL) die(STATE_UNKNOWN, "can not allocate socket array");
387 ufds=(struct pollfd*)malloc(sizeof(struct pollfd)*num_hosts);
388 if(ufds==NULL) die(STATE_UNKNOWN, "can not allocate socket array");
389 servers=(ntp_server_results*)malloc(sizeof(ntp_server_results)*num_hosts);
390 if(servers==NULL) die(STATE_UNKNOWN, "can not allocate server array");
391 memset(servers, 0, sizeof(ntp_server_results)*num_hosts);
392 DBG(printf("Found %d peers to check\n", num_hosts));
393
394 /* setup each socket for writing, and the corresponding struct pollfd */
395 ai_tmp=ai;
396 for(i=0;ai_tmp;i++){
397 socklist[i]=socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP);
398 if(socklist[i] == -1) {
399 perror(NULL);
400 die(STATE_UNKNOWN, "can not create new socket");
401 }
402 if(connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)){
403 /* don't die here, because it is enough if there is one server
404 answering in time. This also would break for dual ipv4/6 stacked
405 ntp servers when the client only supports on of them.
406 */
407 DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno)));
408 } else {
409 ufds[i].fd=socklist[i];
410 ufds[i].events=POLLIN;
411 ufds[i].revents=0;
412 }
413 ai_tmp = ai_tmp->ai_next;
414 }
415
416 /* now do AVG_NUM checks to each host. we stop before timeout/2 seconds
417 * have passed in order to ensure post-processing and jitter time. */
418 now_time=start_ts=time(NULL);
419 while(servers_completed<num_hosts && now_time-start_ts <= socket_timeout/2){
420 /* loop through each server and find each one which hasn't
421 * been touched in the past second or so and is still lacking
422 * some responses. for each of these servers, send a new request,
423 * and update the "waiting" timestamp with the current time. */
424 now_time=time(NULL);
425
426 for(i=0; i<num_hosts; i++){
427 if(servers[i].waiting<now_time && servers[i].num_responses<AVG_NUM){
428 if(verbose && servers[i].waiting != 0) printf("re-");
429 if(verbose) printf("sending request to peer %d\n", i);
430 setup_request(&req[i]);
431 write(socklist[i], &req[i], sizeof(ntp_message));
432 servers[i].waiting=now_time;
433 break;
434 }
435 }
436
437 /* quickly poll for any sockets with pending data */
438 servers_readable=poll(ufds, num_hosts, 100);
439 if(servers_readable==-1){
440 perror("polling ntp sockets");
441 die(STATE_UNKNOWN, "communication errors");
442 }
443
444 /* read from any sockets with pending data */
445 for(i=0; servers_readable && i<num_hosts; i++){
446 if(ufds[i].revents&POLLIN && servers[i].num_responses < AVG_NUM){
447 if(verbose) {
448 printf("response from peer %d: ", i);
449 }
450
451 read(ufds[i].fd, &req[i], sizeof(ntp_message));
452 gettimeofday(&recv_time, NULL);
453 DBG(print_ntp_message(&req[i]));
454 respnum=servers[i].num_responses++;
455 servers[i].offset[respnum]=calc_offset(&req[i], &recv_time);
456 if(verbose) {
457 printf("offset %.10g\n", servers[i].offset[respnum]);
458 }
459 servers[i].stratum=req[i].stratum;
460 servers[i].rtdisp=NTP32asDOUBLE(req[i].rtdisp);
461 servers[i].rtdelay=NTP32asDOUBLE(req[i].rtdelay);
462 servers[i].waiting=0;
463 servers[i].flags=req[i].flags;
464 servers_readable--;
465 one_read = 1;
466 if(servers[i].num_responses==AVG_NUM) servers_completed++;
467 }
468 }
469 /* lather, rinse, repeat. */
470 }
471
472 if (one_read == 0) {
473 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
474 }
475
476 /* now, pick the best server from the list */
477 best_index=best_offset_server(servers, num_hosts);
478 if(best_index < 0){
479 *status=STATE_UNKNOWN;
480 } else {
481 /* finally, calculate the average offset */
482 for(i=0; i<servers[best_index].num_responses;i++){
483 avg_offset+=servers[best_index].offset[i];
484 }
485 avg_offset/=servers[best_index].num_responses;
486 }
487
488 /* cleanup */
489 /* FIXME: Not closing the socket to avoid reuse of the local port
490 * which can cause old NTP packets to be read instead of NTP control
491 * packets in jitter_request(). THERE MUST BE ANOTHER WAY...
492 * for(j=0; j<num_hosts; j++){ close(socklist[j]); } */
493 free(socklist);
494 free(ufds);
495 free(servers);
496 free(req);
497 freeaddrinfo(ai);
498
499 if(verbose) printf("overall average offset: %.10g\n", avg_offset);
500 return avg_offset;
501}
502
503void
504setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq){
505 memset(p, 0, sizeof(ntp_control_message));
506 LI_SET(p->flags, LI_NOWARNING);
507 VN_SET(p->flags, VN_RESERVED);
508 MODE_SET(p->flags, MODE_CONTROLMSG);
509 OP_SET(p->op, opcode);
510 p->seq = htons(seq);
511 /* Remaining fields are zero for requests */
512}
513
514/* XXX handle responses with the error bit set */
515double jitter_request(int *status){
516 int conn=-1, i, npeers=0, num_candidates=0;
517 bool syncsource_found = false;
518 int run=0, min_peer_sel=PEER_INCLUDED, num_selected=0, num_valid=0;
519 int peers_size=0, peer_offset=0;
520 ntp_assoc_status_pair *peers=NULL;
521 ntp_control_message req;
522 const char *getvar = "jitter";
523 double rval = 0.0, jitter = -1.0;
524 char *startofvalue=NULL, *nptr=NULL;
525 void *tmp;
526
527 /* Long-winded explanation:
528 * Getting the jitter requires a number of steps:
529 * 1) Send a READSTAT request.
530 * 2) Interpret the READSTAT reply
531 * a) The data section contains a list of peer identifiers (16 bits)
532 * and associated status words (16 bits)
533 * b) We want the value of 0x06 in the SEL (peer selection) value,
534 * which means "current synchronizatin source". If that's missing,
535 * we take anything better than 0x04 (see the rfc for details) but
536 * set a minimum of warning.
537 * 3) Send a READVAR request for information on each peer identified
538 * in 2b greater than the minimum selection value.
539 * 4) Extract the jitter value from the data[] (it's ASCII)
540 */
541 my_udp_connect(server_address, 123, &conn);
542
543 /* keep sending requests until the server stops setting the
544 * REM_MORE bit, though usually this is only 1 packet. */
545 do{
546 setup_control_request(&req, OP_READSTAT, 1);
547 DBG(printf("sending READSTAT request"));
548 write(conn, &req, SIZEOF_NTPCM(req));
549 DBG(print_ntp_control_message(&req));
550 /* Attempt to read the largest size packet possible */
551 req.count=htons(MAX_CM_SIZE);
552 DBG(printf("receiving READSTAT response"))
553 read(conn, &req, SIZEOF_NTPCM(req));
554 DBG(print_ntp_control_message(&req));
555 /* Each peer identifier is 4 bytes in the data section, which
556 * we represent as a ntp_assoc_status_pair datatype.
557 */
558 peers_size+=ntohs(req.count);
559 if((tmp=realloc(peers, peers_size)) == NULL)
560 free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n");
561 peers=tmp;
562 memcpy((void*)((ptrdiff_t)peers+peer_offset), (void*)req.data, ntohs(req.count));
563 npeers=peers_size/sizeof(ntp_assoc_status_pair);
564 peer_offset+=ntohs(req.count);
565 } while(req.op&REM_MORE);
566
567 /* first, let's find out if we have a sync source, or if there are
568 * at least some candidates. in the case of the latter we'll issue
569 * a warning but go ahead with the check on them. */
570 for (i = 0; i < npeers; i++){
571 if (PEER_SEL(peers[i].status) >= PEER_INCLUDED){
572 num_candidates++;
573 if(PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE){
574 syncsource_found = true;
575 min_peer_sel=PEER_SYNCSOURCE;
576 }
577 }
578 }
579 if(verbose) printf("%d candidate peers available\n", num_candidates);
580 if(verbose && syncsource_found) printf("synchronization source found\n");
581 if(! syncsource_found){
582 *status = STATE_UNKNOWN;
583 if(verbose) printf("warning: no synchronization source found\n");
584 }
585
586
587 for (run=0; run<AVG_NUM; run++){
588 if(verbose) printf("jitter run %d of %d\n", run+1, AVG_NUM);
589 for (i = 0; i < npeers; i++){
590 /* Only query this server if it is the current sync source */
591 if (PEER_SEL(peers[i].status) >= min_peer_sel){
592 char jitter_data[MAX_CM_SIZE+1];
593 size_t jitter_data_count;
594
595 num_selected++;
596 setup_control_request(&req, OP_READVAR, 2);
597 req.assoc = peers[i].assoc;
598 /* By spec, putting the variable name "jitter" in the request
599 * should cause the server to provide _only_ the jitter value.
600 * thus reducing net traffic, guaranteeing us only a single
601 * datagram in reply, and making interpretation much simpler
602 */
603 /* Older servers doesn't know what jitter is, so if we get an
604 * error on the first pass we redo it with "dispersion" */
605 strncpy(req.data, getvar, MAX_CM_SIZE-1);
606 req.count = htons(strlen(getvar));
607 DBG(printf("sending READVAR request...\n"));
608 write(conn, &req, SIZEOF_NTPCM(req));
609 DBG(print_ntp_control_message(&req));
610
611 req.count = htons(MAX_CM_SIZE);
612 DBG(printf("receiving READVAR response...\n"));
613 read(conn, &req, SIZEOF_NTPCM(req));
614 DBG(print_ntp_control_message(&req));
615
616 if(req.op&REM_ERROR && strstr(getvar, "jitter")) {
617 if(verbose) printf("The 'jitter' command failed (old ntp server?)\nRestarting with 'dispersion'...\n");
618 getvar = "dispersion";
619 num_selected--;
620 i--;
621 continue;
622 }
623
624 /* get to the float value */
625 if(verbose) {
626 printf("parsing jitter from peer %.2x: ", ntohs(peers[i].assoc));
627 }
628 if((jitter_data_count = ntohs(req.count)) >= sizeof(jitter_data)){
629 die(STATE_UNKNOWN,
630 _("jitter response too large (%lu bytes)\n"),
631 (unsigned long)jitter_data_count);
632 }
633 memcpy(jitter_data, req.data, jitter_data_count);
634 jitter_data[jitter_data_count] = '\0';
635 startofvalue = strchr(jitter_data, '=');
636 if(startofvalue != NULL) {
637 startofvalue++;
638 jitter = strtod(startofvalue, &nptr);
639 }
640 if(startofvalue == NULL || startofvalue==nptr){
641 printf("warning: unable to read server jitter response.\n");
642 *status = STATE_UNKNOWN;
643 } else {
644 if(verbose) printf("%g\n", jitter);
645 num_valid++;
646 rval += jitter;
647 }
648 }
649 }
650 if(verbose){
651 printf("jitter parsed from %d/%d peers\n", num_valid, num_selected);
652 }
653 }
654
655 rval = num_valid ? rval / num_valid : -1.0;
656
657 close(conn);
658 if(peers!=NULL) free(peers);
659 /* If we return -1.0, it means no synchronization source was found */
660 return rval;
661}
662
663int process_arguments(int argc, char **argv){
664 int c;
665 int option=0;
666 static struct option longopts[] = {
667 {"version", no_argument, 0, 'V'},
668 {"help", no_argument, 0, 'h'},
669 {"verbose", no_argument, 0, 'v'},
670 {"use-ipv4", no_argument, 0, '4'},
671 {"use-ipv6", no_argument, 0, '6'},
672 {"warning", required_argument, 0, 'w'},
673 {"critical", required_argument, 0, 'c'},
674 {"jwarn", required_argument, 0, 'j'},
675 {"jcrit", required_argument, 0, 'k'},
676 {"timeout", required_argument, 0, 't'},
677 {"hostname", required_argument, 0, 'H'},
678 {0, 0, 0, 0}
679 };
680
681
682 if (argc < 2)
683 usage ("\n");
684
685 while (1) {
686 c = getopt_long (argc, argv, "Vhv46w:c:j:k:t:H:", longopts, &option);
687 if (c == -1 || c == EOF || c == 1)
688 break;
689
690 switch (c) {
691 case 'h':
692 print_help();
693 exit(STATE_UNKNOWN);
694 break;
695 case 'V':
696 print_revision(progname, NP_VERSION);
697 exit(STATE_UNKNOWN);
698 break;
699 case 'v':
700 verbose++;
701 break;
702 case 'w':
703 do_offset = true;
704 owarn = optarg;
705 break;
706 case 'c':
707 do_offset = true;
708 ocrit = optarg;
709 break;
710 case 'j':
711 do_jitter = true;
712 jwarn = optarg;
713 break;
714 case 'k':
715 do_jitter = true;
716 jcrit = optarg;
717 break;
718 case 'H':
719 if(!is_host(optarg))
720 usage2(_("Invalid hostname/address"), optarg);
721 server_address = strdup(optarg);
722 break;
723 case 't':
724 socket_timeout=atoi(optarg);
725 break;
726 case '4':
727 address_family = AF_INET;
728 break;
729 case '6':
730#ifdef USE_IPV6
731 address_family = AF_INET6;
732#else
733 usage4 (_("IPv6 support not available"));
734#endif
735 break;
736 case '?':
737 /* print short usage statement if args not parsable */
738 usage5 ();
739 break;
740 }
741 }
742
743 if(server_address == NULL){
744 usage4(_("Hostname was not supplied"));
745 }
746
747 return 0;
748}
749
750char *perfd_offset (double offset)
751{
752 return fperfdata ("offset", offset, "s",
753 true, offset_thresholds->warning->end,
754 true, offset_thresholds->critical->end,
755 false, 0, false, 0);
756}
757
758char *perfd_jitter (double jitter)
759{
760 return fperfdata ("jitter", jitter, "s",
761 do_jitter, jitter_thresholds->warning->end,
762 do_jitter, jitter_thresholds->critical->end,
763 true, 0, false, 0);
764}
765
766int main(int argc, char *argv[]){
767 int result, offset_result, jitter_result;
768 double offset=0, jitter=0;
769 char *result_line, *perfdata_line;
770
771 setlocale (LC_ALL, "");
772 bindtextdomain (PACKAGE, LOCALEDIR);
773 textdomain (PACKAGE);
774
775 result = offset_result = jitter_result = STATE_OK;
776
777 /* Parse extra opts if any */
778 argv=np_extra_opts (&argc, argv, progname);
779
780 if (process_arguments (argc, argv) == ERROR)
781 usage4 (_("Could not parse arguments"));
782
783 set_thresholds(&offset_thresholds, owarn, ocrit);
784 set_thresholds(&jitter_thresholds, jwarn, jcrit);
785
786 /* initialize alarm signal handling */
787 signal (SIGALRM, socket_timeout_alarm_handler);
788
789 /* set socket timeout */
790 alarm (socket_timeout);
791
792 offset = offset_request(server_address, &offset_result);
793 /* check_ntp used to always return CRITICAL if offset_result == STATE_UNKNOWN.
794 * Now we'll only do that is the offset thresholds were set */
795 if (do_offset && offset_result == STATE_UNKNOWN) {
796 result = STATE_CRITICAL;
797 } else {
798 result = get_status(fabs(offset), offset_thresholds);
799 }
800
801 /* If not told to check the jitter, we don't even send packets.
802 * jitter is checked using NTP control packets, which not all
803 * servers recognize. Trying to check the jitter on OpenNTPD
804 * (for example) will result in an error
805 */
806 if(do_jitter){
807 jitter=jitter_request(&jitter_result);
808 result = max_state_alt(result, get_status(jitter, jitter_thresholds));
809 /* -1 indicates that we couldn't calculate the jitter
810 * Only overrides STATE_OK from the offset */
811 if(jitter == -1.0 && result == STATE_OK)
812 result = STATE_UNKNOWN;
813 }
814 result = max_state_alt(result, jitter_result);
815
816 switch (result) {
817 case STATE_CRITICAL :
818 xasprintf(&result_line, _("NTP CRITICAL:"));
819 break;
820 case STATE_WARNING :
821 xasprintf(&result_line, _("NTP WARNING:"));
822 break;
823 case STATE_OK :
824 xasprintf(&result_line, _("NTP OK:"));
825 break;
826 default :
827 xasprintf(&result_line, _("NTP UNKNOWN:"));
828 break;
829 }
830 if(offset_result == STATE_UNKNOWN){
831 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
832 xasprintf(&perfdata_line, "");
833 } else {
834 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
835 xasprintf(&perfdata_line, "%s", perfd_offset(offset));
836 }
837 if (do_jitter) {
838 xasprintf(&result_line, "%s, jitter=%f", result_line, jitter);
839 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(jitter));
840 }
841 printf("%s|%s\n", result_line, perfdata_line);
842
843 if(server_address!=NULL) free(server_address);
844 return result;
845}
846
847
848
849void print_help(void){
850 print_revision(progname, NP_VERSION);
851
852 printf ("Copyright (c) 2006 Sean Finney\n");
853 printf (COPYRIGHT, copyright, email);
854
855 printf ("%s\n", _("This plugin checks the selected ntp server"));
856
857 printf ("\n\n");
858
859 print_usage();
860 printf (UT_HELP_VRSN);
861 printf (UT_EXTRA_OPTS);
862 printf (UT_HOST_PORT, 'p', "123");
863 printf (UT_IPv46);
864 printf (" %s\n", "-w, --warning=THRESHOLD");
865 printf (" %s\n", _("Offset to result in warning status (seconds)"));
866 printf (" %s\n", "-c, --critical=THRESHOLD");
867 printf (" %s\n", _("Offset to result in critical status (seconds)"));
868 printf (" %s\n", "-j, --jwarn=THRESHOLD");
869 printf (" %s\n", _("Warning threshold for jitter"));
870 printf (" %s\n", "-k, --jcrit=THRESHOLD");
871 printf (" %s\n", _("Critical threshold for jitter"));
872 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
873 printf (UT_VERBOSE);
874
875 printf("\n");
876 printf("%s\n", _("Notes:"));
877 printf(UT_THRESHOLDS_NOTES);
878
879 printf("\n");
880 printf("%s\n", _("Examples:"));
881 printf(" %s\n", _("Normal offset check:"));
882 printf(" %s\n", ("./check_ntp -H ntpserv -w 0.5 -c 1"));
883 printf("\n");
884 printf(" %s\n", _("Check jitter too, avoiding critical notifications if jitter isn't available"));
885 printf(" %s\n", _("(See Notes above for more details on thresholds formats):"));
886 printf(" %s\n", ("./check_ntp -H ntpserv -w 0.5 -c 1 -j -1:100 -k -1:200"));
887
888 printf (UT_SUPPORT);
889
890 printf ("%s\n", _("WARNING: check_ntp is deprecated. Please use check_ntp_peer or"));
891 printf ("%s\n\n", _("check_ntp_time instead."));
892}
893
894void
895print_usage(void)
896{
897 printf ("%s\n", _("WARNING: check_ntp is deprecated. Please use check_ntp_peer or"));
898 printf ("%s\n\n", _("check_ntp_time instead."));
899 printf ("%s\n", _("Usage:"));
900 printf(" %s -H <host> [-w <warn>] [-c <crit>] [-j <warn>] [-k <crit>] [-4|-6] [-v verbose]\n", progname);
901}
diff --git a/plugins/check_ntp_peer.c b/plugins/check_ntp_peer.c
index f99e5032..26f74286 100644
--- a/plugins/check_ntp_peer.c
+++ b/plugins/check_ntp_peer.c
@@ -39,33 +39,23 @@ const char *progname = "check_ntp_peer";
39const char *copyright = "2006-2024"; 39const char *copyright = "2006-2024";
40const char *email = "devel@monitoring-plugins.org"; 40const char *email = "devel@monitoring-plugins.org";
41 41
42#include "output.h"
43#include "perfdata.h"
44#include <openssl/x509.h>
45#include "thresholds.h"
42#include "common.h" 46#include "common.h"
43#include "netutils.h" 47#include "netutils.h"
44#include "utils.h" 48#include "utils.h"
49#include "../lib/states.h"
50#include "check_ntp_peer.d/config.h"
45 51
46static char *server_address = NULL;
47static int port = 123;
48static int verbose = 0; 52static int verbose = 0;
49static bool quiet = false; 53
50static char *owarn = "60"; 54typedef struct {
51static char *ocrit = "120"; 55 int errorcode;
52static bool do_stratum = false; 56 check_ntp_peer_config config;
53static char *swarn = "-1:16"; 57} check_ntp_peer_config_wrapper;
54static char *scrit = "-1:16"; 58static check_ntp_peer_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
55static bool do_jitter = false;
56static char *jwarn = "-1:5000";
57static char *jcrit = "-1:10000";
58static bool do_truechimers = false;
59static char *twarn = "0:";
60static char *tcrit = "0:";
61static bool syncsource_found = false;
62static bool li_alarm = false;
63
64static int process_arguments(int /*argc*/, char ** /*argv*/);
65static thresholds *offset_thresholds = NULL;
66static thresholds *jitter_thresholds = NULL;
67static thresholds *stratum_thresholds = NULL;
68static thresholds *truechimer_thresholds = NULL;
69static void print_help(void); 59static void print_help(void);
70void print_usage(void); 60void print_usage(void);
71 61
@@ -94,9 +84,9 @@ typedef struct {
94/* bits 1,2 are the leap indicator */ 84/* bits 1,2 are the leap indicator */
95#define LI_MASK 0xc0 85#define LI_MASK 0xc0
96#define LI(x) ((x & LI_MASK) >> 6) 86#define LI(x) ((x & LI_MASK) >> 6)
97#define LI_SET(x, y) \ 87#define LI_SET(x, y) \
98 do { \ 88 do { \
99 x |= ((y << 6) & LI_MASK); \ 89 x |= ((y << 6) & LI_MASK); \
100 } while (0) 90 } while (0)
101/* and these are the values of the leap indicator */ 91/* and these are the values of the leap indicator */
102#define LI_NOWARNING 0x00 92#define LI_NOWARNING 0x00
@@ -106,17 +96,17 @@ typedef struct {
106/* bits 3,4,5 are the ntp version */ 96/* bits 3,4,5 are the ntp version */
107#define VN_MASK 0x38 97#define VN_MASK 0x38
108#define VN(x) ((x & VN_MASK) >> 3) 98#define VN(x) ((x & VN_MASK) >> 3)
109#define VN_SET(x, y) \ 99#define VN_SET(x, y) \
110 do { \ 100 do { \
111 x |= ((y << 3) & VN_MASK); \ 101 x |= ((y << 3) & VN_MASK); \
112 } while (0) 102 } while (0)
113#define VN_RESERVED 0x02 103#define VN_RESERVED 0x02
114/* bits 6,7,8 are the ntp mode */ 104/* bits 6,7,8 are the ntp mode */
115#define MODE_MASK 0x07 105#define MODE_MASK 0x07
116#define MODE(x) (x & MODE_MASK) 106#define MODE(x) (x & MODE_MASK)
117#define MODE_SET(x, y) \ 107#define MODE_SET(x, y) \
118 do { \ 108 do { \
119 x |= (y & MODE_MASK); \ 109 x |= (y & MODE_MASK); \
120 } while (0) 110 } while (0)
121/* here are some values */ 111/* here are some values */
122#define MODE_CLIENT 0x03 112#define MODE_CLIENT 0x03
@@ -128,9 +118,9 @@ typedef struct {
128#define REM_MORE 0x20 118#define REM_MORE 0x20
129/* In control message, bits 11 - 15 are opcode */ 119/* In control message, bits 11 - 15 are opcode */
130#define OP_MASK 0x1f 120#define OP_MASK 0x1f
131#define OP_SET(x, y) \ 121#define OP_SET(x, y) \
132 do { \ 122 do { \
133 x |= (y & OP_MASK); \ 123 x |= (y & OP_MASK); \
134 } while (0) 124 } while (0)
135#define OP_READSTAT 0x01 125#define OP_READSTAT 0x01
136#define OP_READVAR 0x02 126#define OP_READVAR 0x02
@@ -143,39 +133,40 @@ typedef struct {
143/* NTP control message header is 12 bytes, plus any data in the data 133/* NTP control message header is 12 bytes, plus any data in the data
144 * field, plus null padding to the nearest 32-bit boundary per rfc. 134 * field, plus null padding to the nearest 32-bit boundary per rfc.
145 */ 135 */
146#define SIZEOF_NTPCM(m) (12 + ntohs(m.count) + ((ntohs(m.count) % 4) ? 4 - (ntohs(m.count) % 4) : 0)) 136#define SIZEOF_NTPCM(m) \
137 (12 + ntohs(m.count) + ((ntohs(m.count) % 4) ? 4 - (ntohs(m.count) % 4) : 0))
147 138
148/* finally, a little helper or two for debugging: */ 139/* finally, a little helper or two for debugging: */
149#define DBG(x) \ 140#define DBG(x) \
150 do { \ 141 do { \
151 if (verbose > 1) { \ 142 if (verbose > 1) { \
152 x; \ 143 x; \
153 } \ 144 } \
154 } while (0); 145 } while (0);
155#define PRINTSOCKADDR(x) \ 146#define PRINTSOCKADDR(x) \
156 do { \ 147 do { \
157 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \ 148 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \
158 } while (0); 149 } while (0);
159 150
160void print_ntp_control_message(const ntp_control_message *p) { 151void print_ntp_control_message(const ntp_control_message *message) {
161 printf("control packet contents:\n"); 152 printf("control packet contents:\n");
162 printf("\tflags: 0x%.2x , 0x%.2x\n", p->flags, p->op); 153 printf("\tflags: 0x%.2x , 0x%.2x\n", message->flags, message->op);
163 printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags & LI_MASK); 154 printf("\t li=%d (0x%.2x)\n", LI(message->flags), message->flags & LI_MASK);
164 printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags & VN_MASK); 155 printf("\t vn=%d (0x%.2x)\n", VN(message->flags), message->flags & VN_MASK);
165 printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags & MODE_MASK); 156 printf("\t mode=%d (0x%.2x)\n", MODE(message->flags), message->flags & MODE_MASK);
166 printf("\t response=%d (0x%.2x)\n", (p->op & REM_RESP) > 0, p->op & REM_RESP); 157 printf("\t response=%d (0x%.2x)\n", (message->op & REM_RESP) > 0, message->op & REM_RESP);
167 printf("\t more=%d (0x%.2x)\n", (p->op & REM_MORE) > 0, p->op & REM_MORE); 158 printf("\t more=%d (0x%.2x)\n", (message->op & REM_MORE) > 0, message->op & REM_MORE);
168 printf("\t error=%d (0x%.2x)\n", (p->op & REM_ERROR) > 0, p->op & REM_ERROR); 159 printf("\t error=%d (0x%.2x)\n", (message->op & REM_ERROR) > 0, message->op & REM_ERROR);
169 printf("\t op=%d (0x%.2x)\n", p->op & OP_MASK, p->op & OP_MASK); 160 printf("\t op=%d (0x%.2x)\n", message->op & OP_MASK, message->op & OP_MASK);
170 printf("\tsequence: %d (0x%.2x)\n", ntohs(p->seq), ntohs(p->seq)); 161 printf("\tsequence: %d (0x%.2x)\n", ntohs(message->seq), ntohs(message->seq));
171 printf("\tstatus: %d (0x%.2x)\n", ntohs(p->status), ntohs(p->status)); 162 printf("\tstatus: %d (0x%.2x)\n", ntohs(message->status), ntohs(message->status));
172 printf("\tassoc: %d (0x%.2x)\n", ntohs(p->assoc), ntohs(p->assoc)); 163 printf("\tassoc: %d (0x%.2x)\n", ntohs(message->assoc), ntohs(message->assoc));
173 printf("\toffset: %d (0x%.2x)\n", ntohs(p->offset), ntohs(p->offset)); 164 printf("\toffset: %d (0x%.2x)\n", ntohs(message->offset), ntohs(message->offset));
174 printf("\tcount: %d (0x%.2x)\n", ntohs(p->count), ntohs(p->count)); 165 printf("\tcount: %d (0x%.2x)\n", ntohs(message->count), ntohs(message->count));
175 166
176 int numpeers = ntohs(p->count) / (sizeof(ntp_assoc_status_pair)); 167 int numpeers = ntohs(message->count) / (sizeof(ntp_assoc_status_pair));
177 if (p->op & REM_RESP && p->op & OP_READSTAT) { 168 if (message->op & REM_RESP && message->op & OP_READSTAT) {
178 const ntp_assoc_status_pair *peer = (ntp_assoc_status_pair *)p->data; 169 const ntp_assoc_status_pair *peer = (ntp_assoc_status_pair *)message->data;
179 for (int i = 0; i < numpeers; i++) { 170 for (int i = 0; i < numpeers; i++) {
180 printf("\tpeer id %.2x status %.2x", ntohs(peer[i].assoc), ntohs(peer[i].status)); 171 printf("\tpeer id %.2x status %.2x", ntohs(peer[i].assoc), ntohs(peer[i].status));
181 if (PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE) { 172 if (PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE) {
@@ -190,13 +181,13 @@ void print_ntp_control_message(const ntp_control_message *p) {
190 } 181 }
191} 182}
192 183
193void setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq) { 184void setup_control_request(ntp_control_message *message, uint8_t opcode, uint16_t seq) {
194 memset(p, 0, sizeof(ntp_control_message)); 185 memset(message, 0, sizeof(ntp_control_message));
195 LI_SET(p->flags, LI_NOWARNING); 186 LI_SET(message->flags, LI_NOWARNING);
196 VN_SET(p->flags, VN_RESERVED); 187 VN_SET(message->flags, VN_RESERVED);
197 MODE_SET(p->flags, MODE_CONTROLMSG); 188 MODE_SET(message->flags, MODE_CONTROLMSG);
198 OP_SET(p->op, opcode); 189 OP_SET(message->op, opcode);
199 p->seq = htons(seq); 190 message->seq = htons(seq);
200 /* Remaining fields are zero for requests */ 191 /* Remaining fields are zero for requests */
201} 192}
202 193
@@ -208,13 +199,28 @@ void setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq)
208 * positive value means a success retrieving the value. 199 * positive value means a success retrieving the value.
209 * - status is set to WARNING if there's no sync.peer (otherwise OK) and is 200 * - status is set to WARNING if there's no sync.peer (otherwise OK) and is
210 * the return value of the function. 201 * the return value of the function.
211 * status is pretty much useless as syncsource_found is a global variable 202 */
212 * used later in main to check is the server was synchronized. It works 203typedef struct {
213 * so I left it alone */ 204 mp_state_enum state;
214int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum, int *num_truechimers) { 205 mp_state_enum offset_result;
215 *offset_result = STATE_UNKNOWN; 206 double offset;
216 *jitter = *stratum = -1; 207 double jitter;
217 *num_truechimers = 0; 208 long stratum;
209 int num_truechimers;
210 bool syncsource_found;
211 bool li_alarm;
212} ntp_request_result;
213ntp_request_result ntp_request(const check_ntp_peer_config config) {
214
215 ntp_request_result result = {
216 .state = STATE_OK,
217 .offset_result = STATE_UNKNOWN,
218 .jitter = -1,
219 .stratum = -1,
220 .num_truechimers = 0,
221 .syncsource_found = false,
222 .li_alarm = false,
223 };
218 224
219 /* Long-winded explanation: 225 /* Long-winded explanation:
220 * Getting the sync peer offset, jitter and stratum requires a number of 226 * Getting the sync peer offset, jitter and stratum requires a number of
@@ -232,19 +238,16 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
232 * 4) Extract the offset, jitter and stratum value from the data[] 238 * 4) Extract the offset, jitter and stratum value from the data[]
233 * (it's ASCII) 239 * (it's ASCII)
234 */ 240 */
235 int min_peer_sel = PEER_INCLUDED;
236 int num_candidates = 0;
237 void *tmp;
238 ntp_assoc_status_pair *peers = NULL;
239 int peer_offset = 0;
240 int peers_size = 0;
241 int npeers = 0;
242 int conn = -1; 241 int conn = -1;
243 my_udp_connect(server_address, port, &conn); 242 my_udp_connect(config.server_address, config.port, &conn);
244 243
245 /* keep sending requests until the server stops setting the 244 /* keep sending requests until the server stops setting the
246 * REM_MORE bit, though usually this is only 1 packet. */ 245 * REM_MORE bit, though usually this is only 1 packet. */
247 ntp_control_message req; 246 ntp_control_message req;
247 ntp_assoc_status_pair *peers = NULL;
248 int peer_offset = 0;
249 size_t peers_size = 0;
250 size_t npeers = 0;
248 do { 251 do {
249 setup_control_request(&req, OP_READSTAT, 1); 252 setup_control_request(&req, OP_READSTAT, 1);
250 DBG(printf("sending READSTAT request")); 253 DBG(printf("sending READSTAT request"));
@@ -255,24 +258,29 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
255 /* Attempt to read the largest size packet possible */ 258 /* Attempt to read the largest size packet possible */
256 req.count = htons(MAX_CM_SIZE); 259 req.count = htons(MAX_CM_SIZE);
257 DBG(printf("receiving READSTAT response")) 260 DBG(printf("receiving READSTAT response"))
258 if (read(conn, &req, SIZEOF_NTPCM(req)) == -1) 261 if (read(conn, &req, SIZEOF_NTPCM(req)) == -1) {
259 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); 262 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
263 }
260 DBG(print_ntp_control_message(&req)); 264 DBG(print_ntp_control_message(&req));
261 /* discard obviously invalid packets */ 265 /* discard obviously invalid packets */
262 if (ntohs(req.count) > MAX_CM_SIZE) 266 if (ntohs(req.count) > MAX_CM_SIZE) {
263 die(STATE_CRITICAL, "NTP CRITICAL: Invalid packet received from NTP server\n"); 267 die(STATE_CRITICAL, "NTP CRITICAL: Invalid packet received from NTP server\n");
268 }
264 } while (!(req.op & OP_READSTAT && ntohs(req.seq) == 1)); 269 } while (!(req.op & OP_READSTAT && ntohs(req.seq) == 1));
265 270
266 if (LI(req.flags) == LI_ALARM) 271 if (LI(req.flags) == LI_ALARM) {
267 li_alarm = true; 272 result.li_alarm = true;
273 }
268 /* Each peer identifier is 4 bytes in the data section, which 274 /* Each peer identifier is 4 bytes in the data section, which
269 * we represent as a ntp_assoc_status_pair datatype. 275 * we represent as a ntp_assoc_status_pair datatype.
270 */ 276 */
271 peers_size += ntohs(req.count); 277 peers_size += ntohs(req.count);
272 if ((tmp = realloc(peers, peers_size)) == NULL) 278 void *tmp;
279 if ((tmp = realloc(peers, peers_size)) == NULL) {
273 free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n"); 280 free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n");
281 }
274 peers = tmp; 282 peers = tmp;
275 memcpy((void *)((ptrdiff_t)peers + peer_offset), (void *)req.data, ntohs(req.count)); 283 memcpy((peers + peer_offset), (void *)req.data, ntohs(req.count));
276 npeers = peers_size / sizeof(ntp_assoc_status_pair); 284 npeers = peers_size / sizeof(ntp_assoc_status_pair);
277 peer_offset += ntohs(req.count); 285 peer_offset += ntohs(req.count);
278 } while (req.op & REM_MORE); 286 } while (req.op & REM_MORE);
@@ -280,45 +288,51 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
280 /* first, let's find out if we have a sync source, or if there are 288 /* first, let's find out if we have a sync source, or if there are
281 * at least some candidates. In the latter case we'll issue 289 * at least some candidates. In the latter case we'll issue
282 * a warning but go ahead with the check on them. */ 290 * a warning but go ahead with the check on them. */
283 for (int i = 0; i < npeers; i++) { 291 int min_peer_sel = PEER_INCLUDED;
292 int num_candidates = 0;
293 for (size_t i = 0; i < npeers; i++) {
284 if (PEER_SEL(peers[i].status) >= PEER_TRUECHIMER) { 294 if (PEER_SEL(peers[i].status) >= PEER_TRUECHIMER) {
285 (*num_truechimers)++; 295 result.num_truechimers++;
286 if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) { 296 if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) {
287 num_candidates++; 297 num_candidates++;
288 if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) { 298 if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) {
289 syncsource_found = true; 299 result.syncsource_found = true;
290 min_peer_sel = PEER_SYNCSOURCE; 300 min_peer_sel = PEER_SYNCSOURCE;
291 } 301 }
292 } 302 }
293 } 303 }
294 } 304 }
295 305
296 if (verbose) 306 if (verbose) {
297 printf("%d candidate peers available\n", num_candidates); 307 printf("%d candidate peers available\n", num_candidates);
298 if (verbose && syncsource_found) 308 if (result.syncsource_found) {
299 printf("synchronization source found\n"); 309 printf("synchronization source found\n");
310 }
311 }
300 312
301 int status = STATE_OK; 313 if (!result.syncsource_found) {
302 if (!syncsource_found) { 314 result.state = STATE_WARNING;
303 status = STATE_WARNING; 315 if (verbose) {
304 if (verbose)
305 printf("warning: no synchronization source found\n"); 316 printf("warning: no synchronization source found\n");
317 }
306 } 318 }
307 if (li_alarm) { 319 if (result.li_alarm) {
308 status = STATE_WARNING; 320 result.state = STATE_WARNING;
309 if (verbose) 321 if (verbose) {
310 printf("warning: LI_ALARM bit is set\n"); 322 printf("warning: LI_ALARM bit is set\n");
323 }
311 } 324 }
312 325
313 const char *getvar = "stratum,offset,jitter"; 326 const char *getvar = "stratum,offset,jitter";
314 char *data; 327 char *data;
315 for (int i = 0; i < npeers; i++) { 328 for (size_t i = 0; i < npeers; i++) {
316 /* Only query this server if it is the current sync source */ 329 /* Only query this server if it is the current sync source */
317 /* If there's no sync.peer, query all candidates and use the best one */ 330 /* If there's no sync.peer, query all candidates and use the best one */
318 if (PEER_SEL(peers[i].status) >= min_peer_sel) { 331 if (PEER_SEL(peers[i].status) >= min_peer_sel) {
319 if (verbose) 332 if (verbose) {
320 printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc)); 333 printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc));
321 xasprintf(&data, ""); 334 }
335 data = strdup("");
322 do { 336 do {
323 setup_control_request(&req, OP_READVAR, 2); 337 setup_control_request(&req, OP_READVAR, 2);
324 req.assoc = peers[i].assoc; 338 req.assoc = peers[i].assoc;
@@ -342,81 +356,95 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
342 DBG(print_ntp_control_message(&req)); 356 DBG(print_ntp_control_message(&req));
343 } while (!(req.op & OP_READVAR && ntohs(req.seq) == 2)); 357 } while (!(req.op & OP_READVAR && ntohs(req.seq) == 2));
344 358
345 if (!(req.op & REM_ERROR)) 359 if (!(req.op & REM_ERROR)) {
346 xasprintf(&data, "%s%s", data, req.data); 360 xasprintf(&data, "%s%s", data, req.data);
361 }
347 } while (req.op & REM_MORE); 362 } while (req.op & REM_MORE);
348 363
349 if (req.op & REM_ERROR) { 364 if (req.op & REM_ERROR) {
350 if (strstr(getvar, "jitter")) { 365 if (strstr(getvar, "jitter")) {
351 if (verbose) 366 if (verbose) {
352 printf("The command failed. This is usually caused by servers refusing the 'jitter'\nvariable. Restarting with " 367 printf("The command failed. This is usually caused by servers refusing the "
368 "'jitter'\nvariable. Restarting with "
353 "'dispersion'...\n"); 369 "'dispersion'...\n");
370 }
354 getvar = "stratum,offset,dispersion"; 371 getvar = "stratum,offset,dispersion";
355 i--; 372 i--;
356 continue; 373 continue;
357 } 374 }
358 if (strlen(getvar)) { 375 if (strlen(getvar)) {
359 if (verbose) 376 if (verbose) {
360 printf("Server didn't like dispersion either; will retrieve everything\n"); 377 printf("Server didn't like dispersion either; will retrieve everything\n");
378 }
361 getvar = ""; 379 getvar = "";
362 i--; 380 i--;
363 continue; 381 continue;
364 } 382 }
365 } 383 }
366 384
367 if (verbose > 1) 385 if (verbose > 1) {
368 printf("Server responded: >>>%s<<<\n", data); 386 printf("Server responded: >>>%s<<<\n", data);
387 }
369 388
370 double tmp_offset = 0; 389 double tmp_offset = 0;
371 char *value; 390 char *value;
372 char *nptr; 391 char *nptr;
373 /* get the offset */ 392 /* get the offset */
374 if (verbose) 393 if (verbose) {
375 printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc)); 394 printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc));
395 }
376 396
377 value = np_extract_ntpvar(data, "offset"); 397 value = np_extract_ntpvar(data, "offset");
378 nptr = NULL; 398 nptr = NULL;
379 /* Convert the value if we have one */ 399 /* Convert the value if we have one */
380 if (value != NULL) 400 if (value != NULL) {
381 tmp_offset = strtod(value, &nptr) / 1000; 401 tmp_offset = strtod(value, &nptr) / 1000;
402 }
382 /* If value is null or no conversion was performed */ 403 /* If value is null or no conversion was performed */
383 if (value == NULL || value == nptr) { 404 if (value == NULL || value == nptr) {
384 if (verbose) 405 if (verbose) {
385 printf("error: unable to read server offset response.\n"); 406 printf("error: unable to read server offset response.\n");
407 }
386 } else { 408 } else {
387 if (verbose) 409 if (verbose) {
388 printf("%.10g\n", tmp_offset); 410 printf("%.10g\n", tmp_offset);
389 if (*offset_result == STATE_UNKNOWN || fabs(tmp_offset) < fabs(*offset)) { 411 }
390 *offset = tmp_offset; 412 if (result.offset_result == STATE_UNKNOWN ||
391 *offset_result = STATE_OK; 413 fabs(tmp_offset) < fabs(result.offset)) {
414 result.offset = tmp_offset;
415 result.offset_result = STATE_OK;
392 } else { 416 } else {
393 /* Skip this one; move to the next */ 417 /* Skip this one; move to the next */
394 continue; 418 continue;
395 } 419 }
396 } 420 }
397 421
398 if (do_jitter) { 422 if (config.do_jitter) {
399 /* get the jitter */ 423 /* get the jitter */
400 if (verbose) { 424 if (verbose) {
401 printf("parsing %s from peer %.2x: ", strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter", 425 printf("parsing %s from peer %.2x: ",
426 strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter",
402 ntohs(peers[i].assoc)); 427 ntohs(peers[i].assoc));
403 } 428 }
404 value = np_extract_ntpvar(data, strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter"); 429 value = np_extract_ntpvar(data, strstr(getvar, "dispersion") != NULL ? "dispersion"
430 : "jitter");
405 nptr = NULL; 431 nptr = NULL;
406 /* Convert the value if we have one */ 432 /* Convert the value if we have one */
407 if (value != NULL) 433 if (value != NULL) {
408 *jitter = strtod(value, &nptr); 434 result.jitter = strtod(value, &nptr);
435 }
409 /* If value is null or no conversion was performed */ 436 /* If value is null or no conversion was performed */
410 if (value == NULL || value == nptr) { 437 if (value == NULL || value == nptr) {
411 if (verbose) 438 if (verbose) {
412 printf("error: unable to read server jitter/dispersion response.\n"); 439 printf("error: unable to read server jitter/dispersion response.\n");
413 *jitter = -1; 440 }
441 result.jitter = -1;
414 } else if (verbose) { 442 } else if (verbose) {
415 printf("%.10g\n", *jitter); 443 printf("%.10g\n", result.jitter);
416 } 444 }
417 } 445 }
418 446
419 if (do_stratum) { 447 if (config.do_stratum) {
420 /* get the stratum */ 448 /* get the stratum */
421 if (verbose) { 449 if (verbose) {
422 printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc)); 450 printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc));
@@ -424,46 +452,86 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
424 value = np_extract_ntpvar(data, "stratum"); 452 value = np_extract_ntpvar(data, "stratum");
425 nptr = NULL; 453 nptr = NULL;
426 /* Convert the value if we have one */ 454 /* Convert the value if we have one */
427 if (value != NULL) 455 if (value != NULL) {
428 *stratum = strtol(value, &nptr, 10); 456 result.stratum = strtol(value, &nptr, 10);
457 }
429 if (value == NULL || value == nptr) { 458 if (value == NULL || value == nptr) {
430 if (verbose) 459 if (verbose) {
431 printf("error: unable to read server stratum response.\n"); 460 printf("error: unable to read server stratum response.\n");
432 *stratum = -1; 461 }
462 result.stratum = -1;
433 } else { 463 } else {
434 if (verbose) 464 if (verbose) {
435 printf("%i\n", *stratum); 465 printf("%li\n", result.stratum);
466 }
436 } 467 }
437 } 468 }
438 } /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */ 469 } /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */
439 } /* for (i = 0; i < npeers; i++) */ 470 } /* for (i = 0; i < npeers; i++) */
440 471
441 close(conn); 472 close(conn);
442 if (peers != NULL) 473 if (peers != NULL) {
443 free(peers); 474 free(peers);
475 }
444 476
445 return status; 477 return result;
446} 478}
447 479
448int process_arguments(int argc, char **argv) { 480check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
449 static struct option longopts[] = { 481
450 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'}, 482 enum {
451 {"use-ipv4", no_argument, 0, '4'}, {"use-ipv6", no_argument, 0, '6'}, {"quiet", no_argument, 0, 'q'}, 483 output_format_index = CHAR_MAX + 1,
452 {"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'}, {"swarn", required_argument, 0, 'W'}, 484 };
453 {"scrit", required_argument, 0, 'C'}, {"jwarn", required_argument, 0, 'j'}, {"jcrit", required_argument, 0, 'k'}, 485
454 {"twarn", required_argument, 0, 'm'}, {"tcrit", required_argument, 0, 'n'}, {"timeout", required_argument, 0, 't'}, 486 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
455 {"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'p'}, {0, 0, 0, 0}}; 487 {"help", no_argument, 0, 'h'},
456 488 {"verbose", no_argument, 0, 'v'},
457 if (argc < 2) 489 {"use-ipv4", no_argument, 0, '4'},
490 {"use-ipv6", no_argument, 0, '6'},
491 {"quiet", no_argument, 0, 'q'},
492 {"warning", required_argument, 0, 'w'},
493 {"critical", required_argument, 0, 'c'},
494 {"swarn", required_argument, 0, 'W'},
495 {"scrit", required_argument, 0, 'C'},
496 {"jwarn", required_argument, 0, 'j'},
497 {"jcrit", required_argument, 0, 'k'},
498 {"twarn", required_argument, 0, 'm'},
499 {"tcrit", required_argument, 0, 'n'},
500 {"timeout", required_argument, 0, 't'},
501 {"hostname", required_argument, 0, 'H'},
502 {"port", required_argument, 0, 'p'},
503 {"output-format", required_argument, 0, output_format_index},
504 {0, 0, 0, 0}};
505
506 if (argc < 2) {
458 usage("\n"); 507 usage("\n");
508 }
509
510 check_ntp_peer_config_wrapper result = {
511 .errorcode = OK,
512 .config = check_ntp_peer_config_init(),
513 };
459 514
460 while (true) { 515 while (true) {
461 int option = 0; 516 int option = 0;
462 int option_char = getopt_long(argc, argv, "Vhv46qw:c:W:C:j:k:m:n:t:H:p:", longopts, &option); 517 int option_char =
463 if (option_char == -1 || option_char == EOF || option_char == 1) 518 getopt_long(argc, argv, "Vhv46qw:c:W:C:j:k:m:n:t:H:p:", longopts, &option);
519 if (option_char == -1 || option_char == EOF || option_char == 1) {
464 break; 520 break;
521 }
465 522
466 switch (option_char) { 523 switch (option_char) {
524 case output_format_index: {
525 parsed_output_format parser = mp_parse_output_format(optarg);
526 if (!parser.parsing_success) {
527 printf("Invalid output format: %s\n", optarg);
528 exit(STATE_UNKNOWN);
529 }
530
531 result.config.output_format_is_set = true;
532 result.config.output_format = parser.output_format;
533 break;
534 }
467 case 'h': 535 case 'h':
468 print_help(); 536 print_help();
469 exit(STATE_UNKNOWN); 537 exit(STATE_UNKNOWN);
@@ -476,45 +544,94 @@ int process_arguments(int argc, char **argv) {
476 verbose++; 544 verbose++;
477 break; 545 break;
478 case 'q': 546 case 'q':
479 quiet = true; 547 result.config.quiet = true;
480 break;
481 case 'w':
482 owarn = optarg;
483 break;
484 case 'c':
485 ocrit = optarg;
486 break;
487 case 'W':
488 do_stratum = true;
489 swarn = optarg;
490 break;
491 case 'C':
492 do_stratum = true;
493 scrit = optarg;
494 break;
495 case 'j':
496 do_jitter = true;
497 jwarn = optarg;
498 break;
499 case 'k':
500 do_jitter = true;
501 jcrit = optarg;
502 break;
503 case 'm':
504 do_truechimers = true;
505 twarn = optarg;
506 break;
507 case 'n':
508 do_truechimers = true;
509 tcrit = optarg;
510 break; 548 break;
549 case 'w': {
550 mp_range_parsed tmp = mp_parse_range_string(optarg);
551 if (tmp.error != MP_PARSING_SUCCES) {
552 die(STATE_UNKNOWN, "failed to parse warning offset threshold");
553 }
554
555 result.config.offset_thresholds =
556 mp_thresholds_set_warn(result.config.offset_thresholds, tmp.range);
557 } break;
558 case 'c': {
559 mp_range_parsed tmp = mp_parse_range_string(optarg);
560 if (tmp.error != MP_PARSING_SUCCES) {
561 die(STATE_UNKNOWN, "failed to parse critical offset threshold");
562 }
563
564 result.config.offset_thresholds =
565 mp_thresholds_set_crit(result.config.offset_thresholds, tmp.range);
566 } break;
567 case 'W': {
568 result.config.do_stratum = true;
569 mp_range_parsed tmp = mp_parse_range_string(optarg);
570 if (tmp.error != MP_PARSING_SUCCES) {
571 die(STATE_UNKNOWN, "failed to parse warning stratum threshold");
572 }
573
574 result.config.stratum_thresholds =
575 mp_thresholds_set_warn(result.config.stratum_thresholds, tmp.range);
576 } break;
577 case 'C': {
578 result.config.do_stratum = true;
579 mp_range_parsed tmp = mp_parse_range_string(optarg);
580 if (tmp.error != MP_PARSING_SUCCES) {
581 die(STATE_UNKNOWN, "failed to parse critical stratum threshold");
582 }
583
584 result.config.stratum_thresholds =
585 mp_thresholds_set_crit(result.config.stratum_thresholds, tmp.range);
586 } break;
587 case 'j': {
588 result.config.do_jitter = true;
589 mp_range_parsed tmp = mp_parse_range_string(optarg);
590 if (tmp.error != MP_PARSING_SUCCES) {
591 die(STATE_UNKNOWN, "failed to parse warning jitter threshold");
592 }
593
594 result.config.jitter_thresholds =
595 mp_thresholds_set_warn(result.config.jitter_thresholds, tmp.range);
596 } break;
597 case 'k': {
598 result.config.do_jitter = true;
599 mp_range_parsed tmp = mp_parse_range_string(optarg);
600 if (tmp.error != MP_PARSING_SUCCES) {
601 die(STATE_UNKNOWN, "failed to parse critical jitter threshold");
602 }
603
604 result.config.jitter_thresholds =
605 mp_thresholds_set_crit(result.config.jitter_thresholds, tmp.range);
606 } break;
607 case 'm': {
608 result.config.do_truechimers = true;
609 mp_range_parsed tmp = mp_parse_range_string(optarg);
610 if (tmp.error != MP_PARSING_SUCCES) {
611 die(STATE_UNKNOWN, "failed to parse warning truechimer threshold");
612 }
613
614 result.config.truechimer_thresholds =
615 mp_thresholds_set_warn(result.config.truechimer_thresholds, tmp.range);
616 } break;
617 case 'n': {
618 result.config.do_truechimers = true;
619 mp_range_parsed tmp = mp_parse_range_string(optarg);
620 if (tmp.error != MP_PARSING_SUCCES) {
621 die(STATE_UNKNOWN, "failed to parse critical truechimer threshold");
622 }
623
624 result.config.truechimer_thresholds =
625 mp_thresholds_set_crit(result.config.truechimer_thresholds, tmp.range);
626 } break;
511 case 'H': 627 case 'H':
512 if (!is_host(optarg)) 628 if (!is_host(optarg) && (optarg[0] != '/')) {
513 usage2(_("Invalid hostname/address"), optarg); 629 usage2(_("Invalid hostname/address"), optarg);
514 server_address = strdup(optarg); 630 }
631 result.config.server_address = strdup(optarg);
515 break; 632 break;
516 case 'p': 633 case 'p':
517 port = atoi(optarg); 634 result.config.port = atoi(optarg);
518 break; 635 break;
519 case 't': 636 case 't':
520 socket_timeout = atoi(optarg); 637 socket_timeout = atoi(optarg);
@@ -536,30 +653,32 @@ int process_arguments(int argc, char **argv) {
536 } 653 }
537 } 654 }
538 655
539 if (server_address == NULL) { 656 if (result.config.server_address == NULL) {
540 usage4(_("Hostname was not supplied")); 657 usage4(_("Hostname was not supplied"));
541 } 658 }
542 659
543 return 0; 660 return result;
544} 661}
545 662
546char *perfd_offset(double offset) { 663char *perfd_offset(double offset, thresholds *offset_thresholds) {
547 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, offset_thresholds->critical->end, false, 0, false, 664 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true,
548 0); 665 offset_thresholds->critical->end, false, 0, false, 0);
549} 666}
550 667
551char *perfd_jitter(double jitter) { 668char *perfd_jitter(double jitter, bool do_jitter, thresholds *jitter_thresholds) {
552 return fperfdata("jitter", jitter, "", do_jitter, jitter_thresholds->warning->end, do_jitter, jitter_thresholds->critical->end, true, 0, 669 return fperfdata("jitter", jitter, "", do_jitter, jitter_thresholds->warning->end, do_jitter,
553 false, 0); 670 jitter_thresholds->critical->end, true, 0, false, 0);
554} 671}
555 672
556char *perfd_stratum(int stratum) { 673char *perfd_stratum(int stratum, bool do_stratum, thresholds *stratum_thresholds) {
557 return perfdata("stratum", stratum, "", do_stratum, (int)stratum_thresholds->warning->end, do_stratum, 674 return perfdata("stratum", stratum, "", do_stratum, (int)stratum_thresholds->warning->end,
558 (int)stratum_thresholds->critical->end, true, 0, true, 16); 675 do_stratum, (int)stratum_thresholds->critical->end, true, 0, true, 16);
559} 676}
560 677
561char *perfd_truechimers(int num_truechimers) { 678char *perfd_truechimers(int num_truechimers, const bool do_truechimers,
562 return perfdata("truechimers", num_truechimers, "", do_truechimers, (int)truechimer_thresholds->warning->end, do_truechimers, 679 thresholds *truechimer_thresholds) {
680 return perfdata("truechimers", num_truechimers, "", do_truechimers,
681 (int)truechimer_thresholds->warning->end, do_truechimers,
563 (int)truechimer_thresholds->critical->end, true, 0, false, 0); 682 (int)truechimer_thresholds->critical->end, true, 0, false, 0);
564} 683}
565 684
@@ -571,13 +690,17 @@ int main(int argc, char *argv[]) {
571 /* Parse extra opts if any */ 690 /* Parse extra opts if any */
572 argv = np_extra_opts(&argc, argv, progname); 691 argv = np_extra_opts(&argc, argv, progname);
573 692
574 if (process_arguments(argc, argv) == ERROR) 693 check_ntp_peer_config_wrapper tmp_config = process_arguments(argc, argv);
694
695 if (tmp_config.errorcode == ERROR) {
575 usage4(_("Could not parse arguments")); 696 usage4(_("Could not parse arguments"));
697 }
698
699 const check_ntp_peer_config config = tmp_config.config;
576 700
577 set_thresholds(&offset_thresholds, owarn, ocrit); 701 if (config.output_format_is_set) {
578 set_thresholds(&jitter_thresholds, jwarn, jcrit); 702 mp_set_format(config.output_format);
579 set_thresholds(&stratum_thresholds, swarn, scrit); 703 }
580 set_thresholds(&truechimer_thresholds, twarn, tcrit);
581 704
582 /* initialize alarm signal handling */ 705 /* initialize alarm signal handling */
583 signal(SIGALRM, socket_timeout_alarm_handler); 706 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -585,115 +708,114 @@ int main(int argc, char *argv[]) {
585 /* set socket timeout */ 708 /* set socket timeout */
586 alarm(socket_timeout); 709 alarm(socket_timeout);
587 710
588 int offset_result;
589 int stratum;
590 int num_truechimers;
591 double offset = 0;
592 double jitter = 0;
593 /* This returns either OK or WARNING (See comment preceding ntp_request) */ 711 /* This returns either OK or WARNING (See comment preceding ntp_request) */
594 int result = ntp_request(&offset, &offset_result, &jitter, &stratum, &num_truechimers); 712 const ntp_request_result ntp_res = ntp_request(config);
713 mp_check overall = mp_check_init();
595 714
596 if (offset_result == STATE_UNKNOWN) { 715 mp_subcheck sc_offset = mp_subcheck_init();
716 xasprintf(&sc_offset.output, "offset");
717 if (ntp_res.offset_result == STATE_UNKNOWN) {
597 /* if there's no sync peer (this overrides ntp_request output): */ 718 /* if there's no sync peer (this overrides ntp_request output): */
598 result = (quiet ? STATE_UNKNOWN : STATE_CRITICAL); 719 sc_offset =
720 mp_set_subcheck_state(sc_offset, (config.quiet ? STATE_UNKNOWN : STATE_CRITICAL));
721 xasprintf(&sc_offset.output, "%s unknown", sc_offset.output);
599 } else { 722 } else {
600 /* Be quiet if there's no candidates either */ 723 /* Be quiet if there's no candidates either */
601 if (quiet && result == STATE_WARNING) 724 mp_state_enum tmp = STATE_OK;
602 result = STATE_UNKNOWN; 725 if (config.quiet && ntp_res.state == STATE_WARNING) {
603 result = max_state_alt(result, get_status(fabs(offset), offset_thresholds)); 726 tmp = STATE_UNKNOWN;
604 } 727 }
605 728
606 int oresult = result; 729 xasprintf(&sc_offset.output, "%s: %.6fs", sc_offset.output, ntp_res.offset);
607 730
608 int tresult = STATE_UNKNOWN; 731 mp_perfdata pd_offset = perfdata_init();
732 pd_offset.value = mp_create_pd_value(fabs(ntp_res.offset));
733 pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds);
734 pd_offset.label = "offset";
735 pd_offset.uom = "s";
736 mp_add_perfdata_to_subcheck(&sc_offset, pd_offset);
609 737
610 if (do_truechimers) { 738 tmp = max_state_alt(tmp, mp_get_pd_status(pd_offset));
611 tresult = get_status(num_truechimers, truechimer_thresholds); 739 sc_offset = mp_set_subcheck_state(sc_offset, tmp);
612 result = max_state_alt(result, tresult);
613 } 740 }
614 741
615 int sresult = STATE_UNKNOWN; 742 mp_add_subcheck_to_check(&overall, sc_offset);
616 743
617 if (do_stratum) { 744 // truechimers
618 sresult = get_status(stratum, stratum_thresholds); 745 if (config.do_truechimers) {
619 result = max_state_alt(result, sresult); 746 mp_subcheck sc_truechimers = mp_subcheck_init();
620 } 747 xasprintf(&sc_truechimers.output, "truechimers: %i", ntp_res.num_truechimers);
748
749 mp_perfdata pd_truechimers = perfdata_init();
750 pd_truechimers.value = mp_create_pd_value(ntp_res.num_truechimers);
751 pd_truechimers.label = "truechimers";
752 pd_truechimers = mp_pd_set_thresholds(pd_truechimers, config.truechimer_thresholds);
753
754 mp_add_perfdata_to_subcheck(&sc_truechimers, pd_truechimers);
621 755
622 int jresult = STATE_UNKNOWN; 756 sc_truechimers = mp_set_subcheck_state(sc_truechimers, mp_get_pd_status(pd_truechimers));
623 757
624 if (do_jitter) { 758 mp_add_subcheck_to_check(&overall, sc_truechimers);
625 jresult = get_status(jitter, jitter_thresholds);
626 result = max_state_alt(result, jresult);
627 } 759 }
628 760
629 char *result_line; 761 if (config.do_stratum) {
630 switch (result) { 762 mp_subcheck sc_stratum = mp_subcheck_init();
631 case STATE_CRITICAL: 763 xasprintf(&sc_stratum.output, "stratum: %li", ntp_res.stratum);
632 xasprintf(&result_line, _("NTP CRITICAL:")); 764
633 break; 765 mp_perfdata pd_stratum = perfdata_init();
634 case STATE_WARNING: 766 pd_stratum.value = mp_create_pd_value(ntp_res.stratum);
635 xasprintf(&result_line, _("NTP WARNING:")); 767 pd_stratum = mp_pd_set_thresholds(pd_stratum, config.stratum_thresholds);
636 break; 768 pd_stratum.label = "stratum";
637 case STATE_OK: 769
638 xasprintf(&result_line, _("NTP OK:")); 770 mp_add_perfdata_to_subcheck(&sc_stratum, pd_stratum);
639 break; 771
640 default: 772 sc_stratum = mp_set_subcheck_state(sc_stratum, mp_get_pd_status(pd_stratum));
641 xasprintf(&result_line, _("NTP UNKNOWN:")); 773
642 break; 774 mp_add_subcheck_to_check(&overall, sc_stratum);
643 } 775 }
644 if (!syncsource_found) 776
645 xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized")); 777 if (config.do_jitter) {
646 else if (li_alarm) 778 mp_subcheck sc_jitter = mp_subcheck_init();
647 xasprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set")); 779 xasprintf(&sc_jitter.output, "jitter: %f", ntp_res.jitter);
648 780
649 char *perfdata_line; 781 mp_perfdata pd_jitter = perfdata_init();
650 if (offset_result == STATE_UNKNOWN) { 782 pd_jitter.value = mp_create_pd_value(ntp_res.jitter);
651 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); 783 pd_jitter = mp_pd_set_thresholds(pd_jitter, config.jitter_thresholds);
652 xasprintf(&perfdata_line, ""); 784 pd_jitter.label = "jitter";
653 } else if (oresult == STATE_WARNING) { 785
654 xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"), offset); 786 mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter);
655 } else if (oresult == STATE_CRITICAL) { 787
656 xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"), offset); 788 sc_jitter = mp_set_subcheck_state(sc_jitter, mp_get_pd_status(pd_jitter));
657 } else { 789 mp_add_subcheck_to_check(&overall, sc_jitter);
658 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
659 } 790 }
660 xasprintf(&perfdata_line, "%s", perfd_offset(offset)); 791
661 792 mp_subcheck sc_other_info = mp_subcheck_init();
662 if (do_jitter) { 793 sc_other_info = mp_set_subcheck_default_state(sc_other_info, STATE_OK);
663 if (jresult == STATE_WARNING) { 794 if (!ntp_res.syncsource_found) {
664 xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, jitter); 795 xasprintf(&sc_other_info.output, "%s", _("Server not synchronized"));
665 } else if (jresult == STATE_CRITICAL) { 796 mp_add_subcheck_to_check(&overall, sc_other_info);
666 xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, jitter); 797 } else if (ntp_res.li_alarm) {
667 } else { 798 xasprintf(&sc_other_info.output, "%s", _("Server has the LI_ALARM bit set"));
668 xasprintf(&result_line, "%s, jitter=%f", result_line, jitter); 799 mp_add_subcheck_to_check(&overall, sc_other_info);
669 }
670 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(jitter));
671 } 800 }
672 if (do_stratum) { 801
673 if (sresult == STATE_WARNING) { 802 {
674 xasprintf(&result_line, "%s, stratum=%i (WARNING)", result_line, stratum); 803 mp_subcheck sc_offset = mp_subcheck_init();
675 } else if (sresult == STATE_CRITICAL) { 804 sc_offset = mp_set_subcheck_default_state(sc_offset, STATE_OK);
676 xasprintf(&result_line, "%s, stratum=%i (CRITICAL)", result_line, stratum); 805 xasprintf(&sc_offset.output, "offset: %.10gs", ntp_res.offset);
677 } else { 806
678 xasprintf(&result_line, "%s, stratum=%i", result_line, stratum); 807 mp_perfdata pd_offset = perfdata_init();
679 } 808 pd_offset.value = mp_create_pd_value(ntp_res.offset);
680 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_stratum(stratum)); 809 pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds);
810
811 sc_offset = mp_set_subcheck_state(sc_offset, ntp_res.offset_result);
681 } 812 }
682 if (do_truechimers) { 813
683 if (tresult == STATE_WARNING) { 814 if (config.server_address != NULL) {
684 xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line, num_truechimers); 815 free(config.server_address);
685 } else if (tresult == STATE_CRITICAL) {
686 xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line, num_truechimers);
687 } else {
688 xasprintf(&result_line, "%s, truechimers=%i", result_line, num_truechimers);
689 }
690 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_truechimers(num_truechimers));
691 } 816 }
692 printf("%s|%s\n", result_line, perfdata_line);
693 817
694 if (server_address != NULL) 818 mp_exit(overall);
695 free(server_address);
696 return result;
697} 819}
698 820
699void print_help(void) { 821void print_help(void) {
@@ -712,7 +834,8 @@ void print_help(void) {
712 printf(UT_IPv46); 834 printf(UT_IPv46);
713 printf(UT_HOST_PORT, 'p', "123"); 835 printf(UT_HOST_PORT, 'p', "123");
714 printf(" %s\n", "-q, --quiet"); 836 printf(" %s\n", "-q, --quiet");
715 printf(" %s\n", _("Returns UNKNOWN instead of CRITICAL or WARNING if server isn't synchronized")); 837 printf(" %s\n",
838 _("Returns UNKNOWN instead of CRITICAL or WARNING if server isn't synchronized"));
716 printf(" %s\n", "-w, --warning=THRESHOLD"); 839 printf(" %s\n", "-w, --warning=THRESHOLD");
717 printf(" %s\n", _("Offset to result in warning status (seconds)")); 840 printf(" %s\n", _("Offset to result in warning status (seconds)"));
718 printf(" %s\n", "-c, --critical=THRESHOLD"); 841 printf(" %s\n", "-c, --critical=THRESHOLD");
@@ -731,6 +854,7 @@ void print_help(void) {
731 printf(" %s\n", _("Critical threshold for number of usable time sources (\"truechimers\")")); 854 printf(" %s\n", _("Critical threshold for number of usable time sources (\"truechimers\")"));
732 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 855 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
733 printf(UT_VERBOSE); 856 printf(UT_VERBOSE);
857 printf(UT_OUTPUT_FORMAT);
734 858
735 printf("\n"); 859 printf("\n");
736 printf("%s\n", _("This plugin checks an NTP server independent of any commandline")); 860 printf("%s\n", _("This plugin checks an NTP server independent of any commandline"));
@@ -749,7 +873,8 @@ void print_help(void) {
749 printf(" %s\n", _("Simple NTP server check:")); 873 printf(" %s\n", _("Simple NTP server check:"));
750 printf(" %s\n", ("./check_ntp_peer -H ntpserv -w 0.5 -c 1")); 874 printf(" %s\n", ("./check_ntp_peer -H ntpserv -w 0.5 -c 1"));
751 printf("\n"); 875 printf("\n");
752 printf(" %s\n", _("Check jitter too, avoiding critical notifications if jitter isn't available")); 876 printf(" %s\n",
877 _("Check jitter too, avoiding critical notifications if jitter isn't available"));
753 printf(" %s\n", _("(See Notes above for more details on thresholds formats):")); 878 printf(" %s\n", _("(See Notes above for more details on thresholds formats):"));
754 printf(" %s\n", ("./check_ntp_peer -H ntpserv -w 0.5 -c 1 -j -1:100 -k -1:200")); 879 printf(" %s\n", ("./check_ntp_peer -H ntpserv -w 0.5 -c 1 -j -1:100 -k -1:200"));
755 printf("\n"); 880 printf("\n");
diff --git a/plugins/check_ntp_peer.d/config.h b/plugins/check_ntp_peer.d/config.h
new file mode 100644
index 00000000..488d936c
--- /dev/null
+++ b/plugins/check_ntp_peer.d/config.h
@@ -0,0 +1,82 @@
1#pragma once
2
3#include "../../config.h"
4#include "output.h"
5#include "perfdata.h"
6#include "thresholds.h"
7#include <stddef.h>
8
9enum {
10 DEFAULT_NTP_PORT = 123,
11};
12
13typedef struct {
14 char *server_address;
15 int port;
16
17 bool quiet;
18
19 // truechimer stuff
20 bool do_truechimers;
21 mp_thresholds truechimer_thresholds;
22
23 // offset thresholds
24 mp_thresholds offset_thresholds;
25
26 // stratum stuff
27 bool do_stratum;
28 mp_thresholds stratum_thresholds;
29
30 // jitter stuff
31 bool do_jitter;
32 mp_thresholds jitter_thresholds;
33
34 bool output_format_is_set;
35 mp_output_format output_format;
36} check_ntp_peer_config;
37
38check_ntp_peer_config check_ntp_peer_config_init() {
39 check_ntp_peer_config tmp = {
40 .server_address = NULL,
41 .port = DEFAULT_NTP_PORT,
42
43 .quiet = false,
44 .do_truechimers = false,
45 .truechimer_thresholds = mp_thresholds_init(),
46
47 .offset_thresholds = mp_thresholds_init(),
48
49 .do_stratum = false,
50 .stratum_thresholds = mp_thresholds_init(),
51
52 .do_jitter = false,
53 .jitter_thresholds = mp_thresholds_init(),
54
55 .output_format_is_set = false,
56 };
57
58 mp_range stratum_default = mp_range_init();
59 stratum_default = mp_range_set_start(stratum_default, mp_create_pd_value(-1));
60 stratum_default = mp_range_set_end(stratum_default, mp_create_pd_value(16));
61 tmp.stratum_thresholds = mp_thresholds_set_warn(tmp.stratum_thresholds, stratum_default);
62 tmp.stratum_thresholds = mp_thresholds_set_crit(tmp.stratum_thresholds, stratum_default);
63
64 mp_range jitter_w_default = mp_range_init();
65 jitter_w_default = mp_range_set_start(jitter_w_default, mp_create_pd_value(-1));
66 jitter_w_default = mp_range_set_end(jitter_w_default, mp_create_pd_value(5000));
67 tmp.jitter_thresholds = mp_thresholds_set_warn(tmp.jitter_thresholds, jitter_w_default);
68
69 mp_range jitter_c_default = mp_range_init();
70 jitter_c_default = mp_range_set_start(jitter_c_default, mp_create_pd_value(-1));
71 jitter_c_default = mp_range_set_end(jitter_c_default, mp_create_pd_value(10000));
72 tmp.jitter_thresholds = mp_thresholds_set_crit(tmp.jitter_thresholds, jitter_c_default);
73
74 mp_range offset_w_default = mp_range_init();
75 offset_w_default = mp_range_set_end(offset_w_default, mp_create_pd_value(60));
76 tmp.offset_thresholds = mp_thresholds_set_warn(tmp.offset_thresholds, offset_w_default);
77
78 mp_range offset_c_default = mp_range_init();
79 offset_c_default = mp_range_set_end(offset_c_default, mp_create_pd_value(120));
80 tmp.offset_thresholds = mp_thresholds_set_crit(tmp.offset_thresholds, offset_c_default);
81 return tmp;
82}
diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c
index 31162883..9e0beb9c 100644
--- a/plugins/check_ntp_time.c
+++ b/plugins/check_ntp_time.c
@@ -34,19 +34,23 @@
34 * 34 *
35 *****************************************************************************/ 35 *****************************************************************************/
36 36
37const char *progname = "check_ntp_time"; 37#include "output.h"
38const char *copyright = "2006-2024";
39const char *email = "devel@monitoring-plugins.org";
40
41#include "common.h" 38#include "common.h"
42#include "netutils.h" 39#include "netutils.h"
40#include "perfdata.h"
43#include "utils.h" 41#include "utils.h"
44#include "states.h" 42#include "states.h"
45#include "thresholds.h" 43#include "thresholds.h"
46#include "check_ntp_time.d/config.h" 44#include "check_ntp_time.d/config.h"
45#include <netinet/in.h>
46#include <sys/socket.h>
47 47
48static int verbose = 0; 48static int verbose = 0;
49 49
50const char *progname = "check_ntp_time";
51const char *copyright = "2006-2024";
52const char *email = "devel@monitoring-plugins.org";
53
50typedef struct { 54typedef struct {
51 int errorcode; 55 int errorcode;
52 check_ntp_time_config config; 56 check_ntp_time_config config;
@@ -61,9 +65,6 @@ void print_usage(void);
61# define AVG_NUM 4 65# define AVG_NUM 4
62#endif 66#endif
63 67
64/* max size of control message data */
65#define MAX_CM_SIZE 468
66
67/* this structure holds everything in an ntp request/response as per rfc1305 */ 68/* this structure holds everything in an ntp request/response as per rfc1305 */
68typedef struct { 69typedef struct {
69 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ 70 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
@@ -93,9 +94,9 @@ typedef struct {
93/* bits 1,2 are the leap indicator */ 94/* bits 1,2 are the leap indicator */
94#define LI_MASK 0xc0 95#define LI_MASK 0xc0
95#define LI(x) ((x & LI_MASK) >> 6) 96#define LI(x) ((x & LI_MASK) >> 6)
96#define LI_SET(x, y) \ 97#define LI_SET(x, y) \
97 do { \ 98 do { \
98 x |= ((y << 6) & LI_MASK); \ 99 x |= ((y << 6) & LI_MASK); \
99 } while (0) 100 } while (0)
100/* and these are the values of the leap indicator */ 101/* and these are the values of the leap indicator */
101#define LI_NOWARNING 0x00 102#define LI_NOWARNING 0x00
@@ -105,17 +106,17 @@ typedef struct {
105/* bits 3,4,5 are the ntp version */ 106/* bits 3,4,5 are the ntp version */
106#define VN_MASK 0x38 107#define VN_MASK 0x38
107#define VN(x) ((x & VN_MASK) >> 3) 108#define VN(x) ((x & VN_MASK) >> 3)
108#define VN_SET(x, y) \ 109#define VN_SET(x, y) \
109 do { \ 110 do { \
110 x |= ((y << 3) & VN_MASK); \ 111 x |= ((y << 3) & VN_MASK); \
111 } while (0) 112 } while (0)
112#define VN_RESERVED 0x02 113#define VN_RESERVED 0x02
113/* bits 6,7,8 are the ntp mode */ 114/* bits 6,7,8 are the ntp mode */
114#define MODE_MASK 0x07 115#define MODE_MASK 0x07
115#define MODE(x) (x & MODE_MASK) 116#define MODE(x) (x & MODE_MASK)
116#define MODE_SET(x, y) \ 117#define MODE_SET(x, y) \
117 do { \ 118 do { \
118 x |= (y & MODE_MASK); \ 119 x |= (y & MODE_MASK); \
119 } while (0) 120 } while (0)
120/* here are some values */ 121/* here are some values */
121#define MODE_CLIENT 0x03 122#define MODE_CLIENT 0x03
@@ -127,9 +128,9 @@ typedef struct {
127#define REM_MORE 0x20 128#define REM_MORE 0x20
128/* In control message, bits 11 - 15 are opcode */ 129/* In control message, bits 11 - 15 are opcode */
129#define OP_MASK 0x1f 130#define OP_MASK 0x1f
130#define OP_SET(x, y) \ 131#define OP_SET(x, y) \
131 do { \ 132 do { \
132 x |= (y & OP_MASK); \ 133 x |= (y & OP_MASK); \
133 } while (0) 134 } while (0)
134#define OP_READSTAT 0x01 135#define OP_READSTAT 0x01
135#define OP_READVAR 0x02 136#define OP_READVAR 0x02
@@ -163,32 +164,36 @@ typedef struct {
163#define NTP32asDOUBLE(x) (ntohs(L16(x)) + ((double)ntohs(R16(x)) / 65536.0)) 164#define NTP32asDOUBLE(x) (ntohs(L16(x)) + ((double)ntohs(R16(x)) / 65536.0))
164 165
165/* likewise for a 64-bit ntp fp number */ 166/* likewise for a 64-bit ntp fp number */
166#define NTP64asDOUBLE(n) \ 167#define NTP64asDOUBLE(n) \
167 (double)(((uint64_t)n) ? (ntohl(L32(n)) - EPOCHDIFF) + (.00000001 * (0.5 + (double)(ntohl(R32(n)) / 42.94967296))) : 0) 168 (double)(((uint64_t)n) ? (ntohl(L32(n)) - EPOCHDIFF) + \
169 (.00000001 * (0.5 + (double)(ntohl(R32(n)) / 42.94967296))) \
170 : 0)
168 171
169/* convert a struct timeval to a double */ 172/* convert a struct timeval to a double */
170#define TVasDOUBLE(x) (double)(x.tv_sec + (0.000001 * x.tv_usec)) 173static double TVasDOUBLE(struct timeval time) {
174 return ((double)time.tv_sec + (0.000001 * (double)time.tv_usec));
175}
171 176
172/* convert an ntp 64-bit fp number to a struct timeval */ 177/* convert an ntp 64-bit fp number to a struct timeval */
173#define NTP64toTV(n, t) \ 178#define NTP64toTV(n, t) \
174 do { \ 179 do { \
175 if (!n) \ 180 if (!n) \
176 t.tv_sec = t.tv_usec = 0; \ 181 t.tv_sec = t.tv_usec = 0; \
177 else { \ 182 else { \
178 t.tv_sec = ntohl(L32(n)) - EPOCHDIFF; \ 183 t.tv_sec = ntohl(L32(n)) - EPOCHDIFF; \
179 t.tv_usec = (int)(0.5 + (double)(ntohl(R32(n)) / 4294.967296)); \ 184 t.tv_usec = (int)(0.5 + (double)(ntohl(R32(n)) / 4294.967296)); \
180 } \ 185 } \
181 } while (0) 186 } while (0)
182 187
183/* convert a struct timeval to an ntp 64-bit fp number */ 188/* convert a struct timeval to an ntp 64-bit fp number */
184#define TVtoNTP64(t, n) \ 189#define TVtoNTP64(t, n) \
185 do { \ 190 do { \
186 if (!t.tv_usec && !t.tv_sec) \ 191 if (!t.tv_usec && !t.tv_sec) \
187 n = 0x0UL; \ 192 n = 0x0UL; \
188 else { \ 193 else { \
189 L32(n) = htonl(t.tv_sec + EPOCHDIFF); \ 194 L32(n) = htonl(t.tv_sec + EPOCHDIFF); \
190 R32(n) = htonl((uint64_t)((4294.967296 * t.tv_usec) + .5)); \ 195 R32(n) = htonl((uint64_t)((4294.967296 * t.tv_usec) + .5)); \
191 } \ 196 } \
192 } while (0) 197 } while (0)
193 198
194/* NTP control message header is 12 bytes, plus any data in the data 199/* NTP control message header is 12 bytes, plus any data in the data
@@ -197,15 +202,15 @@ typedef struct {
197#define SIZEOF_NTPCM(m) (12 + ntohs(m.count) + ((m.count) ? 4 - (ntohs(m.count) % 4) : 0)) 202#define SIZEOF_NTPCM(m) (12 + ntohs(m.count) + ((m.count) ? 4 - (ntohs(m.count) % 4) : 0))
198 203
199/* finally, a little helper or two for debugging: */ 204/* finally, a little helper or two for debugging: */
200#define DBG(x) \ 205#define DBG(x) \
201 do { \ 206 do { \
202 if (verbose > 1) { \ 207 if (verbose > 1) { \
203 x; \ 208 x; \
204 } \ 209 } \
205 } while (0); 210 } while (0);
206#define PRINTSOCKADDR(x) \ 211#define PRINTSOCKADDR(x) \
207 do { \ 212 do { \
208 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \ 213 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \
209 } while (0); 214 } while (0);
210 215
211/* calculate the offset of the local clock */ 216/* calculate the offset of the local clock */
@@ -260,8 +265,8 @@ void setup_request(ntp_message *message) {
260/* select the "best" server from a list of servers, and return its index. 265/* select the "best" server from a list of servers, and return its index.
261 * this is done by filtering servers based on stratum, dispersion, and 266 * this is done by filtering servers based on stratum, dispersion, and
262 * finally round-trip delay. */ 267 * finally round-trip delay. */
263int best_offset_server(const ntp_server_results *slist, int nservers) { 268static int best_offset_server(const ntp_server_results *slist, int nservers) {
264 int best_server = -1; 269 int best_server_index = -1;
265 270
266 /* for each server */ 271 /* for each server */
267 for (int cserver = 0; cserver < nservers; cserver++) { 272 for (int cserver = 0; cserver < nservers; cserver++) {
@@ -284,33 +289,33 @@ int best_offset_server(const ntp_server_results *slist, int nservers) {
284 } 289 }
285 290
286 /* If we don't have a server yet, use the first one */ 291 /* If we don't have a server yet, use the first one */
287 if (best_server == -1) { 292 if (best_server_index == -1) {
288 best_server = cserver; 293 best_server_index = cserver;
289 DBG(printf("using peer %d as our first candidate\n", best_server)); 294 DBG(printf("using peer %d as our first candidate\n", best_server_index));
290 continue; 295 continue;
291 } 296 }
292 297
293 /* compare the server to the best one we've seen so far */ 298 /* compare the server to the best one we've seen so far */
294 /* does it have an equal or better stratum? */ 299 /* does it have an equal or better stratum? */
295 DBG(printf("comparing peer %d with peer %d\n", cserver, best_server)); 300 DBG(printf("comparing peer %d with peer %d\n", cserver, best_server_index));
296 if (slist[cserver].stratum <= slist[best_server].stratum) { 301 if (slist[cserver].stratum <= slist[best_server_index].stratum) {
297 DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server)); 302 DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server_index));
298 /* does it have an equal or better dispersion? */ 303 /* does it have an equal or better dispersion? */
299 if (slist[cserver].rtdisp <= slist[best_server].rtdisp) { 304 if (slist[cserver].rtdisp <= slist[best_server_index].rtdisp) {
300 DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server)); 305 DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server_index));
301 /* does it have a better rtdelay? */ 306 /* does it have a better rtdelay? */
302 if (slist[cserver].rtdelay < slist[best_server].rtdelay) { 307 if (slist[cserver].rtdelay < slist[best_server_index].rtdelay) {
303 DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server)); 308 DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server_index));
304 best_server = cserver; 309 best_server_index = cserver;
305 DBG(printf("peer %d is now our best candidate\n", best_server)); 310 DBG(printf("peer %d is now our best candidate\n", best_server_index));
306 } 311 }
307 } 312 }
308 } 313 }
309 } 314 }
310 315
311 if (best_server >= 0) { 316 if (best_server_index >= 0) {
312 DBG(printf("best server selected: peer %d\n", best_server)); 317 DBG(printf("best server selected: peer %d\n", best_server_index));
313 return best_server; 318 return best_server_index;
314 } 319 }
315 DBG(printf("no peers meeting synchronization criteria :(\n")); 320 DBG(printf("no peers meeting synchronization criteria :(\n"));
316 return -1; 321 return -1;
@@ -321,7 +326,11 @@ int best_offset_server(const ntp_server_results *slist, int nservers) {
321 * we don't waste time sitting around waiting for single packets. 326 * we don't waste time sitting around waiting for single packets.
322 * - we also "manually" handle resolving host names and connecting, because 327 * - we also "manually" handle resolving host names and connecting, because
323 * we have to do it in a way that our lazy macros don't handle currently :( */ 328 * we have to do it in a way that our lazy macros don't handle currently :( */
324double offset_request(const char *host, const char *port, mp_state_enum *status, int time_offset) { 329typedef struct {
330 mp_state_enum offset_result;
331 double offset;
332} offset_request_wrapper;
333static offset_request_wrapper offset_request(const char *host, const char *port, int time_offset) {
325 /* setup hints to only return results from getaddrinfo that we'd like */ 334 /* setup hints to only return results from getaddrinfo that we'd like */
326 struct addrinfo hints; 335 struct addrinfo hints;
327 memset(&hints, 0, sizeof(struct addrinfo)); 336 memset(&hints, 0, sizeof(struct addrinfo));
@@ -329,17 +338,25 @@ double offset_request(const char *host, const char *port, mp_state_enum *status,
329 hints.ai_protocol = IPPROTO_UDP; 338 hints.ai_protocol = IPPROTO_UDP;
330 hints.ai_socktype = SOCK_DGRAM; 339 hints.ai_socktype = SOCK_DGRAM;
331 340
332 /* fill in ai with the list of hosts resolved by the host name */ 341 bool is_socket;
333 struct addrinfo *addresses = NULL; 342 struct addrinfo *addresses = NULL;
334 int ga_result = getaddrinfo(host, port, &hints, &addresses);
335 if (ga_result != 0) {
336 die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result));
337 }
338
339 /* count the number of returned hosts, and allocate stuff accordingly */
340 size_t num_hosts = 0; 343 size_t num_hosts = 0;
341 for (struct addrinfo *ai_tmp = addresses; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) { 344 if (host[0] == '/') {
342 num_hosts++; 345 num_hosts = 1;
346 is_socket = true;
347 } else {
348 is_socket = false;
349
350 /* fill in ai with the list of hosts resolved by the host name */
351 int ga_result = getaddrinfo(host, port, &hints, &addresses);
352 if (ga_result != 0) {
353 die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result));
354 }
355
356 /* count the number of returned hosts, and allocate stuff accordingly */
357 for (struct addrinfo *ai_tmp = addresses; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) {
358 num_hosts++;
359 }
343 } 360 }
344 361
345 ntp_message *req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts); 362 ntp_message *req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts);
@@ -358,7 +375,8 @@ double offset_request(const char *host, const char *port, mp_state_enum *status,
358 die(STATE_UNKNOWN, "can not allocate socket array"); 375 die(STATE_UNKNOWN, "can not allocate socket array");
359 } 376 }
360 377
361 ntp_server_results *servers = (ntp_server_results *)malloc(sizeof(ntp_server_results) * num_hosts); 378 ntp_server_results *servers =
379 (ntp_server_results *)malloc(sizeof(ntp_server_results) * num_hosts);
362 if (servers == NULL) { 380 if (servers == NULL) {
363 die(STATE_UNKNOWN, "can not allocate server array"); 381 die(STATE_UNKNOWN, "can not allocate server array");
364 } 382 }
@@ -366,25 +384,51 @@ double offset_request(const char *host, const char *port, mp_state_enum *status,
366 DBG(printf("Found %zu peers to check\n", num_hosts)); 384 DBG(printf("Found %zu peers to check\n", num_hosts));
367 385
368 /* setup each socket for writing, and the corresponding struct pollfd */ 386 /* setup each socket for writing, and the corresponding struct pollfd */
369 struct addrinfo *ai_tmp = addresses; 387 if (is_socket) {
370 for (int i = 0; ai_tmp; i++) { 388 socklist[0] = socket(AF_UNIX, SOCK_STREAM, 0);
371 socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP); 389 if (socklist[0] == -1) {
372 if (socklist[i] == -1) { 390 DBG(printf("can't create socket: %s\n", strerror(errno)));
373 perror(NULL); 391 die(STATE_UNKNOWN, "can not create new socket\n");
374 die(STATE_UNKNOWN, "can not create new socket");
375 } 392 }
376 if (connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)) { 393
394 struct sockaddr_un unix_socket = {
395 .sun_family = AF_UNIX,
396 };
397
398 strncpy(unix_socket.sun_path, host, strlen(host));
399
400 if (connect(socklist[0], &unix_socket, sizeof(unix_socket))) {
377 /* don't die here, because it is enough if there is one server 401 /* don't die here, because it is enough if there is one server
378 answering in time. This also would break for dual ipv4/6 stacked 402 answering in time. This also would break for dual ipv4/6 stacked
379 ntp servers when the client only supports on of them. 403 ntp servers when the client only supports on of them.
380 */ 404 */
381 DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno))); 405 DBG(printf("can't create socket connection on peer %i: %s\n", 0, strerror(errno)));
382 } else { 406 } else {
383 ufds[i].fd = socklist[i]; 407 ufds[0].fd = socklist[0];
384 ufds[i].events = POLLIN; 408 ufds[0].events = POLLIN;
385 ufds[i].revents = 0; 409 ufds[0].revents = 0;
410 }
411 } else {
412 struct addrinfo *ai_tmp = addresses;
413 for (int i = 0; ai_tmp; i++) {
414 socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP);
415 if (socklist[i] == -1) {
416 perror(NULL);
417 die(STATE_UNKNOWN, "can not create new socket");
418 }
419 if (connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)) {
420 /* don't die here, because it is enough if there is one server
421 answering in time. This also would break for dual ipv4/6 stacked
422 ntp servers when the client only supports on of them.
423 */
424 DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno)));
425 } else {
426 ufds[i].fd = socklist[i];
427 ufds[i].events = POLLIN;
428 ufds[i].revents = 0;
429 }
430 ai_tmp = ai_tmp->ai_next;
386 } 431 }
387 ai_tmp = ai_tmp->ai_next;
388 } 432 }
389 433
390 /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds 434 /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds
@@ -459,12 +503,18 @@ double offset_request(const char *host, const char *port, mp_state_enum *status,
459 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); 503 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
460 } 504 }
461 505
506 offset_request_wrapper result = {
507 .offset = 0,
508 .offset_result = STATE_UNKNOWN,
509 };
510
462 /* now, pick the best server from the list */ 511 /* now, pick the best server from the list */
463 double avg_offset = 0.; 512 double avg_offset = 0.;
464 int best_index = best_offset_server(servers, num_hosts); 513 int best_index = best_offset_server(servers, num_hosts);
465 if (best_index < 0) { 514 if (best_index < 0) {
466 *status = STATE_UNKNOWN; 515 result.offset_result = STATE_UNKNOWN;
467 } else { 516 } else {
517 result.offset_result = STATE_OK;
468 /* finally, calculate the average offset */ 518 /* finally, calculate the average offset */
469 for (int i = 0; i < servers[best_index].num_responses; i++) { 519 for (int i = 0; i < servers[best_index].num_responses; i++) {
470 avg_offset += servers[best_index].offset[i]; 520 avg_offset += servers[best_index].offset[i];
@@ -485,22 +535,30 @@ double offset_request(const char *host, const char *port, mp_state_enum *status,
485 if (verbose) { 535 if (verbose) {
486 printf("overall average offset: %.10g\n", avg_offset); 536 printf("overall average offset: %.10g\n", avg_offset);
487 } 537 }
488 return avg_offset; 538
539 result.offset = avg_offset;
540 return result;
489} 541}
490 542
491check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { 543static check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
544
545 enum {
546 output_format_index = CHAR_MAX + 1,
547 };
548
492 static struct option longopts[] = {{"version", no_argument, 0, 'V'}, 549 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
493 {"help", no_argument, 0, 'h'}, 550 {"help", no_argument, 0, 'h'},
494 {"verbose", no_argument, 0, 'v'}, 551 {"verbose", no_argument, 0, 'v'},
495 {"use-ipv4", no_argument, 0, '4'}, 552 {"use-ipv4", no_argument, 0, '4'},
496 {"use-ipv6", no_argument, 0, '6'}, 553 {"use-ipv6", no_argument, 0, '6'},
497 {"quiet", no_argument, 0, 'q'}, 554 {"quiet", no_argument, 0, 'q'},
498 {"time-offset", optional_argument, 0, 'o'}, 555 {"time-offset", required_argument, 0, 'o'},
499 {"warning", required_argument, 0, 'w'}, 556 {"warning", required_argument, 0, 'w'},
500 {"critical", required_argument, 0, 'c'}, 557 {"critical", required_argument, 0, 'c'},
501 {"timeout", required_argument, 0, 't'}, 558 {"timeout", required_argument, 0, 't'},
502 {"hostname", required_argument, 0, 'H'}, 559 {"hostname", required_argument, 0, 'H'},
503 {"port", required_argument, 0, 'p'}, 560 {"port", required_argument, 0, 'p'},
561 {"output-format", required_argument, 0, output_format_index},
504 {0, 0, 0, 0}}; 562 {0, 0, 0, 0}};
505 563
506 if (argc < 2) { 564 if (argc < 2) {
@@ -512,9 +570,6 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
512 .config = check_ntp_time_config_init(), 570 .config = check_ntp_time_config_init(),
513 }; 571 };
514 572
515 char *owarn = "60";
516 char *ocrit = "120";
517
518 while (true) { 573 while (true) {
519 int option = 0; 574 int option = 0;
520 int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option); 575 int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option);
@@ -523,6 +578,17 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
523 } 578 }
524 579
525 switch (option_char) { 580 switch (option_char) {
581 case output_format_index: {
582 parsed_output_format parser = mp_parse_output_format(optarg);
583 if (!parser.parsing_success) {
584 printf("Invalid output format: %s\n", optarg);
585 exit(STATE_UNKNOWN);
586 }
587
588 result.config.output_format_is_set = true;
589 result.config.output_format = parser.output_format;
590 break;
591 }
526 case 'h': 592 case 'h':
527 print_help(); 593 print_help();
528 exit(STATE_UNKNOWN); 594 exit(STATE_UNKNOWN);
@@ -537,14 +603,26 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
537 case 'q': 603 case 'q':
538 result.config.quiet = true; 604 result.config.quiet = true;
539 break; 605 break;
540 case 'w': 606 case 'w': {
541 owarn = optarg; 607 mp_range_parsed tmp = mp_parse_range_string(optarg);
542 break; 608 if (tmp.error != MP_PARSING_SUCCES) {
543 case 'c': 609 die(STATE_UNKNOWN, "failed to parse warning threshold");
544 ocrit = optarg; 610 }
545 break; 611
612 result.config.offset_thresholds =
613 mp_thresholds_set_warn(result.config.offset_thresholds, tmp.range);
614 } break;
615 case 'c': {
616 mp_range_parsed tmp = mp_parse_range_string(optarg);
617 if (tmp.error != MP_PARSING_SUCCES) {
618 die(STATE_UNKNOWN, "failed to parse crit threshold");
619 }
620
621 result.config.offset_thresholds =
622 mp_thresholds_set_crit(result.config.offset_thresholds, tmp.range);
623 } break;
546 case 'H': 624 case 'H':
547 if (!is_host(optarg)) { 625 if (!is_host(optarg) && (optarg[0] != '/')) {
548 usage2(_("Invalid hostname/address"), optarg); 626 usage2(_("Invalid hostname/address"), optarg);
549 } 627 }
550 result.config.server_address = strdup(optarg); 628 result.config.server_address = strdup(optarg);
@@ -579,16 +657,9 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
579 usage4(_("Hostname was not supplied")); 657 usage4(_("Hostname was not supplied"));
580 } 658 }
581 659
582 set_thresholds(&result.config.offset_thresholds, owarn, ocrit);
583
584 return result; 660 return result;
585} 661}
586 662
587char *perfd_offset(double offset, thresholds *offset_thresholds) {
588 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, offset_thresholds->critical->end, false, 0, false,
589 0);
590}
591
592int main(int argc, char *argv[]) { 663int main(int argc, char *argv[]) {
593 setlocale(LC_ALL, ""); 664 setlocale(LC_ALL, "");
594 bindtextdomain(PACKAGE, LOCALEDIR); 665 bindtextdomain(PACKAGE, LOCALEDIR);
@@ -605,51 +676,47 @@ int main(int argc, char *argv[]) {
605 676
606 const check_ntp_time_config config = tmp_config.config; 677 const check_ntp_time_config config = tmp_config.config;
607 678
679 if (config.output_format_is_set) {
680 mp_set_format(config.output_format);
681 }
682
608 /* initialize alarm signal handling */ 683 /* initialize alarm signal handling */
609 signal(SIGALRM, socket_timeout_alarm_handler); 684 signal(SIGALRM, socket_timeout_alarm_handler);
610 685
611 /* set socket timeout */ 686 /* set socket timeout */
612 alarm(socket_timeout); 687 alarm(socket_timeout);
613 688
614 mp_state_enum offset_result = STATE_OK; 689 mp_check overall = mp_check_init();
615 mp_state_enum result = STATE_OK;
616 double offset = offset_request(config.server_address, config.port, &offset_result, config.time_offset);
617 if (offset_result == STATE_UNKNOWN) {
618 result = ((!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL);
619 } else {
620 result = get_status(fabs(offset), config.offset_thresholds);
621 }
622 690
623 char *result_line; 691 mp_subcheck sc_offset = mp_subcheck_init();
624 switch (result) { 692 offset_request_wrapper offset_result =
625 case STATE_CRITICAL: 693 offset_request(config.server_address, config.port, config.time_offset);
626 xasprintf(&result_line, _("NTP CRITICAL:"));
627 break;
628 case STATE_WARNING:
629 xasprintf(&result_line, _("NTP WARNING:"));
630 break;
631 case STATE_OK:
632 xasprintf(&result_line, _("NTP OK:"));
633 break;
634 default:
635 xasprintf(&result_line, _("NTP UNKNOWN:"));
636 break;
637 }
638 694
639 char *perfdata_line; 695 if (offset_result.offset_result == STATE_UNKNOWN) {
640 if (offset_result == STATE_UNKNOWN) { 696 sc_offset =
641 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); 697 mp_set_subcheck_state(sc_offset, (!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL);
642 xasprintf(&perfdata_line, ""); 698 xasprintf(&sc_offset.output, "Offset unknown");
643 } else { 699 mp_add_subcheck_to_check(&overall, sc_offset);
644 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset); 700 mp_exit(overall);
645 xasprintf(&perfdata_line, "%s", perfd_offset(offset, config.offset_thresholds));
646 } 701 }
647 printf("%s|%s\n", result_line, perfdata_line); 702
703 xasprintf(&sc_offset.output, "Offset: %.6fs", offset_result.offset);
704
705 mp_perfdata pd_offset = perfdata_init();
706 pd_offset = mp_set_pd_value(pd_offset, fabs(offset_result.offset));
707 pd_offset.label = "offset";
708 pd_offset.uom = "s";
709 pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds);
710
711 sc_offset = mp_set_subcheck_state(sc_offset, mp_get_pd_status(pd_offset));
712
713 mp_add_perfdata_to_subcheck(&sc_offset, pd_offset);
714 mp_add_subcheck_to_check(&overall, sc_offset);
648 715
649 if (config.server_address != NULL) { 716 if (config.server_address != NULL) {
650 free(config.server_address); 717 free(config.server_address);
651 } 718 }
652 exit(result); 719 mp_exit(overall);
653} 720}
654 721
655void print_help(void) { 722void print_help(void) {
@@ -673,10 +740,11 @@ void print_help(void) {
673 printf(" %s\n", _("Offset to result in warning status (seconds)")); 740 printf(" %s\n", _("Offset to result in warning status (seconds)"));
674 printf(" %s\n", "-c, --critical=THRESHOLD"); 741 printf(" %s\n", "-c, --critical=THRESHOLD");
675 printf(" %s\n", _("Offset to result in critical status (seconds)")); 742 printf(" %s\n", _("Offset to result in critical status (seconds)"));
676 printf(" %s\n", "-o, --time_offset=INTEGER"); 743 printf(" %s\n", "-o, --time-offset=INTEGER");
677 printf(" %s\n", _("Expected offset of the ntp server relative to local server (seconds)")); 744 printf(" %s\n", _("Expected offset of the ntp server relative to local server (seconds)"));
678 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 745 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
679 printf(UT_VERBOSE); 746 printf(UT_VERBOSE);
747 printf(UT_OUTPUT_FORMAT);
680 748
681 printf("\n"); 749 printf("\n");
682 printf("%s\n", _("This plugin checks the clock offset between the local host and a")); 750 printf("%s\n", _("This plugin checks the clock offset between the local host and a"));
@@ -701,5 +769,6 @@ void print_help(void) {
701 769
702void print_usage(void) { 770void print_usage(void) {
703 printf("%s\n", _("Usage:")); 771 printf("%s\n", _("Usage:"));
704 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose] [-o <time offset>]\n", progname); 772 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose] [-o <time offset>]\n",
773 progname);
705} 774}
diff --git a/plugins/check_ntp_time.d/config.h b/plugins/check_ntp_time.d/config.h
index 99dabbbd..9bbd82aa 100644
--- a/plugins/check_ntp_time.d/config.h
+++ b/plugins/check_ntp_time.d/config.h
@@ -1,6 +1,7 @@
1#pragma once 1#pragma once
2 2
3#include "../../config.h" 3#include "../../config.h"
4#include "output.h"
4#include "thresholds.h" 5#include "thresholds.h"
5#include <stddef.h> 6#include <stddef.h>
6 7
@@ -11,7 +12,10 @@ typedef struct {
11 bool quiet; 12 bool quiet;
12 int time_offset; 13 int time_offset;
13 14
14 thresholds *offset_thresholds; 15 mp_thresholds offset_thresholds;
16
17 bool output_format_is_set;
18 mp_output_format output_format;
15} check_ntp_time_config; 19} check_ntp_time_config;
16 20
17check_ntp_time_config check_ntp_time_config_init() { 21check_ntp_time_config check_ntp_time_config_init() {
@@ -22,7 +26,18 @@ check_ntp_time_config check_ntp_time_config_init() {
22 .quiet = false, 26 .quiet = false,
23 .time_offset = 0, 27 .time_offset = 0,
24 28
25 .offset_thresholds = NULL, 29 .offset_thresholds = mp_thresholds_init(),
30
31 .output_format_is_set = false,
26 }; 32 };
33
34 mp_range warning = mp_range_init();
35 warning = mp_range_set_end(warning, mp_create_pd_value(60));
36 tmp.offset_thresholds = mp_thresholds_set_warn(tmp.offset_thresholds, warning);
37
38 mp_range critical = mp_range_init();
39 critical = mp_range_set_end(warning, mp_create_pd_value(120));
40 tmp.offset_thresholds = mp_thresholds_set_crit(tmp.offset_thresholds, critical);
41
27 return tmp; 42 return tmp;
28} 43}
diff --git a/plugins/check_nwstat.c b/plugins/check_nwstat.c
deleted file mode 100644
index 176dfbc8..00000000
--- a/plugins/check_nwstat.c
+++ /dev/null
@@ -1,1527 +0,0 @@
1/*****************************************************************************
2 *
3 * Monitoring check_nwstat plugin
4 *
5 * License: GPL
6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7 *
8 * Description:
9 *
10 * This file contains the check_nwstat plugin
11 *
12 * This plugin attempts to contact the MRTGEXT NLM running on a
13 * Novell server to gather the requested system information.
14 *
15 *
16 * This program is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, either version 3 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 *
29 *
30 *****************************************************************************/
31
32const char *progname = "check_nwstat";
33const char *copyright = "2000-2024";
34const char *email = "devel@monitoring-plugins.org";
35
36#include "common.h"
37#include "netutils.h"
38#include "utils.h"
39
40enum checkvar {
41 NONE,
42 LOAD1, /* check 1 minute CPU load */
43 LOAD5, /* check 5 minute CPU load */
44 LOAD15, /* check 15 minute CPU load */
45 CONNS, /* check number of connections */
46 VPF, /* check % free space on volume */
47 VMF, /* check MB free space on volume */
48 VMU, /* check MB used space on volume */
49 VPU, /* check % used space on volume */
50 VMP, /* check MB purgeable space on volume */
51 VKF, /* check KB free space on volume */
52 LTCH, /* check long-term cache hit percentage */
53 CBUFF, /* check total cache buffers */
54 CDBUFF, /* check dirty cache buffers */
55 LRUM, /* check LRU sitting time in minutes */
56 DSDB, /* check to see if DS Database is open */
57 LOGINS, /* check to see if logins are enabled */
58 NRMH, /* check to see NRM Health Status */
59 PUPRB, /* check % of used packet receive buffers */
60 UPRB, /* check used packet receive buffers */
61 SAPENTRIES, /* check SAP entries */
62 OFILES, /* check number of open files */
63 VKP, /* check KB purgeable space on volume */
64 VPP, /* check % purgeable space on volume */
65 VKNP, /* check KB not yet purgeable space on volume */
66 VPNP, /* check % not yet purgeable space on volume */
67 ABENDS, /* check abended thread count */
68 CSPROCS, /* check number of current service processes */
69 TSYNC, /* check timesync status 0=no 1=yes in sync to the network */
70 LRUS, /* check LRU sitting time in seconds */
71 DCB, /* check dirty cache buffers as a percentage of the total */
72 TCB, /* check total cache buffers as a percentage of the original */
73 DSVER, /* check NDS version */
74 UPTIME, /* check server uptime */
75 NLM, /* check NLM loaded */
76 NRMP, /* check NRM Process Values */
77 NRMM, /* check NRM Memory Values */
78 NRMS, /* check NRM Values */
79 NSS1, /* check Statistics from _Admin:Manage_NSS\GeneralStats.xml */
80 NSS2, /* check Statistics from _Admin:Manage_NSS\BufferCache.xml */
81 NSS3, /* check statistics from _Admin:Manage_NSS\NameCache.xml */
82 NSS4, /* check statistics from _Admin:Manage_NSS\FileStats.xml */
83 NSS5, /* check statistics from _Admin:Manage_NSS\ObjectCache.xml */
84 NSS6, /* check statistics from _Admin:Manage_NSS\Thread.xml */
85 NSS7 /* check statistics from _Admin:Manage_NSS\AuthorizationCache.xml */
86};
87
88enum {
89 PORT = 9999
90};
91
92static char *server_address = NULL;
93static char *volume_name = NULL;
94static char *nlm_name = NULL;
95static char *nrmp_name = NULL;
96static char *nrmm_name = NULL;
97static char *nrms_name = NULL;
98static char *nss1_name = NULL;
99static char *nss2_name = NULL;
100static char *nss3_name = NULL;
101static char *nss4_name = NULL;
102static char *nss5_name = NULL;
103static char *nss6_name = NULL;
104static char *nss7_name = NULL;
105static int server_port = PORT;
106static unsigned long warning_value = 0L;
107static unsigned long critical_value = 0L;
108static bool check_warning_value = false;
109static bool check_critical_value = false;
110static bool check_netware_version = false;
111static enum checkvar vars_to_check = NONE;
112static int sap_number = -1;
113
114static int process_arguments(int /*argc*/, char ** /*argv*/);
115static void print_help(void);
116void print_usage(void);
117
118int main(int argc, char **argv) {
119 int result = STATE_UNKNOWN;
120 int sd;
121 char *send_buffer = NULL;
122 char recv_buffer[MAX_INPUT_BUFFER];
123 char *output_message = NULL;
124 char *temp_buffer = NULL;
125 char *netware_version = NULL;
126
127 int time_sync_status = 0;
128 int nrm_health_status = 0;
129 unsigned long total_cache_buffers = 0;
130 unsigned long dirty_cache_buffers = 0;
131 unsigned long open_files = 0;
132 unsigned long abended_threads = 0;
133 unsigned long max_service_processes = 0;
134 unsigned long current_service_processes = 0;
135 unsigned long free_disk_space = 0L;
136 unsigned long nrmp_value = 0L;
137 unsigned long nrmm_value = 0L;
138 unsigned long nrms_value = 0L;
139 unsigned long nss1_value = 0L;
140 unsigned long nss2_value = 0L;
141 unsigned long nss3_value = 0L;
142 unsigned long nss4_value = 0L;
143 unsigned long nss5_value = 0L;
144 unsigned long nss6_value = 0L;
145 unsigned long nss7_value = 0L;
146 unsigned long total_disk_space = 0L;
147 unsigned long used_disk_space = 0L;
148 unsigned long percent_used_disk_space = 0L;
149 unsigned long purgeable_disk_space = 0L;
150 unsigned long non_purgeable_disk_space = 0L;
151 unsigned long percent_free_space = 0;
152 unsigned long percent_purgeable_space = 0;
153 unsigned long percent_non_purgeable_space = 0;
154 unsigned long current_connections = 0L;
155 unsigned long utilization = 0L;
156 unsigned long cache_hits = 0;
157 unsigned long cache_buffers = 0L;
158 unsigned long lru_time = 0L;
159 unsigned long max_packet_receive_buffers = 0;
160 unsigned long used_packet_receive_buffers = 0;
161 unsigned long percent_used_packet_receive_buffers = 0L;
162 unsigned long sap_entries = 0;
163 char uptime[MAX_INPUT_BUFFER];
164
165 setlocale(LC_ALL, "");
166 bindtextdomain(PACKAGE, LOCALEDIR);
167 textdomain(PACKAGE);
168
169 /* Parse extra opts if any */
170 argv = np_extra_opts(&argc, argv, progname);
171
172 if (process_arguments(argc, argv) == ERROR)
173 usage4(_("Could not parse arguments"));
174
175 /* initialize alarm signal handling */
176 signal(SIGALRM, socket_timeout_alarm_handler);
177
178 /* set socket timeout */
179 alarm(socket_timeout);
180
181 /* open connection */
182 my_tcp_connect(server_address, server_port, &sd);
183
184 /* get OS version string */
185 if (check_netware_version) {
186 send_buffer = strdup("S19\r\n");
187 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
188 if (result != STATE_OK)
189 return result;
190 if (!strcmp(recv_buffer, "-1\n"))
191 netware_version = strdup("");
192 else {
193 recv_buffer[strlen(recv_buffer) - 1] = 0;
194 xasprintf(&netware_version, _("NetWare %s: "), recv_buffer);
195 }
196 } else
197 netware_version = strdup("");
198
199 /* check CPU load */
200 if (vars_to_check == LOAD1 || vars_to_check == LOAD5 || vars_to_check == LOAD15) {
201
202 switch (vars_to_check) {
203 case LOAD1:
204 temp_buffer = strdup("1");
205 break;
206 case LOAD5:
207 temp_buffer = strdup("5");
208 break;
209 default:
210 temp_buffer = strdup("15");
211 break;
212 }
213
214 close(sd);
215 my_tcp_connect(server_address, server_port, &sd);
216
217 xasprintf(&send_buffer, "UTIL%s\r\n", temp_buffer);
218 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
219 if (result != STATE_OK)
220 return result;
221 utilization = strtoul(recv_buffer, NULL, 10);
222
223 close(sd);
224 my_tcp_connect(server_address, server_port, &sd);
225
226 send_buffer = strdup("UPTIME\r\n");
227 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
228 if (result != STATE_OK)
229 return result;
230 recv_buffer[strlen(recv_buffer) - 1] = 0;
231 sprintf(uptime, _("Up %s,"), recv_buffer);
232
233 if (check_critical_value && utilization >= critical_value)
234 result = STATE_CRITICAL;
235 else if (check_warning_value && utilization >= warning_value)
236 result = STATE_WARNING;
237
238 xasprintf(&output_message, _("Load %s - %s %s-min load average = %lu%%|load%s=%lu;%lu;%lu;0;100"), state_text(result), uptime,
239 temp_buffer, utilization, temp_buffer, utilization, warning_value, critical_value);
240
241 /* check number of user connections */
242 } else if (vars_to_check == CONNS) {
243
244 close(sd);
245 my_tcp_connect(server_address, server_port, &sd);
246
247 send_buffer = strdup("CONNECT\r\n");
248 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
249 if (result != STATE_OK)
250 return result;
251 current_connections = strtoul(recv_buffer, NULL, 10);
252
253 if (check_critical_value && current_connections >= critical_value)
254 result = STATE_CRITICAL;
255 else if (check_warning_value && current_connections >= warning_value)
256 result = STATE_WARNING;
257
258 xasprintf(&output_message, _("Conns %s - %lu current connections|Conns=%lu;%lu;%lu;;"), state_text(result), current_connections,
259 current_connections, warning_value, critical_value);
260
261 /* check % long term cache hits */
262 } else if (vars_to_check == LTCH) {
263
264 close(sd);
265 my_tcp_connect(server_address, server_port, &sd);
266
267 send_buffer = strdup("S1\r\n");
268 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
269 if (result != STATE_OK)
270 return result;
271 cache_hits = atoi(recv_buffer);
272
273 if (check_critical_value && cache_hits <= critical_value)
274 result = STATE_CRITICAL;
275 else if (check_warning_value && cache_hits <= warning_value)
276 result = STATE_WARNING;
277
278 xasprintf(&output_message, _("%s: Long term cache hits = %lu%%"), state_text(result), cache_hits);
279
280 /* check cache buffers */
281 } else if (vars_to_check == CBUFF) {
282
283 close(sd);
284 my_tcp_connect(server_address, server_port, &sd);
285
286 send_buffer = strdup("S2\r\n");
287 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
288 if (result != STATE_OK)
289 return result;
290 cache_buffers = strtoul(recv_buffer, NULL, 10);
291
292 if (check_critical_value && cache_buffers <= critical_value)
293 result = STATE_CRITICAL;
294 else if (check_warning_value && cache_buffers <= warning_value)
295 result = STATE_WARNING;
296
297 xasprintf(&output_message, _("%s: Total cache buffers = %lu|Cachebuffers=%lu;%lu;%lu;;"), state_text(result), cache_buffers,
298 cache_buffers, warning_value, critical_value);
299
300 /* check dirty cache buffers */
301 } else if (vars_to_check == CDBUFF) {
302
303 close(sd);
304 my_tcp_connect(server_address, server_port, &sd);
305
306 send_buffer = strdup("S3\r\n");
307 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
308 if (result != STATE_OK)
309 return result;
310 cache_buffers = strtoul(recv_buffer, NULL, 10);
311
312 if (check_critical_value && cache_buffers >= critical_value)
313 result = STATE_CRITICAL;
314 else if (check_warning_value && cache_buffers >= warning_value)
315 result = STATE_WARNING;
316
317 xasprintf(&output_message, _("%s: Dirty cache buffers = %lu|Dirty-Cache-Buffers=%lu;%lu;%lu;;"), state_text(result), cache_buffers,
318 cache_buffers, warning_value, critical_value);
319
320 /* check LRU sitting time in minutes */
321 } else if (vars_to_check == LRUM) {
322
323 close(sd);
324 my_tcp_connect(server_address, server_port, &sd);
325
326 send_buffer = strdup("S5\r\n");
327 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
328 if (result != STATE_OK)
329 return result;
330 lru_time = strtoul(recv_buffer, NULL, 10);
331
332 if (check_critical_value && lru_time <= critical_value)
333 result = STATE_CRITICAL;
334 else if (check_warning_value && lru_time <= warning_value)
335 result = STATE_WARNING;
336
337 xasprintf(&output_message, _("%s: LRU sitting time = %lu minutes"), state_text(result), lru_time);
338
339 /* check KB free space on volume */
340 } else if (vars_to_check == VKF) {
341
342 close(sd);
343 my_tcp_connect(server_address, server_port, &sd);
344
345 xasprintf(&send_buffer, "VKF%s\r\n", volume_name);
346 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
347 if (result != STATE_OK)
348 return result;
349
350 if (!strcmp(recv_buffer, "-1\n")) {
351 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
352 result = STATE_CRITICAL;
353 } else {
354 free_disk_space = strtoul(recv_buffer, NULL, 10);
355 if (check_critical_value && free_disk_space <= critical_value)
356 result = STATE_CRITICAL;
357 else if (check_warning_value && free_disk_space <= warning_value)
358 result = STATE_WARNING;
359 xasprintf(&output_message, _("%s%lu KB free on volume %s|KBFree%s=%lu;%lu;%lu;;"), (result == STATE_OK) ? "" : _("Only "),
360 free_disk_space, volume_name, volume_name, free_disk_space, warning_value, critical_value);
361 }
362
363 /* check MB free space on volume */
364 } else if (vars_to_check == VMF) {
365
366 xasprintf(&send_buffer, "VMF%s\r\n", volume_name);
367 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
368 if (result != STATE_OK)
369 return result;
370
371 if (!strcmp(recv_buffer, "-1\n")) {
372 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
373 result = STATE_CRITICAL;
374 } else {
375 free_disk_space = strtoul(recv_buffer, NULL, 10);
376 if (check_critical_value && free_disk_space <= critical_value)
377 result = STATE_CRITICAL;
378 else if (check_warning_value && free_disk_space <= warning_value)
379 result = STATE_WARNING;
380 xasprintf(&output_message, _("%s%lu MB free on volume %s|MBFree%s=%lu;%lu;%lu;;"), (result == STATE_OK) ? "" : _("Only "),
381 free_disk_space, volume_name, volume_name, free_disk_space, warning_value, critical_value);
382 }
383 /* check MB used space on volume */
384 } else if (vars_to_check == VMU) {
385
386 xasprintf(&send_buffer, "VMU%s\r\n", volume_name);
387 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
388 if (result != STATE_OK)
389 return result;
390
391 if (!strcmp(recv_buffer, "-1\n")) {
392 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
393 result = STATE_CRITICAL;
394 } else {
395 free_disk_space = strtoul(recv_buffer, NULL, 10);
396 if (check_critical_value && free_disk_space <= critical_value)
397 result = STATE_CRITICAL;
398 else if (check_warning_value && free_disk_space <= warning_value)
399 result = STATE_WARNING;
400 xasprintf(&output_message, _("%s%lu MB used on volume %s|MBUsed%s=%lu;%lu;%lu;;"), (result == STATE_OK) ? "" : _("Only "),
401 free_disk_space, volume_name, volume_name, free_disk_space, warning_value, critical_value);
402 }
403 /* check % used space on volume */
404 } else if (vars_to_check == VPU) {
405 close(sd);
406 my_tcp_connect(server_address, server_port, &sd);
407
408 asprintf(&send_buffer, "VMU%s\r\n", volume_name);
409 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
410
411 if (result != STATE_OK)
412 return result;
413
414 if (!strcmp(recv_buffer, "-1\n")) {
415 asprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
416 result = STATE_CRITICAL;
417
418 } else {
419 used_disk_space = strtoul(recv_buffer, NULL, 10);
420 close(sd);
421 my_tcp_connect(server_address, server_port, &sd);
422 /* get total volume in MB */
423 asprintf(&send_buffer, "VMS%s\r\n", volume_name);
424 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
425 if (result != STATE_OK)
426 return result;
427 total_disk_space = strtoul(recv_buffer, NULL, 10);
428 /* calculate percent used on volume */
429 percent_used_disk_space = (unsigned long)(((double)used_disk_space / (double)total_disk_space) * 100.0);
430
431 if (check_critical_value && percent_used_disk_space >= critical_value)
432 result = STATE_CRITICAL;
433 else if (check_warning_value && percent_used_disk_space >= warning_value)
434 result = STATE_WARNING;
435
436 asprintf(&output_message, _("%lu MB (%lu%%) used on volume %s - total %lu MB|Used space in percent on %s=%lu;%lu;%lu;0;100"),
437 used_disk_space, percent_used_disk_space, volume_name, total_disk_space, volume_name, percent_used_disk_space,
438 warning_value, critical_value);
439 }
440
441 /* check % free space on volume */
442 } else if (vars_to_check == VPF) {
443
444 close(sd);
445 my_tcp_connect(server_address, server_port, &sd);
446
447 xasprintf(&send_buffer, "VKF%s\r\n", volume_name);
448 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
449 if (result != STATE_OK)
450 return result;
451
452 if (!strcmp(recv_buffer, "-1\n")) {
453
454 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
455 result = STATE_CRITICAL;
456
457 } else {
458
459 free_disk_space = strtoul(recv_buffer, NULL, 10);
460
461 close(sd);
462 my_tcp_connect(server_address, server_port, &sd);
463
464 xasprintf(&send_buffer, "VKS%s\r\n", volume_name);
465 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
466 if (result != STATE_OK)
467 return result;
468 total_disk_space = strtoul(recv_buffer, NULL, 10);
469
470 percent_free_space = (unsigned long)(((double)free_disk_space / (double)total_disk_space) * 100.0);
471
472 if (check_critical_value && percent_free_space <= critical_value)
473 result = STATE_CRITICAL;
474 else if (check_warning_value && percent_free_space <= warning_value)
475 result = STATE_WARNING;
476 free_disk_space /= 1024;
477 total_disk_space /= 1024;
478 xasprintf(&output_message, _("%lu MB (%lu%%) free on volume %s - total %lu MB|FreeMB%s=%lu;%lu;%lu;0;100"), free_disk_space,
479 percent_free_space, volume_name, total_disk_space, volume_name, percent_free_space, warning_value, critical_value);
480 }
481
482 /* check to see if DS Database is open or closed */
483 } else if (vars_to_check == DSDB) {
484
485 close(sd);
486 my_tcp_connect(server_address, server_port, &sd);
487
488 send_buffer = strdup("S11\r\n");
489 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
490 if (result != STATE_OK)
491 return result;
492 if (atoi(recv_buffer) == 1)
493 result = STATE_OK;
494 else
495 result = STATE_WARNING;
496
497 close(sd);
498 my_tcp_connect(server_address, server_port, &sd);
499
500 send_buffer = strdup("S13\r\n");
501 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
502 temp_buffer = strtok(recv_buffer, "\r\n");
503
504 xasprintf(&output_message, _("Directory Services Database is %s (DS version %s)"), (result == STATE_OK) ? "open" : "closed",
505 temp_buffer);
506
507 /* check to see if logins are enabled */
508 } else if (vars_to_check == LOGINS) {
509
510 close(sd);
511 my_tcp_connect(server_address, server_port, &sd);
512
513 send_buffer = strdup("S12\r\n");
514 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
515 if (result != STATE_OK)
516 return result;
517 if (atoi(recv_buffer) == 1)
518 result = STATE_OK;
519 else
520 result = STATE_WARNING;
521
522 xasprintf(&output_message, _("Logins are %s"), (result == STATE_OK) ? _("enabled") : _("disabled"));
523
524 /* check NRM Health Status Summary*/
525 } else if (vars_to_check == NRMH) {
526
527 xasprintf(&send_buffer, "NRMH\r\n");
528 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
529 if (result != STATE_OK)
530 return result;
531
532 nrm_health_status = atoi(recv_buffer);
533
534 if (nrm_health_status == 2) {
535 result = STATE_OK;
536 xasprintf(&output_message, _("CRITICAL - NRM Status is bad!"));
537 } else {
538 if (nrm_health_status == 1) {
539 result = STATE_WARNING;
540 xasprintf(&output_message, _("Warning - NRM Status is suspect!"));
541 }
542
543 xasprintf(&output_message, _("OK - NRM Status is good!"));
544 }
545
546 /* check packet receive buffers */
547 } else if (vars_to_check == UPRB || vars_to_check == PUPRB) {
548
549 close(sd);
550 my_tcp_connect(server_address, server_port, &sd);
551
552 xasprintf(&send_buffer, "S15\r\n");
553 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
554 if (result != STATE_OK)
555 return result;
556
557 used_packet_receive_buffers = atoi(recv_buffer);
558
559 close(sd);
560 my_tcp_connect(server_address, server_port, &sd);
561
562 xasprintf(&send_buffer, "S16\r\n");
563 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
564 if (result != STATE_OK)
565 return result;
566
567 max_packet_receive_buffers = atoi(recv_buffer);
568
569 percent_used_packet_receive_buffers =
570 (unsigned long)(((double)used_packet_receive_buffers / (double)max_packet_receive_buffers) * 100.0);
571
572 if (vars_to_check == UPRB) {
573 if (check_critical_value && used_packet_receive_buffers >= critical_value)
574 result = STATE_CRITICAL;
575 else if (check_warning_value && used_packet_receive_buffers >= warning_value)
576 result = STATE_WARNING;
577 } else {
578 if (check_critical_value && percent_used_packet_receive_buffers >= critical_value)
579 result = STATE_CRITICAL;
580 else if (check_warning_value && percent_used_packet_receive_buffers >= warning_value)
581 result = STATE_WARNING;
582 }
583
584 xasprintf(&output_message, _("%lu of %lu (%lu%%) packet receive buffers used"), used_packet_receive_buffers,
585 max_packet_receive_buffers, percent_used_packet_receive_buffers);
586
587 /* check SAP table entries */
588 } else if (vars_to_check == SAPENTRIES) {
589
590 close(sd);
591 my_tcp_connect(server_address, server_port, &sd);
592
593 if (sap_number == -1)
594 xasprintf(&send_buffer, "S9\r\n");
595 else
596 xasprintf(&send_buffer, "S9.%d\r\n", sap_number);
597 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
598 if (result != STATE_OK)
599 return result;
600
601 sap_entries = atoi(recv_buffer);
602
603 if (check_critical_value && sap_entries >= critical_value)
604 result = STATE_CRITICAL;
605 else if (check_warning_value && sap_entries >= warning_value)
606 result = STATE_WARNING;
607
608 if (sap_number == -1)
609 xasprintf(&output_message, _("%lu entries in SAP table"), sap_entries);
610 else
611 xasprintf(&output_message, _("%lu entries in SAP table for SAP type %d"), sap_entries, sap_number);
612
613 /* check KB purgeable space on volume */
614 } else if (vars_to_check == VKP) {
615
616 close(sd);
617 my_tcp_connect(server_address, server_port, &sd);
618
619 xasprintf(&send_buffer, "VKP%s\r\n", volume_name);
620 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
621 if (result != STATE_OK)
622 return result;
623
624 if (!strcmp(recv_buffer, "-1\n")) {
625 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
626 result = STATE_CRITICAL;
627 } else {
628 purgeable_disk_space = strtoul(recv_buffer, NULL, 10);
629 if (check_critical_value && purgeable_disk_space >= critical_value)
630 result = STATE_CRITICAL;
631 else if (check_warning_value && purgeable_disk_space >= warning_value)
632 result = STATE_WARNING;
633 xasprintf(&output_message, _("%s%lu KB purgeable on volume %s|Purge%s=%lu;%lu;%lu;;"), (result == STATE_OK) ? "" : _("Only "),
634 purgeable_disk_space, volume_name, volume_name, purgeable_disk_space, warning_value, critical_value);
635 }
636 /* check MB purgeable space on volume */
637 } else if (vars_to_check == VMP) {
638
639 xasprintf(&send_buffer, "VMP%s\r\n", volume_name);
640 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
641 if (result != STATE_OK)
642 return result;
643
644 if (!strcmp(recv_buffer, "-1\n")) {
645 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
646 result = STATE_CRITICAL;
647 } else {
648 purgeable_disk_space = strtoul(recv_buffer, NULL, 10);
649 if (check_critical_value && purgeable_disk_space >= critical_value)
650 result = STATE_CRITICAL;
651 else if (check_warning_value && purgeable_disk_space >= warning_value)
652 result = STATE_WARNING;
653 xasprintf(&output_message, _("%s%lu MB purgeable on volume %s|Purge%s=%lu;%lu;%lu;;"), (result == STATE_OK) ? "" : _("Only "),
654 purgeable_disk_space, volume_name, volume_name, purgeable_disk_space, warning_value, critical_value);
655 }
656
657 /* check % purgeable space on volume */
658 } else if (vars_to_check == VPP) {
659
660 close(sd);
661 my_tcp_connect(server_address, server_port, &sd);
662
663 xasprintf(&send_buffer, "VKP%s\r\n", volume_name);
664 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
665 if (result != STATE_OK)
666 return result;
667
668 if (!strcmp(recv_buffer, "-1\n")) {
669
670 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
671 result = STATE_CRITICAL;
672
673 } else {
674
675 purgeable_disk_space = strtoul(recv_buffer, NULL, 10);
676
677 close(sd);
678 my_tcp_connect(server_address, server_port, &sd);
679
680 xasprintf(&send_buffer, "VKS%s\r\n", volume_name);
681 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
682 if (result != STATE_OK)
683 return result;
684 total_disk_space = strtoul(recv_buffer, NULL, 10);
685
686 percent_purgeable_space = (unsigned long)(((double)purgeable_disk_space / (double)total_disk_space) * 100.0);
687
688 if (check_critical_value && percent_purgeable_space >= critical_value)
689 result = STATE_CRITICAL;
690 else if (check_warning_value && percent_purgeable_space >= warning_value)
691 result = STATE_WARNING;
692 purgeable_disk_space /= 1024;
693 xasprintf(&output_message, _("%lu MB (%lu%%) purgeable on volume %s|Purgeable%s=%lu;%lu;%lu;0;100"), purgeable_disk_space,
694 percent_purgeable_space, volume_name, volume_name, percent_purgeable_space, warning_value, critical_value);
695 }
696
697 /* check KB not yet purgeable space on volume */
698 } else if (vars_to_check == VKNP) {
699
700 close(sd);
701 my_tcp_connect(server_address, server_port, &sd);
702
703 xasprintf(&send_buffer, "VKNP%s\r\n", volume_name);
704 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
705 if (result != STATE_OK)
706 return result;
707
708 if (!strcmp(recv_buffer, "-1\n")) {
709 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
710 result = STATE_CRITICAL;
711 } else {
712 non_purgeable_disk_space = strtoul(recv_buffer, NULL, 10);
713 if (check_critical_value && non_purgeable_disk_space >= critical_value)
714 result = STATE_CRITICAL;
715 else if (check_warning_value && non_purgeable_disk_space >= warning_value)
716 result = STATE_WARNING;
717 xasprintf(&output_message, _("%s%lu KB not yet purgeable on volume %s"), (result == STATE_OK) ? "" : _("Only "),
718 non_purgeable_disk_space, volume_name);
719 }
720
721 /* check % not yet purgeable space on volume */
722 } else if (vars_to_check == VPNP) {
723
724 close(sd);
725 my_tcp_connect(server_address, server_port, &sd);
726
727 xasprintf(&send_buffer, "VKNP%s\r\n", volume_name);
728 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
729 if (result != STATE_OK)
730 return result;
731
732 if (!strcmp(recv_buffer, "-1\n")) {
733
734 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
735 result = STATE_CRITICAL;
736
737 } else {
738
739 non_purgeable_disk_space = strtoul(recv_buffer, NULL, 10);
740
741 close(sd);
742 my_tcp_connect(server_address, server_port, &sd);
743
744 xasprintf(&send_buffer, "VKS%s\r\n", volume_name);
745 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
746 if (result != STATE_OK)
747 return result;
748 total_disk_space = strtoul(recv_buffer, NULL, 10);
749
750 percent_non_purgeable_space = (unsigned long)(((double)non_purgeable_disk_space / (double)total_disk_space) * 100.0);
751
752 if (check_critical_value && percent_non_purgeable_space >= critical_value)
753 result = STATE_CRITICAL;
754 else if (check_warning_value && percent_non_purgeable_space >= warning_value)
755 result = STATE_WARNING;
756 purgeable_disk_space /= 1024;
757 xasprintf(&output_message, _("%lu MB (%lu%%) not yet purgeable on volume %s"), non_purgeable_disk_space,
758 percent_non_purgeable_space, volume_name);
759 }
760
761 /* check # of open files */
762 } else if (vars_to_check == OFILES) {
763
764 close(sd);
765 my_tcp_connect(server_address, server_port, &sd);
766
767 xasprintf(&send_buffer, "S18\r\n");
768 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
769 if (result != STATE_OK)
770 return result;
771
772 open_files = atoi(recv_buffer);
773
774 if (check_critical_value && open_files >= critical_value)
775 result = STATE_CRITICAL;
776 else if (check_warning_value && open_files >= warning_value)
777 result = STATE_WARNING;
778
779 xasprintf(&output_message, _("%lu open files|Openfiles=%lu;%lu;%lu;0,0"), open_files, open_files, warning_value, critical_value);
780
781 /* check # of abended threads (Netware > 5.x only) */
782 } else if (vars_to_check == ABENDS) {
783
784 close(sd);
785 my_tcp_connect(server_address, server_port, &sd);
786
787 xasprintf(&send_buffer, "S17\r\n");
788 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
789 if (result != STATE_OK)
790 return result;
791
792 abended_threads = atoi(recv_buffer);
793
794 if (check_critical_value && abended_threads >= critical_value)
795 result = STATE_CRITICAL;
796 else if (check_warning_value && abended_threads >= warning_value)
797 result = STATE_WARNING;
798
799 xasprintf(&output_message, _("%lu abended threads|Abends=%lu;%lu;%lu;;"), abended_threads, abended_threads, warning_value,
800 critical_value);
801
802 /* check # of current service processes (Netware 5.x only) */
803 } else if (vars_to_check == CSPROCS) {
804
805 close(sd);
806 my_tcp_connect(server_address, server_port, &sd);
807
808 xasprintf(&send_buffer, "S20\r\n");
809 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
810 if (result != STATE_OK)
811 return result;
812
813 max_service_processes = atoi(recv_buffer);
814
815 close(sd);
816 my_tcp_connect(server_address, server_port, &sd);
817
818 xasprintf(&send_buffer, "S21\r\n");
819 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
820 if (result != STATE_OK)
821 return result;
822
823 current_service_processes = atoi(recv_buffer);
824
825 if (check_critical_value && current_service_processes >= critical_value)
826 result = STATE_CRITICAL;
827 else if (check_warning_value && current_service_processes >= warning_value)
828 result = STATE_WARNING;
829
830 xasprintf(&output_message, _("%lu current service processes (%lu max)|Processes=%lu;%lu;%lu;0;%lu"), current_service_processes,
831 max_service_processes, current_service_processes, warning_value, critical_value, max_service_processes);
832
833 /* check # Timesync Status */
834 } else if (vars_to_check == TSYNC) {
835
836 close(sd);
837 my_tcp_connect(server_address, server_port, &sd);
838
839 xasprintf(&send_buffer, "S22\r\n");
840 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
841 if (result != STATE_OK)
842 return result;
843
844 time_sync_status = atoi(recv_buffer);
845
846 if (time_sync_status == 0) {
847 result = STATE_CRITICAL;
848 xasprintf(&output_message, _("CRITICAL - Time not in sync with network!"));
849 } else {
850 xasprintf(&output_message, _("OK - Time in sync with network!"));
851 }
852
853 /* check LRU sitting time in secondss */
854 } else if (vars_to_check == LRUS) {
855
856 close(sd);
857 my_tcp_connect(server_address, server_port, &sd);
858
859 send_buffer = strdup("S4\r\n");
860 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
861 if (result != STATE_OK)
862 return result;
863 lru_time = strtoul(recv_buffer, NULL, 10);
864
865 if (check_critical_value && lru_time <= critical_value)
866 result = STATE_CRITICAL;
867 else if (check_warning_value && lru_time <= warning_value)
868 result = STATE_WARNING;
869 xasprintf(&output_message, _("LRU sitting time = %lu seconds"), lru_time);
870
871 /* check % dirty cacheobuffers as a percentage of the total*/
872 } else if (vars_to_check == DCB) {
873
874 close(sd);
875 my_tcp_connect(server_address, server_port, &sd);
876
877 send_buffer = strdup("S6\r\n");
878 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
879 if (result != STATE_OK)
880 return result;
881 dirty_cache_buffers = atoi(recv_buffer);
882
883 if (check_critical_value && dirty_cache_buffers <= critical_value)
884 result = STATE_CRITICAL;
885 else if (check_warning_value && dirty_cache_buffers <= warning_value)
886 result = STATE_WARNING;
887 xasprintf(&output_message, _("Dirty cache buffers = %lu%% of the total|DCB=%lu;%lu;%lu;0;100"), dirty_cache_buffers,
888 dirty_cache_buffers, warning_value, critical_value);
889
890 /* check % total cache buffers as a percentage of the original*/
891 } else if (vars_to_check == TCB) {
892
893 close(sd);
894 my_tcp_connect(server_address, server_port, &sd);
895
896 send_buffer = strdup("S7\r\n");
897 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
898 if (result != STATE_OK)
899 return result;
900 total_cache_buffers = atoi(recv_buffer);
901
902 if (check_critical_value && total_cache_buffers <= critical_value)
903 result = STATE_CRITICAL;
904 else if (check_warning_value && total_cache_buffers <= warning_value)
905 result = STATE_WARNING;
906 xasprintf(&output_message, _("Total cache buffers = %lu%% of the original|TCB=%lu;%lu;%lu;0;100"), total_cache_buffers,
907 total_cache_buffers, warning_value, critical_value);
908
909 } else if (vars_to_check == DSVER) {
910
911 close(sd);
912 my_tcp_connect(server_address, server_port, &sd);
913
914 xasprintf(&send_buffer, "S13\r\n");
915 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
916 if (result != STATE_OK)
917 return result;
918
919 recv_buffer[strlen(recv_buffer) - 1] = 0;
920
921 xasprintf(&output_message, _("NDS Version %s"), recv_buffer);
922
923 } else if (vars_to_check == UPTIME) {
924
925 close(sd);
926 my_tcp_connect(server_address, server_port, &sd);
927
928 xasprintf(&send_buffer, "UPTIME\r\n");
929 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
930 if (result != STATE_OK)
931 return result;
932
933 recv_buffer[sizeof(recv_buffer) - 1] = 0;
934 recv_buffer[strlen(recv_buffer) - 1] = 0;
935
936 xasprintf(&output_message, _("Up %s"), recv_buffer);
937
938 } else if (vars_to_check == NLM) {
939
940 close(sd);
941 my_tcp_connect(server_address, server_port, &sd);
942
943 xasprintf(&send_buffer, "S24:%s\r\n", nlm_name);
944 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
945 if (result != STATE_OK)
946 return result;
947
948 recv_buffer[strlen(recv_buffer) - 1] = 0;
949 if (strcmp(recv_buffer, "-1")) {
950 xasprintf(&output_message, _("Module %s version %s is loaded"), nlm_name, recv_buffer);
951 } else {
952 result = STATE_CRITICAL;
953 xasprintf(&output_message, _("Module %s is not loaded"), nlm_name);
954 }
955 } else if (vars_to_check == NRMP) {
956
957 xasprintf(&send_buffer, "NRMP:%s\r\n", nrmp_name);
958 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
959 if (result != STATE_OK)
960 return result;
961
962 if (!strcmp(recv_buffer, "-1\n")) {
963 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nrmp_name);
964 result = STATE_CRITICAL;
965 } else {
966 nrmp_value = strtoul(recv_buffer, NULL, 10);
967 if (check_critical_value && nrmp_value <= critical_value)
968 result = STATE_CRITICAL;
969 else if (check_warning_value && nrmp_value <= warning_value)
970 result = STATE_WARNING;
971 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nrmp_name, nrmp_value, nrmp_name, nrmp_value, warning_value,
972 critical_value);
973 }
974
975 } else if (vars_to_check == NRMM) {
976
977 xasprintf(&send_buffer, "NRMM:%s\r\n", nrmm_name);
978 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
979 if (result != STATE_OK)
980 return result;
981
982 if (!strcmp(recv_buffer, "-1\n")) {
983 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nrmm_name);
984 result = STATE_CRITICAL;
985 } else {
986 nrmm_value = strtoul(recv_buffer, NULL, 10);
987 if (check_critical_value && nrmm_value <= critical_value)
988 result = STATE_CRITICAL;
989 else if (check_warning_value && nrmm_value <= warning_value)
990 result = STATE_WARNING;
991 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nrmm_name, nrmm_value, nrmm_name, nrmm_value, warning_value,
992 critical_value);
993 }
994
995 } else if (vars_to_check == NRMS) {
996
997 xasprintf(&send_buffer, "NRMS:%s\r\n", nrms_name);
998 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
999 if (result != STATE_OK)
1000 return result;
1001
1002 if (!strcmp(recv_buffer, "-1\n")) {
1003 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nrms_name);
1004 result = STATE_CRITICAL;
1005 } else {
1006 nrms_value = strtoul(recv_buffer, NULL, 10);
1007 if (check_critical_value && nrms_value >= critical_value)
1008 result = STATE_CRITICAL;
1009 else if (check_warning_value && nrms_value >= warning_value)
1010 result = STATE_WARNING;
1011 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nrms_name, nrms_value, nrms_name, nrms_value, warning_value,
1012 critical_value);
1013 }
1014
1015 } else if (vars_to_check == NSS1) {
1016
1017 xasprintf(&send_buffer, "NSS1:%s\r\n", nss1_name);
1018 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
1019 if (result != STATE_OK)
1020 return result;
1021
1022 if (!strcmp(recv_buffer, "-1\n")) {
1023 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nss1_name);
1024 result = STATE_CRITICAL;
1025 } else {
1026 nss1_value = strtoul(recv_buffer, NULL, 10);
1027 if (check_critical_value && nss1_value >= critical_value)
1028 result = STATE_CRITICAL;
1029 else if (check_warning_value && nss1_value >= warning_value)
1030 result = STATE_WARNING;
1031 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nss1_name, nss1_value, nss1_name, nss1_value, warning_value,
1032 critical_value);
1033 }
1034
1035 } else if (vars_to_check == NSS2) {
1036
1037 xasprintf(&send_buffer, "NSS2:%s\r\n", nss2_name);
1038 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
1039 if (result != STATE_OK)
1040 return result;
1041
1042 if (!strcmp(recv_buffer, "-1\n")) {
1043 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nss2_name);
1044 result = STATE_CRITICAL;
1045 } else {
1046 nss2_value = strtoul(recv_buffer, NULL, 10);
1047 if (check_critical_value && nss2_value >= critical_value)
1048 result = STATE_CRITICAL;
1049 else if (check_warning_value && nss2_value >= warning_value)
1050 result = STATE_WARNING;
1051 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nss2_name, nss2_value, nss2_name, nss2_value, warning_value,
1052 critical_value);
1053 }
1054
1055 } else if (vars_to_check == NSS3) {
1056
1057 xasprintf(&send_buffer, "NSS3:%s\r\n", nss3_name);
1058 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
1059 if (result != STATE_OK)
1060 return result;
1061
1062 if (!strcmp(recv_buffer, "-1\n")) {
1063 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nss3_name);
1064 result = STATE_CRITICAL;
1065 } else {
1066 nss3_value = strtoul(recv_buffer, NULL, 10);
1067 if (check_critical_value && nss3_value >= critical_value)
1068 result = STATE_CRITICAL;
1069 else if (check_warning_value && nss3_value >= warning_value)
1070 result = STATE_WARNING;
1071 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nss3_name, nss3_value, nss3_name, nss3_value, warning_value,
1072 critical_value);
1073 }
1074
1075 } else if (vars_to_check == NSS4) {
1076
1077 xasprintf(&send_buffer, "NSS4:%s\r\n", nss4_name);
1078 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
1079 if (result != STATE_OK)
1080 return result;
1081
1082 if (!strcmp(recv_buffer, "-1\n")) {
1083 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nss4_name);
1084 result = STATE_CRITICAL;
1085 } else {
1086 nss4_value = strtoul(recv_buffer, NULL, 10);
1087 if (check_critical_value && nss4_value >= critical_value)
1088 result = STATE_CRITICAL;
1089 else if (check_warning_value && nss4_value >= warning_value)
1090 result = STATE_WARNING;
1091 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nss4_name, nss4_value, nss4_name, nss4_value, warning_value,
1092 critical_value);
1093 }
1094
1095 } else if (vars_to_check == NSS5) {
1096
1097 xasprintf(&send_buffer, "NSS5:%s\r\n", nss5_name);
1098 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
1099 if (result != STATE_OK)
1100 return result;
1101
1102 if (!strcmp(recv_buffer, "-1\n")) {
1103 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nss5_name);
1104 result = STATE_CRITICAL;
1105 } else {
1106 nss5_value = strtoul(recv_buffer, NULL, 10);
1107 if (check_critical_value && nss5_value >= critical_value)
1108 result = STATE_CRITICAL;
1109 else if (check_warning_value && nss5_value >= warning_value)
1110 result = STATE_WARNING;
1111 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nss5_name, nss5_value, nss5_name, nss5_value, warning_value,
1112 critical_value);
1113 }
1114
1115 } else if (vars_to_check == NSS6) {
1116
1117 xasprintf(&send_buffer, "NSS6:%s\r\n", nss6_name);
1118 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
1119 if (result != STATE_OK)
1120 return result;
1121
1122 if (!strcmp(recv_buffer, "-1\n")) {
1123 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nss6_name);
1124 result = STATE_CRITICAL;
1125 } else {
1126 nss6_value = strtoul(recv_buffer, NULL, 10);
1127 if (check_critical_value && nss6_value >= critical_value)
1128 result = STATE_CRITICAL;
1129 else if (check_warning_value && nss6_value >= warning_value)
1130 result = STATE_WARNING;
1131 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nss6_name, nss6_value, nss6_name, nss6_value, warning_value,
1132 critical_value);
1133 }
1134
1135 } else if (vars_to_check == NSS7) {
1136
1137 xasprintf(&send_buffer, "NSS7:%s\r\n", nss7_name);
1138 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
1139 if (result != STATE_OK)
1140 return result;
1141
1142 if (!strcmp(recv_buffer, "-1\n")) {
1143 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nss7_name);
1144 result = STATE_CRITICAL;
1145 } else {
1146 nss7_value = strtoul(recv_buffer, NULL, 10);
1147 if (check_critical_value && nss7_value >= critical_value)
1148 result = STATE_CRITICAL;
1149 else if (check_warning_value && nss7_value >= warning_value)
1150 result = STATE_WARNING;
1151 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nss7_name, nss7_value, nss7_name, nss7_value, warning_value,
1152 critical_value);
1153 }
1154
1155 } else {
1156
1157 output_message = strdup(_("Nothing to check!\n"));
1158 result = STATE_UNKNOWN;
1159 }
1160
1161 close(sd);
1162
1163 /* reset timeout */
1164 alarm(0);
1165
1166 printf("%s%s\n", netware_version, output_message);
1167
1168 return result;
1169}
1170
1171/* process command-line arguments */
1172int process_arguments(int argc, char **argv) {
1173 int c;
1174
1175 int option = 0;
1176 static struct option longopts[] = {{"port", required_argument, 0, 'p'}, {"timeout", required_argument, 0, 't'},
1177 {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'},
1178 {"variable", required_argument, 0, 'v'}, {"hostname", required_argument, 0, 'H'},
1179 {"osversion", no_argument, 0, 'o'}, {"version", no_argument, 0, 'V'},
1180 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
1181
1182 /* no options were supplied */
1183 if (argc < 2)
1184 return ERROR;
1185
1186 /* backwards compatibility */
1187 if (!is_option(argv[1])) {
1188 server_address = argv[1];
1189 argv[1] = argv[0];
1190 argv = &argv[1];
1191 argc--;
1192 }
1193
1194 for (c = 1; c < argc; c++) {
1195 if (strcmp("-to", argv[c]) == 0)
1196 strcpy(argv[c], "-t");
1197 else if (strcmp("-wv", argv[c]) == 0)
1198 strcpy(argv[c], "-w");
1199 else if (strcmp("-cv", argv[c]) == 0)
1200 strcpy(argv[c], "-c");
1201 }
1202
1203 while (1) {
1204 c = getopt_long(argc, argv, "+hoVH:t:c:w:p:v:", longopts, &option);
1205
1206 if (c == -1 || c == EOF || c == 1)
1207 break;
1208
1209 switch (c) {
1210 case '?': /* print short usage statement if args not parsable */
1211 usage5();
1212 case 'h': /* help */
1213 print_help();
1214 exit(STATE_UNKNOWN);
1215 case 'V': /* version */
1216 print_revision(progname, NP_VERSION);
1217 exit(STATE_UNKNOWN);
1218 case 'H': /* hostname */
1219 server_address = optarg;
1220 break;
1221 case 'o': /* display nos version */
1222 check_netware_version = true;
1223 break;
1224 case 'p': /* port */
1225 if (is_intnonneg(optarg))
1226 server_port = atoi(optarg);
1227 else
1228 die(STATE_UNKNOWN, _("Server port an integer\n"));
1229 break;
1230 case 'v':
1231 if (strlen(optarg) < 3)
1232 return ERROR;
1233 if (!strcmp(optarg, "LOAD1"))
1234 vars_to_check = LOAD1;
1235 else if (!strcmp(optarg, "LOAD5"))
1236 vars_to_check = LOAD5;
1237 else if (!strcmp(optarg, "LOAD15"))
1238 vars_to_check = LOAD15;
1239 else if (!strcmp(optarg, "CONNS"))
1240 vars_to_check = CONNS;
1241 else if (!strcmp(optarg, "LTCH"))
1242 vars_to_check = LTCH;
1243 else if (!strcmp(optarg, "DCB"))
1244 vars_to_check = DCB;
1245 else if (!strcmp(optarg, "TCB"))
1246 vars_to_check = TCB;
1247 else if (!strcmp(optarg, "CBUFF"))
1248 vars_to_check = CBUFF;
1249 else if (!strcmp(optarg, "CDBUFF"))
1250 vars_to_check = CDBUFF;
1251 else if (!strcmp(optarg, "LRUM"))
1252 vars_to_check = LRUM;
1253 else if (!strcmp(optarg, "LRUS"))
1254 vars_to_check = LRUS;
1255 else if (strncmp(optarg, "VPF", 3) == 0) {
1256 vars_to_check = VPF;
1257 volume_name = strdup(optarg + 3);
1258 if (!strcmp(volume_name, ""))
1259 volume_name = strdup("SYS");
1260 } else if (strncmp(optarg, "VKF", 3) == 0) {
1261 vars_to_check = VKF;
1262 volume_name = strdup(optarg + 3);
1263 if (!strcmp(volume_name, ""))
1264 volume_name = strdup("SYS");
1265 } else if (strncmp(optarg, "VMF", 3) == 0) {
1266 vars_to_check = VMF;
1267 volume_name = strdup(optarg + 3);
1268 if (!strcmp(volume_name, ""))
1269 volume_name = strdup("SYS");
1270 } else if (!strcmp(optarg, "DSDB"))
1271 vars_to_check = DSDB;
1272 else if (!strcmp(optarg, "LOGINS"))
1273 vars_to_check = LOGINS;
1274 else if (!strcmp(optarg, "NRMH"))
1275 vars_to_check = NRMH;
1276 else if (!strcmp(optarg, "UPRB"))
1277 vars_to_check = UPRB;
1278 else if (!strcmp(optarg, "PUPRB"))
1279 vars_to_check = PUPRB;
1280 else if (!strncmp(optarg, "SAPENTRIES", 10)) {
1281 vars_to_check = SAPENTRIES;
1282 if (strlen(optarg) > 10)
1283 sap_number = atoi(optarg + 10);
1284 else
1285 sap_number = -1;
1286 } else if (!strcmp(optarg, "OFILES"))
1287 vars_to_check = OFILES;
1288 else if (strncmp(optarg, "VKP", 3) == 0) {
1289 vars_to_check = VKP;
1290 volume_name = strdup(optarg + 3);
1291 if (!strcmp(volume_name, ""))
1292 volume_name = strdup("SYS");
1293 } else if (strncmp(optarg, "VMP", 3) == 0) {
1294 vars_to_check = VMP;
1295 volume_name = strdup(optarg + 3);
1296 if (!strcmp(volume_name, ""))
1297 volume_name = strdup("SYS");
1298 } else if (strncmp(optarg, "VMU", 3) == 0) {
1299 vars_to_check = VMU;
1300 volume_name = strdup(optarg + 3);
1301 if (!strcmp(volume_name, ""))
1302 volume_name = strdup("SYS");
1303 } else if (strncmp(optarg, "VPU", 3) == 0) {
1304 vars_to_check = VPU;
1305 volume_name = strdup(optarg + 3);
1306 if (!strcmp(volume_name, ""))
1307 volume_name = strdup("SYS");
1308 } else if (strncmp(optarg, "VPP", 3) == 0) {
1309 vars_to_check = VPP;
1310 volume_name = strdup(optarg + 3);
1311 if (!strcmp(volume_name, ""))
1312 volume_name = strdup("SYS");
1313 } else if (strncmp(optarg, "VKNP", 4) == 0) {
1314 vars_to_check = VKNP;
1315 volume_name = strdup(optarg + 4);
1316 if (!strcmp(volume_name, ""))
1317 volume_name = strdup("SYS");
1318 } else if (strncmp(optarg, "VPNP", 4) == 0) {
1319 vars_to_check = VPNP;
1320 volume_name = strdup(optarg + 4);
1321 if (!strcmp(volume_name, ""))
1322 volume_name = strdup("SYS");
1323 } else if (!strcmp(optarg, "ABENDS"))
1324 vars_to_check = ABENDS;
1325 else if (!strcmp(optarg, "CSPROCS"))
1326 vars_to_check = CSPROCS;
1327 else if (!strcmp(optarg, "TSYNC"))
1328 vars_to_check = TSYNC;
1329 else if (!strcmp(optarg, "DSVER"))
1330 vars_to_check = DSVER;
1331 else if (!strcmp(optarg, "UPTIME")) {
1332 vars_to_check = UPTIME;
1333 } else if (strncmp(optarg, "NLM:", 4) == 0) {
1334 vars_to_check = NLM;
1335 nlm_name = strdup(optarg + 4);
1336 } else if (strncmp(optarg, "NRMP", 4) == 0) {
1337 vars_to_check = NRMP;
1338 nrmp_name = strdup(optarg + 4);
1339 if (!strcmp(nrmp_name, ""))
1340 nrmp_name = strdup("AVAILABLE_MEMORY");
1341 } else if (strncmp(optarg, "NRMM", 4) == 0) {
1342 vars_to_check = NRMM;
1343 nrmm_name = strdup(optarg + 4);
1344 if (!strcmp(nrmm_name, ""))
1345 nrmm_name = strdup("AVAILABLE_CACHE_MEMORY");
1346
1347 }
1348
1349 else if (strncmp(optarg, "NRMS", 4) == 0) {
1350 vars_to_check = NRMS;
1351 nrms_name = strdup(optarg + 4);
1352 if (!strcmp(nrms_name, ""))
1353 nrms_name = strdup("USED_SWAP_SPACE");
1354
1355 }
1356
1357 else if (strncmp(optarg, "NSS1", 4) == 0) {
1358 vars_to_check = NSS1;
1359 nss1_name = strdup(optarg + 4);
1360 if (!strcmp(nss1_name, ""))
1361 nss1_name = strdup("CURRENTBUFFERCACHESIZE");
1362
1363 }
1364
1365 else if (strncmp(optarg, "NSS2", 4) == 0) {
1366 vars_to_check = NSS2;
1367 nss2_name = strdup(optarg + 4);
1368 if (!strcmp(nss2_name, ""))
1369 nss2_name = strdup("CACHEHITS");
1370
1371 }
1372
1373 else if (strncmp(optarg, "NSS3", 4) == 0) {
1374 vars_to_check = NSS3;
1375 nss3_name = strdup(optarg + 4);
1376 if (!strcmp(nss3_name, ""))
1377 nss3_name = strdup("CACHEGITPERCENT");
1378
1379 }
1380
1381 else if (strncmp(optarg, "NSS4", 4) == 0) {
1382 vars_to_check = NSS4;
1383 nss4_name = strdup(optarg + 4);
1384 if (!strcmp(nss4_name, ""))
1385 nss4_name = strdup("CURRENTOPENCOUNT");
1386
1387 }
1388
1389 else if (strncmp(optarg, "NSS5", 4) == 0) {
1390 vars_to_check = NSS5;
1391 nss5_name = strdup(optarg + 4);
1392 if (!strcmp(nss5_name, ""))
1393 nss5_name = strdup("CACHEMISSES");
1394
1395 }
1396
1397 else if (strncmp(optarg, "NSS6", 4) == 0) {
1398 vars_to_check = NSS6;
1399 nss6_name = strdup(optarg + 4);
1400 if (!strcmp(nss6_name, ""))
1401 nss6_name = strdup("PENDINGWORKSCOUNT");
1402
1403 }
1404
1405 else if (strncmp(optarg, "NSS7", 4) == 0) {
1406 vars_to_check = NSS7;
1407 nss7_name = strdup(optarg + 4);
1408 if (!strcmp(nss7_name, ""))
1409 nss7_name = strdup("CACHESIZE");
1410
1411 }
1412
1413 else
1414 return ERROR;
1415 break;
1416 case 'w': /* warning threshold */
1417 warning_value = strtoul(optarg, NULL, 10);
1418 check_warning_value = true;
1419 break;
1420 case 'c': /* critical threshold */
1421 critical_value = strtoul(optarg, NULL, 10);
1422 check_critical_value = true;
1423 break;
1424 case 't': /* timeout */
1425 socket_timeout = atoi(optarg);
1426 if (socket_timeout <= 0)
1427 return ERROR;
1428 }
1429 }
1430
1431 return OK;
1432}
1433
1434void print_help(void) {
1435 char *myport;
1436 xasprintf(&myport, "%d", PORT);
1437
1438 print_revision(progname, NP_VERSION);
1439
1440 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1441 printf(COPYRIGHT, copyright, email);
1442
1443 printf("%s\n", _("This plugin attempts to contact the MRTGEXT NLM running on a"));
1444 printf("%s\n", _("Novell server to gather the requested system information."));
1445
1446 printf("\n\n");
1447
1448 print_usage();
1449
1450 printf(UT_HELP_VRSN);
1451 printf(UT_EXTRA_OPTS);
1452
1453 printf(UT_HOST_PORT, 'p', myport);
1454
1455 printf(" %s\n", "-v, --variable=STRING");
1456 printf(" %s\n", _("Variable to check. Valid variables include:"));
1457 printf(" %s\n", _("LOAD1 = 1 minute average CPU load"));
1458 printf(" %s\n", _("LOAD5 = 5 minute average CPU load"));
1459 printf(" %s\n", _("LOAD15 = 15 minute average CPU load"));
1460 printf(" %s\n", _("CSPROCS = number of current service processes (NW 5.x only)"));
1461 printf(" %s\n", _("ABENDS = number of abended threads (NW 5.x only)"));
1462 printf(" %s\n", _("UPTIME = server uptime"));
1463 printf(" %s\n", _("LTCH = percent long term cache hits"));
1464 printf(" %s\n", _("CBUFF = current number of cache buffers"));
1465 printf(" %s\n", _("CDBUFF = current number of dirty cache buffers"));
1466 printf(" %s\n", _("DCB = dirty cache buffers as a percentage of the total"));
1467 printf(" %s\n", _("TCB = dirty cache buffers as a percentage of the original"));
1468 printf(" %s\n", _("OFILES = number of open files"));
1469 printf(" %s\n", _(" VMF<vol> = MB of free space on Volume <vol>"));
1470 printf(" %s\n", _(" VMU<vol> = MB used space on Volume <vol>"));
1471 printf(" %s\n", _(" VPU<vol> = percent used space on Volume <vol>"));
1472 printf(" %s\n", _(" VMP<vol> = MB of purgeable space on Volume <vol>"));
1473 printf(" %s\n", _(" VPF<vol> = percent free space on volume <vol>"));
1474 printf(" %s\n", _(" VKF<vol> = KB of free space on volume <vol>"));
1475 printf(" %s\n", _(" VPP<vol> = percent purgeable space on volume <vol>"));
1476 printf(" %s\n", _(" VKP<vol> = KB of purgeable space on volume <vol>"));
1477 printf(" %s\n", _(" VPNP<vol> = percent not yet purgeable space on volume <vol>"));
1478 printf(" %s\n", _(" VKNP<vol> = KB of not yet purgeable space on volume <vol>"));
1479 printf(" %s\n", _(" LRUM = LRU sitting time in minutes"));
1480 printf(" %s\n", _(" LRUS = LRU sitting time in seconds"));
1481 printf(" %s\n", _(" DSDB = check to see if DS Database is open"));
1482 printf(" %s\n", _(" DSVER = NDS version"));
1483 printf(" %s\n", _(" UPRB = used packet receive buffers"));
1484 printf(" %s\n", _(" PUPRB = percent (of max) used packet receive buffers"));
1485 printf(" %s\n", _(" SAPENTRIES = number of entries in the SAP table"));
1486 printf(" %s\n", _(" SAPENTRIES<n> = number of entries in the SAP table for SAP type <n>"));
1487 printf(" %s\n", _(" TSYNC = timesync status"));
1488 printf(" %s\n", _(" LOGINS = check to see if logins are enabled"));
1489 printf(" %s\n", _(" CONNS = number of currently licensed connections"));
1490 printf(" %s\n", _(" NRMH = NRM Summary Status"));
1491 printf(" %s\n", _(" NRMP<stat> = Returns the current value for a NRM health item"));
1492 printf(" %s\n", _(" NRMM<stat> = Returns the current memory stats from NRM"));
1493 printf(" %s\n", _(" NRMS<stat> = Returns the current Swapfile stats from NRM"));
1494 printf(" %s\n", _(" NSS1<stat> = Statistics from _Admin:Manage_NSS\\GeneralStats.xml"));
1495 printf(" %s\n", _(" NSS3<stat> = Statistics from _Admin:Manage_NSS\\NameCache.xml"));
1496 printf(" %s\n", _(" NSS4<stat> = Statistics from _Admin:Manage_NSS\\FileStats.xml"));
1497 printf(" %s\n", _(" NSS5<stat> = Statistics from _Admin:Manage_NSS\\ObjectCache.xml"));
1498 printf(" %s\n", _(" NSS6<stat> = Statistics from _Admin:Manage_NSS\\Thread.xml"));
1499 printf(" %s\n", _(" NSS7<stat> = Statistics from _Admin:Manage_NSS\\AuthorizationCache.xml"));
1500 printf(" %s\n", _(" NLM:<nlm> = check if NLM is loaded and report version"));
1501 printf(" %s\n", _(" (e.g. NLM:TSANDS.NLM)"));
1502 printf("\n");
1503 printf(" %s\n", "-w, --warning=INTEGER");
1504 printf(" %s\n", _("Threshold which will result in a warning status"));
1505 printf(" %s\n", "-c, --critical=INTEGER");
1506 printf(" %s\n", _("Threshold which will result in a critical status"));
1507 printf(" %s\n", "-o, --osversion");
1508 printf(" %s\n", _("Include server version string in results"));
1509
1510 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1511
1512 printf("\n");
1513 printf("%s\n", _("Notes:"));
1514 printf(" %s\n", _("- This plugin requires that the MRTGEXT.NLM file from James Drews' MRTG"));
1515 printf(" %s\n", _(" extension for NetWare be loaded on the Novell servers you wish to check."));
1516 printf(" %s\n", _(" (available from http://www.engr.wisc.edu/~drews/mrtg/)"));
1517 printf(" %s\n", _("- Values for critical thresholds should be lower than warning thresholds"));
1518 printf(" %s\n", _(" when the following variables are checked: VPF, VKF, LTCH, CBUFF, DCB, "));
1519 printf(" %s\n", _(" TCB, LRUS and LRUM."));
1520
1521 printf(UT_SUPPORT);
1522}
1523
1524void print_usage(void) {
1525 printf("%s\n", _("Usage:"));
1526 printf("%s -H host [-p port] [-v variable] [-w warning] [-c critical] [-t timeout]\n", progname);
1527}
diff --git a/plugins/check_pgsql.c b/plugins/check_pgsql.c
index 84305adb..0ce75e0a 100644
--- a/plugins/check_pgsql.c
+++ b/plugins/check_pgsql.c
@@ -28,32 +28,35 @@
28 * 28 *
29 *****************************************************************************/ 29 *****************************************************************************/
30 30
31#include "output.h"
32#include "perfdata.h"
31#include "states.h" 33#include "states.h"
32const char *progname = "check_pgsql";
33const char *copyright = "1999-2024";
34const char *email = "devel@monitoring-plugins.org";
35
36#include "common.h" 34#include "common.h"
37#include "utils.h" 35#include "utils.h"
38#include "utils_cmd.h" 36#include "utils_cmd.h"
39#include "check_pgsql.d/config.h" 37#include "check_pgsql.d/config.h"
40#include "thresholds.h" 38#include "thresholds.h"
41
42#include "netutils.h" 39#include "netutils.h"
43#include <libpq-fe.h> 40#include <libpq-fe.h>
44#include <pg_config_manual.h> 41#include <pg_config_manual.h>
45 42
43const char *progname = "check_pgsql";
44const char *copyright = "1999-2024";
45const char *email = "devel@monitoring-plugins.org";
46
46#define DEFAULT_HOST "127.0.0.1" 47#define DEFAULT_HOST "127.0.0.1"
47 48
48/* return the PSQL server version as a 3-tuple */ 49/* return the PSQL server version as a 3-tuple */
49#define PSQL_SERVER_VERSION3(server_version) \ 50#define PSQL_SERVER_VERSION3(server_version) \
50 (server_version) / 10000, (server_version) / 100 - (int)((server_version) / 10000) * 100, \ 51 ((server_version) / 10000), \
51 (server_version) - (int)((server_version) / 100) * 100 52 (((server_version) / 100) - (int)(((server_version) / 10000) * 100)), \
53 (server_version) - (int)(((server_version) / 100) * 100)
52/* return true if the given host is a UNIX domain socket */ 54/* return true if the given host is a UNIX domain socket */
53#define PSQL_IS_UNIX_DOMAIN_SOCKET(host) ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host))) 55#define PSQL_IS_UNIX_DOMAIN_SOCKET(host) ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host)))
54/* return a 3-tuple identifying a host/port independent of the socket type */ 56/* return a 3-tuple identifying a host/port independent of the socket type */
55#define PSQL_SOCKET3(host, port) \ 57#define PSQL_SOCKET3(host, port) \
56 ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, PSQL_IS_UNIX_DOMAIN_SOCKET(host) ? "/.s.PGSQL." : ":", port 58 ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, \
59 PSQL_IS_UNIX_DOMAIN_SOCKET(host) ? "/.s.PGSQL." : ":", port
57 60
58typedef struct { 61typedef struct {
59 int errorcode; 62 int errorcode;
@@ -63,14 +66,25 @@ static check_pgsql_config_wrapper process_arguments(int /*argc*/, char ** /*argv
63 66
64static void print_help(void); 67static void print_help(void);
65static bool is_pg_logname(char * /*username*/); 68static bool is_pg_logname(char * /*username*/);
66static mp_state_enum do_query(PGconn * /*conn*/, char * /*query*/, const char /*pgqueryname*/[], thresholds * /*qthresholds*/, 69
67 char * /*query_warning*/, char * /*query_critical*/); 70typedef enum {
71 QUERY_OK,
72 ERROR_WITH_QUERY, // critical
73 NO_ROWS_RETURNED, // warning
74 NO_COLUMNS_RETURNED, // warning
75 NO_DATA_RETURNED, // critica/
76 RESULT_IS_NOT_NUMERIC // critical
77} do_query_errorcode;
78
79typedef struct {
80 do_query_errorcode error_code;
81 double numerical_result;
82} do_query_wrapper;
83static do_query_wrapper do_query(PGconn * /*conn*/, char * /*query*/);
68void print_usage(void); 84void print_usage(void);
69 85
70static int verbose = 0; 86static int verbose = 0;
71 87
72#define OPTID_QUERYNAME -1000
73
74/****************************************************************************** 88/******************************************************************************
75 89
76The (pseudo?)literate programming XML is contained within \@\@\- <XML> \-\@\@ 90The (pseudo?)literate programming XML is contained within \@\@\- <XML> \-\@\@
@@ -136,8 +150,8 @@ int main(int argc, char **argv) {
136 150
137 const check_pgsql_config config = tmp_config.config; 151 const check_pgsql_config config = tmp_config.config;
138 152
139 if (verbose > 2) { 153 if (config.output_format_is_set) {
140 printf("Arguments initialized\n"); 154 mp_set_format(config.output_format);
141 } 155 }
142 156
143 /* Set signal handling and alarm */ 157 /* Set signal handling and alarm */
@@ -167,7 +181,8 @@ int main(int argc, char **argv) {
167 } 181 }
168 182
169 if (verbose) { /* do not include password (see right below) in output */ 183 if (verbose) { /* do not include password (see right below) in output */
170 printf("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo, config.pgpasswd ? " password = <hidden>" : ""); 184 printf("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo,
185 config.pgpasswd ? " password = <hidden>" : "");
171 } 186 }
172 187
173 if (config.pgpasswd) { 188 if (config.pgpasswd) {
@@ -185,8 +200,8 @@ int main(int argc, char **argv) {
185 --end_timeval.tv_sec; 200 --end_timeval.tv_sec;
186 end_timeval.tv_usec += 1000000; 201 end_timeval.tv_usec += 1000000;
187 } 202 }
188 double elapsed_time = 203 double elapsed_time = (double)(end_timeval.tv_sec - start_timeval.tv_sec) +
189 (double)(end_timeval.tv_sec - start_timeval.tv_sec) + ((double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0); 204 ((double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0);
190 205
191 if (verbose) { 206 if (verbose) {
192 printf("Time elapsed: %f\n", elapsed_time); 207 printf("Time elapsed: %f\n", elapsed_time);
@@ -196,21 +211,41 @@ int main(int argc, char **argv) {
196 if (verbose) { 211 if (verbose) {
197 printf("Verifying connection\n"); 212 printf("Verifying connection\n");
198 } 213 }
214
215 mp_check overall = mp_check_init();
216
217 mp_subcheck sc_connection = mp_subcheck_init();
218
199 if (PQstatus(conn) == CONNECTION_BAD) { 219 if (PQstatus(conn) == CONNECTION_BAD) {
200 printf(_("CRITICAL - no connection to '%s' (%s).\n"), config.dbName, PQerrorMessage(conn)); 220 sc_connection = mp_set_subcheck_state(sc_connection, STATE_CRITICAL);
221 xasprintf(&sc_connection.output, "no connection to '%s' (%s)", config.dbName,
222 PQerrorMessage(conn));
201 PQfinish(conn); 223 PQfinish(conn);
202 return STATE_CRITICAL; 224 mp_add_subcheck_to_check(&overall, sc_connection);
203 } 225 mp_exit(overall);
204
205 mp_state_enum status = STATE_UNKNOWN;
206 if (elapsed_time > config.tcrit) {
207 status = STATE_CRITICAL;
208 } else if (elapsed_time > config.twarn) {
209 status = STATE_WARNING;
210 } else { 226 } else {
211 status = STATE_OK; 227 sc_connection = mp_set_subcheck_state(sc_connection, STATE_OK);
228 xasprintf(&sc_connection.output, "connected to '%s'", config.dbName);
229 mp_add_subcheck_to_check(&overall, sc_connection);
212 } 230 }
213 231
232 mp_subcheck sc_connection_time = mp_subcheck_init();
233 sc_connection_time = mp_set_subcheck_default_state(sc_connection_time, STATE_UNKNOWN);
234
235 xasprintf(&sc_connection_time.output, "connection time: %.10g", elapsed_time);
236
237 mp_perfdata pd_connection_time = perfdata_init();
238 pd_connection_time.label = "time";
239 pd_connection_time.uom = "s";
240 pd_connection_time = mp_set_pd_value(pd_connection_time, elapsed_time);
241 pd_connection_time = mp_pd_set_thresholds(pd_connection_time, config.time_thresholds);
242
243 mp_add_perfdata_to_subcheck(&sc_connection_time, pd_connection_time);
244 sc_connection_time =
245 mp_set_subcheck_state(sc_connection_time, mp_get_pd_status(pd_connection_time));
246
247 mp_add_subcheck_to_check(&overall, sc_connection_time);
248
214 if (verbose) { 249 if (verbose) {
215 char *server_host = PQhost(conn); 250 char *server_host = PQhost(conn);
216 int server_version = PQserverVersion(conn); 251 int server_version = PQserverVersion(conn);
@@ -218,27 +253,91 @@ int main(int argc, char **argv) {
218 printf("Successfully connected to database %s (user %s) " 253 printf("Successfully connected to database %s (user %s) "
219 "at server %s%s%s (server version: %d.%d.%d, " 254 "at server %s%s%s (server version: %d.%d.%d, "
220 "protocol version: %d, pid: %d)\n", 255 "protocol version: %d, pid: %d)\n",
221 PQdb(conn), PQuser(conn), PSQL_SOCKET3(server_host, PQport(conn)), PSQL_SERVER_VERSION3(server_version), 256 PQdb(conn), PQuser(conn), PSQL_SOCKET3(server_host, PQport(conn)),
222 PQprotocolVersion(conn), PQbackendPID(conn)); 257 PSQL_SERVER_VERSION3(server_version), PQprotocolVersion(conn), PQbackendPID(conn));
223 } 258 }
224 259
225 printf(_(" %s - database %s (%f sec.)|%s\n"), state_text(status), config.dbName, elapsed_time,
226 fperfdata("time", elapsed_time, "s", (config.twarn > 0.0), config.twarn, (config.tcrit > 0.0), config.tcrit, true, 0, false, 0));
227
228 mp_state_enum query_status = STATE_UNKNOWN;
229 if (config.pgquery) { 260 if (config.pgquery) {
230 query_status = do_query(conn, config.pgquery, config.pgqueryname, config.qthresholds, config.query_warning, config.query_critical); 261 mp_subcheck sc_query = mp_subcheck_init();
262 sc_query = mp_set_subcheck_default_state(sc_query, STATE_UNKNOWN);
263 if (config.pgqueryname) {
264 xasprintf(&sc_query.output, "query '%s'", config.pgqueryname);
265 } else {
266 xasprintf(&sc_query.output, "query '%s'", config.pgquery);
267 }
268
269 do_query_wrapper query_result = do_query(conn, config.pgquery);
270
271 switch (query_result.error_code) {
272 case QUERY_OK: {
273 // Query was successful and there is a numerical result
274 sc_query = mp_set_subcheck_state(sc_query, STATE_OK);
275 xasprintf(&sc_query.output, "%s succeeded", sc_query.output);
276
277 mp_perfdata pd_query = perfdata_init();
278 pd_query = mp_set_pd_value(pd_query, query_result.numerical_result);
279 pd_query = mp_pd_set_thresholds(pd_query, config.qthresholds);
280 pd_query.label = "query";
281
282 mp_subcheck sc_query_compare = mp_subcheck_init();
283 mp_state_enum query_compare_state = mp_get_pd_status(pd_query);
284
285 sc_query_compare = mp_set_subcheck_state(sc_query_compare, query_compare_state);
286 mp_add_perfdata_to_subcheck(&sc_query_compare, pd_query);
287
288 if (query_compare_state == STATE_OK) {
289 xasprintf(&sc_query_compare.output, "query result '%f' is within thresholds",
290 query_result.numerical_result);
291 } else {
292 xasprintf(&sc_query_compare.output, "query result '%f' is violating thresholds",
293 query_result.numerical_result);
294 }
295 mp_add_subcheck_to_check(&overall, sc_query_compare);
296
297 } break;
298 case ERROR_WITH_QUERY:
299 xasprintf(&sc_query.output, "%s - Error with query: %s", sc_query.output,
300 PQerrorMessage(conn));
301 sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
302 break;
303 case NO_ROWS_RETURNED:
304 xasprintf(&sc_query.output, "%s - no rows were returned by the query", sc_query.output);
305 sc_query = mp_set_subcheck_state(sc_query, STATE_WARNING);
306 break;
307 case NO_COLUMNS_RETURNED:
308 xasprintf(&sc_query.output, "%s - no columns were returned by the query",
309 sc_query.output);
310 sc_query = mp_set_subcheck_state(sc_query, STATE_WARNING);
311 break;
312 case NO_DATA_RETURNED:
313 xasprintf(&sc_query.output, "%s - no data was returned by the query", sc_query.output);
314 sc_query = mp_set_subcheck_state(sc_query, STATE_WARNING);
315 break;
316 case RESULT_IS_NOT_NUMERIC:
317 xasprintf(&sc_query.output, "%s - result of the query is not numeric", sc_query.output);
318 sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
319 break;
320 };
321
322 mp_add_subcheck_to_check(&overall, sc_query);
231 } 323 }
232 324
233 if (verbose) { 325 if (verbose) {
234 printf("Closing connection\n"); 326 printf("Closing connection\n");
235 } 327 }
236 PQfinish(conn); 328 PQfinish(conn);
237 return (config.pgquery && query_status > status) ? query_status : status; 329
330 mp_exit(overall);
238} 331}
239 332
240/* process command-line arguments */ 333/* process command-line arguments */
241check_pgsql_config_wrapper process_arguments(int argc, char **argv) { 334static check_pgsql_config_wrapper process_arguments(int argc, char **argv) {
335
336 enum {
337 OPTID_QUERYNAME = CHAR_MAX + 1,
338 output_format_index,
339 };
340
242 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, 341 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
243 {"version", no_argument, 0, 'V'}, 342 {"version", no_argument, 0, 'V'},
244 {"timeout", required_argument, 0, 't'}, 343 {"timeout", required_argument, 0, 't'},
@@ -256,6 +355,7 @@ check_pgsql_config_wrapper process_arguments(int argc, char **argv) {
256 {"query_critical", required_argument, 0, 'C'}, 355 {"query_critical", required_argument, 0, 'C'},
257 {"query_warning", required_argument, 0, 'W'}, 356 {"query_warning", required_argument, 0, 'W'},
258 {"verbose", no_argument, 0, 'v'}, 357 {"verbose", no_argument, 0, 'v'},
358 {"output-format", required_argument, 0, output_format_index},
259 {0, 0, 0, 0}}; 359 {0, 0, 0, 0}};
260 360
261 check_pgsql_config_wrapper result = { 361 check_pgsql_config_wrapper result = {
@@ -265,13 +365,25 @@ check_pgsql_config_wrapper process_arguments(int argc, char **argv) {
265 365
266 while (true) { 366 while (true) {
267 int option = 0; 367 int option = 0;
268 int option_char = getopt_long(argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v", longopts, &option); 368 int option_char =
369 getopt_long(argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v", longopts, &option);
269 370
270 if (option_char == EOF) { 371 if (option_char == EOF) {
271 break; 372 break;
272 } 373 }
273 374
274 switch (option_char) { 375 switch (option_char) {
376 case output_format_index: {
377 parsed_output_format parser = mp_parse_output_format(optarg);
378 if (!parser.parsing_success) {
379 printf("Invalid output format: %s\n", optarg);
380 exit(STATE_UNKNOWN);
381 }
382
383 result.config.output_format_is_set = true;
384 result.config.output_format = parser.output_format;
385 break;
386 }
275 case '?': /* usage */ 387 case '?': /* usage */
276 usage5(); 388 usage5();
277 case 'h': /* help */ 389 case 'h': /* help */
@@ -287,26 +399,40 @@ check_pgsql_config_wrapper process_arguments(int argc, char **argv) {
287 timeout_interval = atoi(optarg); 399 timeout_interval = atoi(optarg);
288 } 400 }
289 break; 401 break;
290 case 'c': /* critical time threshold */ 402 case 'c': /* critical time threshold */ {
291 if (!is_nonnegative(optarg)) { 403 mp_range_parsed tmp = mp_parse_range_string(optarg);
292 usage2(_("Critical threshold must be a positive integer"), optarg); 404 if (tmp.error != MP_PARSING_SUCCES) {
293 } else { 405 die(STATE_UNKNOWN, "failed to parse critical time threshold");
294 result.config.tcrit = strtod(optarg, NULL);
295 } 406 }
296 break; 407 result.config.time_thresholds =
297 case 'w': /* warning time threshold */ 408 mp_thresholds_set_crit(result.config.time_thresholds, tmp.range);
298 if (!is_nonnegative(optarg)) { 409 } break;
299 usage2(_("Warning threshold must be a positive integer"), optarg); 410 case 'w': /* warning time threshold */ {
300 } else { 411 mp_range_parsed tmp = mp_parse_range_string(optarg);
301 result.config.twarn = strtod(optarg, NULL); 412 if (tmp.error != MP_PARSING_SUCCES) {
413 die(STATE_UNKNOWN, "failed to parse warning time threshold");
302 } 414 }
303 break; 415 result.config.time_thresholds =
304 case 'C': /* critical query threshold */ 416 mp_thresholds_set_warn(result.config.time_thresholds, tmp.range);
305 result.config.query_critical = optarg; 417 } break;
306 break; 418 case 'C': /* critical query threshold */ {
307 case 'W': /* warning query threshold */ 419 mp_range_parsed tmp = mp_parse_range_string(optarg);
308 result.config.query_warning = optarg; 420 if (tmp.error != MP_PARSING_SUCCES) {
309 break; 421 die(STATE_UNKNOWN, "failed to parse critical query threshold");
422 }
423
424 result.config.qthresholds =
425 mp_thresholds_set_crit(result.config.qthresholds, tmp.range);
426
427 } break;
428 case 'W': /* warning query threshold */ {
429 mp_range_parsed tmp = mp_parse_range_string(optarg);
430 if (tmp.error != MP_PARSING_SUCCES) {
431 die(STATE_UNKNOWN, "failed to parse warning query threshold");
432 }
433 result.config.qthresholds =
434 mp_thresholds_set_warn(result.config.qthresholds, tmp.range);
435 } break;
310 case 'H': /* host */ 436 case 'H': /* host */
311 if ((*optarg != '/') && (!is_host(optarg))) { 437 if ((*optarg != '/') && (!is_host(optarg))) {
312 usage2(_("Invalid hostname/address"), optarg); 438 usage2(_("Invalid hostname/address"), optarg);
@@ -357,8 +483,6 @@ check_pgsql_config_wrapper process_arguments(int argc, char **argv) {
357 } 483 }
358 } 484 }
359 485
360 set_thresholds(&result.config.qthresholds, result.config.query_warning, result.config.query_critical);
361
362 return result; 486 return result;
363} 487}
364 488
@@ -386,7 +510,7 @@ should be added.</para>
386-@@ 510-@@
387******************************************************************************/ 511******************************************************************************/
388 512
389bool is_pg_logname(char *username) { 513static bool is_pg_logname(char *username) {
390 if (strlen(username) > NAMEDATALEN - 1) { 514 if (strlen(username) > NAMEDATALEN - 1) {
391 return (false); 515 return (false);
392 } 516 }
@@ -440,12 +564,13 @@ void print_help(void) {
440 printf(" %s\n", "--queryname=STRING"); 564 printf(" %s\n", "--queryname=STRING");
441 printf(" %s\n", _("A name for the query, this string is used instead of the query")); 565 printf(" %s\n", _("A name for the query, this string is used instead of the query"));
442 printf(" %s\n", _("in the long output of the plugin")); 566 printf(" %s\n", _("in the long output of the plugin"));
443 printf(" %s\n", "-W, --query-warning=RANGE"); 567 printf(" %s\n", "-W, --query_warning=RANGE");
444 printf(" %s\n", _("SQL query value to result in warning status (double)")); 568 printf(" %s\n", _("SQL query value to result in warning status (double)"));
445 printf(" %s\n", "-C, --query-critical=RANGE"); 569 printf(" %s\n", "-C, --query_critical=RANGE");
446 printf(" %s\n", _("SQL query value to result in critical status (double)")); 570 printf(" %s\n", _("SQL query value to result in critical status (double)"));
447 571
448 printf(UT_VERBOSE); 572 printf(UT_VERBOSE);
573 printf(UT_OUTPUT_FORMAT);
449 574
450 printf("\n"); 575 printf("\n");
451 printf(" %s\n", _("All parameters are optional.")); 576 printf(" %s\n", _("All parameters are optional."));
@@ -457,29 +582,39 @@ void print_help(void) {
457 582
458 printf(" %s\n", _("If a query is specified using the -q option, it will be executed after")); 583 printf(" %s\n", _("If a query is specified using the -q option, it will be executed after"));
459 printf(" %s\n", _("connecting to the server. The result from the query has to be numeric.")); 584 printf(" %s\n", _("connecting to the server. The result from the query has to be numeric."));
460 printf(" %s\n", _("Multiple SQL commands, separated by semicolon, are allowed but the result ")); 585 printf(" %s\n",
586 _("Multiple SQL commands, separated by semicolon, are allowed but the result "));
461 printf(" %s\n", _("of the last command is taken into account only. The value of the first")); 587 printf(" %s\n", _("of the last command is taken into account only. The value of the first"));
462 printf(" %s\n", _("column in the first row is used as the check result. If a second column is")); 588 printf(" %s\n",
589 _("column in the first row is used as the check result. If a second column is"));
463 printf(" %s\n", _("present in the result set, this is added to the plugin output with a")); 590 printf(" %s\n", _("present in the result set, this is added to the plugin output with a"));
464 printf(" %s\n", _("prefix of \"Extra Info:\". This information can be displayed in the system")); 591 printf(" %s\n",
592 _("prefix of \"Extra Info:\". This information can be displayed in the system"));
465 printf(" %s\n\n", _("executing the plugin.")); 593 printf(" %s\n\n", _("executing the plugin."));
466 594
467 printf(" %s\n", _("See the chapter \"Monitoring Database Activity\" of the PostgreSQL manual")); 595 printf(" %s\n", _("See the chapter \"Monitoring Database Activity\" of the PostgreSQL manual"));
468 printf(" %s\n\n", _("for details about how to access internal statistics of the database server.")); 596 printf(" %s\n\n",
597 _("for details about how to access internal statistics of the database server."));
469 598
470 printf(" %s\n", _("For a list of available connection parameters which may be used with the -o")); 599 printf(" %s\n",
471 printf(" %s\n", _("command line option, see the documentation for PQconnectdb() in the chapter")); 600 _("For a list of available connection parameters which may be used with the -o"));
601 printf(" %s\n",
602 _("command line option, see the documentation for PQconnectdb() in the chapter"));
472 printf(" %s\n", _("\"libpq - C Library\" of the PostgreSQL manual. For example, this may be")); 603 printf(" %s\n", _("\"libpq - C Library\" of the PostgreSQL manual. For example, this may be"));
473 printf(" %s\n", _("used to specify a service name in pg_service.conf to be used for additional")); 604 printf(" %s\n",
605 _("used to specify a service name in pg_service.conf to be used for additional"));
474 printf(" %s\n", _("connection parameters: -o 'service=<name>' or to specify the SSL mode:")); 606 printf(" %s\n", _("connection parameters: -o 'service=<name>' or to specify the SSL mode:"));
475 printf(" %s\n\n", _("-o 'sslmode=require'.")); 607 printf(" %s\n\n", _("-o 'sslmode=require'."));
476 608
477 printf(" %s\n", _("The plugin will connect to a local postmaster if no host is specified. To")); 609 printf(" %s\n", _("The plugin will connect to a local postmaster if no host is specified. To"));
478 printf(" %s\n", _("connect to a remote host, be sure that the remote postmaster accepts TCP/IP")); 610 printf(" %s\n",
611 _("connect to a remote host, be sure that the remote postmaster accepts TCP/IP"));
479 printf(" %s\n\n", _("connections (start the postmaster with the -i option).")); 612 printf(" %s\n\n", _("connections (start the postmaster with the -i option)."));
480 613
481 printf(" %s\n", _("Typically, the monitoring user (unless the --logname option is used) should be")); 614 printf(" %s\n",
482 printf(" %s\n", _("able to connect to the database without a password. The plugin can also send")); 615 _("Typically, the monitoring user (unless the --logname option is used) should be"));
616 printf(" %s\n",
617 _("able to connect to the database without a password. The plugin can also send"));
483 printf(" %s\n", _("a password, but no effort is made to obscure or encrypt the password.")); 618 printf(" %s\n", _("a password, but no effort is made to obscure or encrypt the password."));
484 619
485 printf(UT_SUPPORT); 620 printf(UT_SUPPORT);
@@ -492,32 +627,44 @@ void print_usage(void) {
492 "[-q <query>] [-C <critical query range>] [-W <warning query range>]\n"); 627 "[-q <query>] [-C <critical query range>] [-W <warning query range>]\n");
493} 628}
494 629
495mp_state_enum do_query(PGconn *conn, char *query, const char pgqueryname[], thresholds *qthresholds, char *query_warning, 630static do_query_wrapper do_query(PGconn *conn, char *query) {
496 char *query_critical) {
497 if (verbose) { 631 if (verbose) {
498 printf("Executing SQL query \"%s\".\n", query); 632 printf("Executing SQL query \"%s\".\n", query);
499 } 633 }
500 PGresult *res = PQexec(conn, query); 634 PGresult *res = PQexec(conn, query);
501 635
636 do_query_wrapper result = {
637 .error_code = QUERY_OK,
638 };
639
502 if (PGRES_TUPLES_OK != PQresultStatus(res)) { 640 if (PGRES_TUPLES_OK != PQresultStatus(res)) {
503 printf(_("QUERY %s - %s: %s.\n"), _("CRITICAL"), _("Error with query"), PQerrorMessage(conn)); 641 // TODO
504 return STATE_CRITICAL; 642 // printf(_("QUERY %s - %s: %s.\n"), _("CRITICAL"), _("Error with query"),
643 // PQerrorMessage(conn));
644 result.error_code = ERROR_WITH_QUERY;
645 return result;
505 } 646 }
506 647
507 if (PQntuples(res) < 1) { 648 if (PQntuples(res) < 1) {
508 printf("QUERY %s - %s.\n", _("WARNING"), _("No rows returned")); 649 // TODO
509 return STATE_WARNING; 650 // printf("QUERY %s - %s.\n", _("WARNING"), _("No rows returned"));
651 result.error_code = NO_ROWS_RETURNED;
652 return result;
510 } 653 }
511 654
512 if (PQnfields(res) < 1) { 655 if (PQnfields(res) < 1) {
513 printf("QUERY %s - %s.\n", _("WARNING"), _("No columns returned")); 656 // TODO
514 return STATE_WARNING; 657 // printf("QUERY %s - %s.\n", _("WARNING"), _("No columns returned"));
658 result.error_code = NO_COLUMNS_RETURNED;
659 return result;
515 } 660 }
516 661
517 char *val_str = PQgetvalue(res, 0, 0); 662 char *val_str = PQgetvalue(res, 0, 0);
518 if (!val_str) { 663 if (!val_str) {
519 printf("QUERY %s - %s.\n", _("CRITICAL"), _("No data returned")); 664 // TODO
520 return STATE_CRITICAL; 665 // printf("QUERY %s - %s.\n", _("CRITICAL"), _("No data returned"));
666 result.error_code = NO_DATA_RETURNED;
667 return result;
521 } 668 }
522 669
523 char *endptr = NULL; 670 char *endptr = NULL;
@@ -527,8 +674,10 @@ mp_state_enum do_query(PGconn *conn, char *query, const char pgqueryname[], thre
527 } 674 }
528 675
529 if (endptr == val_str) { 676 if (endptr == val_str) {
530 printf("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str); 677 // TODO
531 return STATE_CRITICAL; 678 // printf("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str);
679 result.error_code = RESULT_IS_NOT_NUMERIC;
680 return result;
532 } 681 }
533 682
534 if ((endptr != NULL) && (*endptr != '\0')) { 683 if ((endptr != NULL) && (*endptr != '\0')) {
@@ -537,23 +686,7 @@ mp_state_enum do_query(PGconn *conn, char *query, const char pgqueryname[], thre
537 } 686 }
538 } 687 }
539 688
540 mp_state_enum my_status = get_status(value, qthresholds); 689 result.numerical_result = value;
541 printf("QUERY %s - ", (my_status == STATE_OK) ? _("OK")
542 : (my_status == STATE_WARNING) ? _("WARNING")
543 : (my_status == STATE_CRITICAL) ? _("CRITICAL")
544 : _("UNKNOWN"));
545 if (pgqueryname) {
546 printf(_("%s returned %f"), pgqueryname, value);
547 } else {
548 printf(_("'%s' returned %f"), query, value);
549 }
550 690
551 printf("|query=%f;%s;%s;;\n", value, query_warning ? query_warning : "", query_critical ? query_critical : ""); 691 return result;
552 if (PQnfields(res) > 1) {
553 char *extra_info = PQgetvalue(res, 0, 1);
554 if (extra_info != NULL) {
555 printf("Extra Info: %s\n", extra_info);
556 }
557 }
558 return my_status;
559} 692}
diff --git a/plugins/check_pgsql.d/config.h b/plugins/check_pgsql.d/config.h
index 2d4b8b89..7cf0637b 100644
--- a/plugins/check_pgsql.d/config.h
+++ b/plugins/check_pgsql.d/config.h
@@ -1,6 +1,8 @@
1#pragma once 1#pragma once
2 2
3#include "../../config.h" 3#include "../../config.h"
4#include "output.h"
5#include "perfdata.h"
4#include "thresholds.h" 6#include "thresholds.h"
5#include <stddef.h> 7#include <stddef.h>
6#include <pg_config_manual.h> 8#include <pg_config_manual.h>
@@ -24,11 +26,11 @@ typedef struct {
24 char *pgquery; 26 char *pgquery;
25 char *pgqueryname; 27 char *pgqueryname;
26 28
27 double twarn; 29 mp_thresholds time_thresholds;
28 double tcrit; 30 mp_thresholds qthresholds;
29 thresholds *qthresholds; 31
30 char *query_warning; 32 bool output_format_is_set;
31 char *query_critical; 33 mp_output_format output_format;
32} check_pgsql_config; 34} check_pgsql_config;
33 35
34/* begin, by setting the parameters for a backend connection if the 36/* begin, by setting the parameters for a backend connection if the
@@ -51,11 +53,18 @@ check_pgsql_config check_pgsql_config_init() {
51 .pgquery = NULL, 53 .pgquery = NULL,
52 .pgqueryname = NULL, 54 .pgqueryname = NULL,
53 55
54 .twarn = (double)DEFAULT_WARN, 56 .time_thresholds = mp_thresholds_init(),
55 .tcrit = (double)DEFAULT_CRIT, 57 .qthresholds = mp_thresholds_init(),
56 .qthresholds = NULL, 58
57 .query_warning = NULL, 59 .output_format_is_set = false,
58 .query_critical = NULL,
59 }; 60 };
61
62 mp_range tmp_range = mp_range_init();
63 tmp_range = mp_range_set_end(tmp_range, mp_create_pd_value(DEFAULT_WARN));
64 tmp.time_thresholds = mp_thresholds_set_warn(tmp.time_thresholds, tmp_range);
65
66 tmp_range = mp_range_set_end(tmp_range, mp_create_pd_value(DEFAULT_CRIT));
67 tmp.time_thresholds = mp_thresholds_set_crit(tmp.time_thresholds, tmp_range);
68
60 return tmp; 69 return tmp;
61} 70}
diff --git a/plugins/check_ping.c b/plugins/check_ping.c
index 4aafaf41..61feb958 100644
--- a/plugins/check_ping.c
+++ b/plugins/check_ping.c
@@ -36,61 +36,52 @@ const char *email = "devel@monitoring-plugins.org";
36#include "netutils.h" 36#include "netutils.h"
37#include "popen.h" 37#include "popen.h"
38#include "utils.h" 38#include "utils.h"
39#include "check_ping.d/config.h"
40#include "../lib/states.h"
39 41
40#include <signal.h> 42#include <signal.h>
41 43
42#define WARN_DUPLICATES "DUPLICATES FOUND! " 44#define WARN_DUPLICATES "DUPLICATES FOUND! "
43#define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */
44 45
45enum { 46typedef struct {
46 UNKNOWN_PACKET_LOSS = 200, /* 200% */ 47 int errorcode;
47 DEFAULT_MAX_PACKETS = 5 /* default no. of ICMP ECHO packets */ 48 check_ping_config config;
48}; 49} check_ping_config_wrapper;
50static check_ping_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
51static check_ping_config_wrapper validate_arguments(check_ping_config_wrapper /*config_wrapper*/);
49 52
50static int process_arguments(int /*argc*/, char ** /*argv*/); 53static int get_threshold(char * /*arg*/, double * /*trta*/, int * /*tpl*/);
51static int get_threshold(char * /*arg*/, float * /*trta*/, int * /*tpl*/); 54
52static int validate_arguments(void); 55typedef struct {
53static int run_ping(const char *cmd, const char *addr); 56 mp_state_enum state;
54static int error_scan(char buf[MAX_INPUT_BUFFER], const char *addr); 57 double round_trip_average;
58 int packet_loss;
59} ping_result;
60static ping_result run_ping(const char *cmd, const char *addr, double /*crta*/);
61
62static mp_state_enum error_scan(char buf[MAX_INPUT_BUFFER], const char *addr);
55static void print_help(void); 63static void print_help(void);
56void print_usage(void); 64void print_usage(void);
57 65
58static bool display_html = false;
59static int wpl = UNKNOWN_PACKET_LOSS;
60static int cpl = UNKNOWN_PACKET_LOSS;
61static float wrta = UNKNOWN_TRIP_TIME;
62static float crta = UNKNOWN_TRIP_TIME;
63static char **addresses = NULL;
64static int n_addresses = 0;
65static int max_addr = 1;
66static int max_packets = -1;
67static int verbose = 0; 66static int verbose = 0;
68 67
69static float rta = UNKNOWN_TRIP_TIME;
70static int pl = UNKNOWN_PACKET_LOSS;
71
72static char *warn_text; 68static char *warn_text;
73 69
74int main(int argc, char **argv) { 70int main(int argc, char **argv) {
75 char *cmd = NULL;
76 char *rawcmd = NULL;
77 int result = STATE_UNKNOWN;
78 int this_result = STATE_UNKNOWN;
79 int i;
80
81 setlocale(LC_ALL, ""); 71 setlocale(LC_ALL, "");
82 setlocale(LC_NUMERIC, "C"); 72 setlocale(LC_NUMERIC, "C");
83 bindtextdomain(PACKAGE, LOCALEDIR); 73 bindtextdomain(PACKAGE, LOCALEDIR);
84 textdomain(PACKAGE); 74 textdomain(PACKAGE);
85 75
86 addresses = malloc(sizeof(char *) * max_addr);
87 addresses[0] = NULL;
88
89 /* Parse extra opts if any */ 76 /* Parse extra opts if any */
90 argv = np_extra_opts(&argc, argv, progname); 77 argv = np_extra_opts(&argc, argv, progname);
91 78
92 if (process_arguments(argc, argv) == ERROR) 79 check_ping_config_wrapper tmp_config = process_arguments(argc, argv);
80 if (tmp_config.errorcode == ERROR) {
93 usage4(_("Could not parse arguments")); 81 usage4(_("Could not parse arguments"));
82 }
83
84 const check_ping_config config = tmp_config.config;
94 85
95 /* Set signal handling and alarm */ 86 /* Set signal handling and alarm */
96 if (signal(SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) { 87 if (signal(SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
@@ -105,71 +96,90 @@ int main(int argc, char **argv) {
105 alarm(timeout_interval); 96 alarm(timeout_interval);
106#endif 97#endif
107 98
108 for (i = 0; i < n_addresses; i++) { 99 int result = STATE_UNKNOWN;
109 100 char *rawcmd = NULL;
101 for (size_t i = 0; i < config.n_addresses; i++) {
110#ifdef PING6_COMMAND 102#ifdef PING6_COMMAND
111 if (address_family != AF_INET && is_inet6_addr(addresses[i])) 103 if (address_family != AF_INET && is_inet6_addr(config.addresses[i])) {
112 rawcmd = strdup(PING6_COMMAND); 104 rawcmd = strdup(PING6_COMMAND);
113 else 105 } else {
114 rawcmd = strdup(PING_COMMAND); 106 rawcmd = strdup(PING_COMMAND);
107 }
115#else 108#else
116 rawcmd = strdup(PING_COMMAND); 109 rawcmd = strdup(PING_COMMAND);
117#endif 110#endif
118 111
119 /* does the host address of number of packets argument come first? */ 112 char *cmd = NULL;
113
114 /* does the host address of number of packets argument come first? */
120#ifdef PING_PACKETS_FIRST 115#ifdef PING_PACKETS_FIRST
121# ifdef PING_HAS_TIMEOUT 116# ifdef PING_HAS_TIMEOUT
122 xasprintf(&cmd, rawcmd, timeout_interval, max_packets, addresses[i]); 117 xasprintf(&cmd, rawcmd, timeout_interval, config.max_packets, config.addresses[i]);
123# else 118# else
124 xasprintf(&cmd, rawcmd, max_packets, addresses[i]); 119 xasprintf(&cmd, rawcmd, config.max_packets, config.addresses[i]);
125# endif 120# endif
126#else 121#else
127 xasprintf(&cmd, rawcmd, addresses[i], max_packets); 122 xasprintf(&cmd, rawcmd, config.addresses[i], config.max_packets);
128#endif 123#endif
129 124
130 if (verbose >= 2) 125 if (verbose >= 2) {
131 printf("CMD: %s\n", cmd); 126 printf("CMD: %s\n", cmd);
127 }
132 128
133 /* run the command */ 129 /* run the command */
134 this_result = run_ping(cmd, addresses[i]);
135 130
136 if (pl == UNKNOWN_PACKET_LOSS || rta < 0.0) { 131 ping_result pinged = run_ping(cmd, config.addresses[i], config.crta);
132
133 if (pinged.packet_loss == UNKNOWN_PACKET_LOSS || pinged.round_trip_average < 0.0) {
137 printf("%s\n", cmd); 134 printf("%s\n", cmd);
138 die(STATE_UNKNOWN, _("CRITICAL - Could not interpret output from ping command\n")); 135 die(STATE_UNKNOWN, _("CRITICAL - Could not interpret output from ping command\n"));
139 } 136 }
140 137
141 if (pl >= cpl || rta >= crta || rta < 0) 138 if (pinged.packet_loss >= config.cpl || pinged.round_trip_average >= config.crta ||
142 this_result = STATE_CRITICAL; 139 pinged.round_trip_average < 0) {
143 else if (pl >= wpl || rta >= wrta) 140 pinged.state = STATE_CRITICAL;
144 this_result = STATE_WARNING; 141 } else if (pinged.packet_loss >= config.wpl || pinged.round_trip_average >= config.wrta) {
145 else if (pl >= 0 && rta >= 0) 142 pinged.state = STATE_WARNING;
146 this_result = max_state(STATE_OK, this_result); 143 } else if (pinged.packet_loss >= 0 && pinged.round_trip_average >= 0) {
147 144 pinged.state = max_state(STATE_OK, pinged.state);
148 if (n_addresses > 1 && this_result != STATE_UNKNOWN) 145 }
149 die(STATE_OK, "%s is alive\n", addresses[i]); 146
150 147 if (config.n_addresses > 1 && pinged.state != STATE_UNKNOWN) {
151 if (display_html == true) 148 die(STATE_OK, "%s is alive\n", config.addresses[i]);
152 printf("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, addresses[i]); 149 }
153 if (pl == 100) 150
154 printf(_("PING %s - %sPacket loss = %d%%"), state_text(this_result), warn_text, pl); 151 if (config.display_html) {
155 else 152 printf("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, config.addresses[i]);
156 printf(_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"), state_text(this_result), warn_text, pl, rta); 153 }
157 if (display_html == true) 154 if (pinged.packet_loss == 100) {
155 printf(_("PING %s - %sPacket loss = %d%%"), state_text(pinged.state), warn_text,
156 pinged.packet_loss);
157 } else {
158 printf(_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"), state_text(pinged.state),
159 warn_text, pinged.packet_loss, pinged.round_trip_average);
160 }
161 if (config.display_html) {
158 printf("</A>"); 162 printf("</A>");
163 }
159 164
160 /* Print performance data */ 165 /* Print performance data */
161 if (pl != 100) { 166 if (pinged.packet_loss != 100) {
162 printf("|%s", 167 printf("|%s",
163 fperfdata("rta", (double)rta, "ms", wrta > 0 ? true : false, wrta, crta > 0 ? true : false, crta, true, 0, false, 0)); 168 fperfdata("rta", pinged.round_trip_average, "ms", (bool)(config.wrta > 0),
169 config.wrta, (bool)(config.crta > 0), config.crta, true, 0, false, 0));
164 } else { 170 } else {
165 printf("| rta=U;%f;%f;;", wrta, crta); 171 printf("| rta=U;%f;%f;;", config.wrta, config.crta);
166 } 172 }
167 printf(" %s\n", perfdata("pl", (long)pl, "%", wpl > 0 ? true : false, wpl, cpl > 0 ? true : false, cpl, true, 0, false, 0));
168 173
169 if (verbose >= 2) 174 printf(" %s\n",
170 printf("%f:%d%% %f:%d%%\n", wrta, wpl, crta, cpl); 175 perfdata("pl", (long)pinged.packet_loss, "%", (bool)(config.wpl > 0), config.wpl,
176 (bool)(config.cpl > 0), config.cpl, true, 0, false, 0));
177
178 if (verbose >= 2) {
179 printf("%f:%d%% %f:%d%%\n", config.wrta, config.wpl, config.crta, config.cpl);
180 }
171 181
172 result = max_state(result, this_result); 182 result = max_state(result, pinged.state);
173 free(rawcmd); 183 free(rawcmd);
174 free(cmd); 184 free(cmd);
175 } 185 }
@@ -178,11 +188,7 @@ int main(int argc, char **argv) {
178} 188}
179 189
180/* process command-line arguments */ 190/* process command-line arguments */
181int process_arguments(int argc, char **argv) { 191check_ping_config_wrapper process_arguments(int argc, char **argv) {
182 int c = 1;
183 char *ptr;
184
185 int option = 0;
186 static struct option longopts[] = {STD_LONG_OPTS, 192 static struct option longopts[] = {STD_LONG_OPTS,
187 {"packets", required_argument, 0, 'p'}, 193 {"packets", required_argument, 0, 'p'},
188 {"nohtml", no_argument, 0, 'n'}, 194 {"nohtml", no_argument, 0, 'n'},
@@ -191,23 +197,35 @@ int process_arguments(int argc, char **argv) {
191 {"use-ipv6", no_argument, 0, '6'}, 197 {"use-ipv6", no_argument, 0, '6'},
192 {0, 0, 0, 0}}; 198 {0, 0, 0, 0}};
193 199
194 if (argc < 2) 200 check_ping_config_wrapper result = {
195 return ERROR; 201 .errorcode = OK,
202 .config = check_ping_config_init(),
203 };
204
205 if (argc < 2) {
206 result.errorcode = ERROR;
207 return result;
208 }
196 209
197 for (c = 1; c < argc; c++) { 210 for (int index = 1; index < argc; index++) {
198 if (strcmp("-to", argv[c]) == 0) 211 if (strcmp("-to", argv[index]) == 0) {
199 strcpy(argv[c], "-t"); 212 strcpy(argv[index], "-t");
200 if (strcmp("-nohtml", argv[c]) == 0) 213 }
201 strcpy(argv[c], "-n"); 214 if (strcmp("-nohtml", argv[index]) == 0) {
215 strcpy(argv[index], "-n");
216 }
202 } 217 }
203 218
204 while (1) { 219 int option = 0;
205 c = getopt_long(argc, argv, "VvhnL46t:c:w:H:p:", longopts, &option); 220 size_t max_addr = MAX_ADDR_START;
221 while (true) {
222 int option_index = getopt_long(argc, argv, "VvhnL46t:c:w:H:p:", longopts, &option);
206 223
207 if (c == -1 || c == EOF) 224 if (option_index == -1 || option_index == EOF) {
208 break; 225 break;
226 }
209 227
210 switch (c) { 228 switch (option_index) {
211 case '?': /* usage */ 229 case '?': /* usage */
212 usage5(); 230 usage5();
213 case 'h': /* help */ 231 case 'h': /* help */
@@ -234,17 +252,19 @@ int process_arguments(int argc, char **argv) {
234 usage(_("IPv6 support not available\n")); 252 usage(_("IPv6 support not available\n"));
235#endif 253#endif
236 break; 254 break;
237 case 'H': /* hostname */ 255 case 'H': /* hostname */ {
238 ptr = optarg; 256 char *ptr = optarg;
239 while (1) { 257 while (true) {
240 n_addresses++; 258 result.config.n_addresses++;
241 if (n_addresses > max_addr) { 259 if (result.config.n_addresses > max_addr) {
242 max_addr *= 2; 260 max_addr *= 2;
243 addresses = realloc(addresses, sizeof(char *) * max_addr); 261 result.config.addresses =
244 if (addresses == NULL) 262 realloc(result.config.addresses, sizeof(char *) * max_addr);
263 if (result.config.addresses == NULL) {
245 die(STATE_UNKNOWN, _("Could not realloc() addresses\n")); 264 die(STATE_UNKNOWN, _("Could not realloc() addresses\n"));
265 }
246 } 266 }
247 addresses[n_addresses - 1] = ptr; 267 result.config.addresses[result.config.n_addresses - 1] = ptr;
248 if ((ptr = index(ptr, ','))) { 268 if ((ptr = index(ptr, ','))) {
249 strcpy(ptr, ""); 269 strcpy(ptr, "");
250 ptr += sizeof(char); 270 ptr += sizeof(char);
@@ -252,219 +272,302 @@ int process_arguments(int argc, char **argv) {
252 break; 272 break;
253 } 273 }
254 } 274 }
255 break; 275 } break;
256 case 'p': /* number of packets to send */ 276 case 'p': /* number of packets to send */
257 if (is_intnonneg(optarg)) 277 if (is_intnonneg(optarg)) {
258 max_packets = atoi(optarg); 278 result.config.max_packets = atoi(optarg);
259 else 279 } else {
260 usage2(_("<max_packets> (%s) must be a non-negative number\n"), optarg); 280 usage2(_("<max_packets> (%s) must be a non-negative number\n"), optarg);
281 }
261 break; 282 break;
262 case 'n': /* no HTML */ 283 case 'n': /* no HTML */
263 display_html = false; 284 result.config.display_html = false;
264 break; 285 break;
265 case 'L': /* show HTML */ 286 case 'L': /* show HTML */
266 display_html = true; 287 result.config.display_html = true;
267 break; 288 break;
268 case 'c': 289 case 'c':
269 get_threshold(optarg, &crta, &cpl); 290 get_threshold(optarg, &result.config.crta, &result.config.cpl);
270 break; 291 break;
271 case 'w': 292 case 'w':
272 get_threshold(optarg, &wrta, &wpl); 293 get_threshold(optarg, &result.config.wrta, &result.config.wpl);
273 break; 294 break;
274 } 295 }
275 } 296 }
276 297
277 c = optind; 298 int arg_counter = optind;
278 if (c == argc) 299 if (arg_counter == argc) {
279 return validate_arguments(); 300 return validate_arguments(result);
301 }
280 302
281 if (addresses[0] == NULL) { 303 if (result.config.addresses[0] == NULL) {
282 if (!is_host(argv[c])) { 304 if (!is_host(argv[arg_counter])) {
283 usage2(_("Invalid hostname/address"), argv[c]); 305 usage2(_("Invalid hostname/address"), argv[arg_counter]);
284 } else { 306 } else {
285 addresses[0] = argv[c++]; 307 result.config.addresses[0] = argv[arg_counter++];
286 n_addresses++; 308 result.config.n_addresses++;
287 if (c == argc) 309 if (arg_counter == argc) {
288 return validate_arguments(); 310 return validate_arguments(result);
311 }
289 } 312 }
290 } 313 }
291 314
292 if (wpl == UNKNOWN_PACKET_LOSS) { 315 if (result.config.wpl == UNKNOWN_PACKET_LOSS) {
293 if (!is_intpercent(argv[c])) { 316 if (!is_intpercent(argv[arg_counter])) {
294 printf(_("<wpl> (%s) must be an integer percentage\n"), argv[c]); 317 printf(_("<wpl> (%s) must be an integer percentage\n"), argv[arg_counter]);
295 return ERROR; 318 result.errorcode = ERROR;
296 } else { 319 return result;
297 wpl = atoi(argv[c++]); 320 }
298 if (c == argc) 321 result.config.wpl = atoi(argv[arg_counter++]);
299 return validate_arguments(); 322 if (arg_counter == argc) {
323 return validate_arguments(result);
300 } 324 }
301 } 325 }
302 326
303 if (cpl == UNKNOWN_PACKET_LOSS) { 327 if (result.config.cpl == UNKNOWN_PACKET_LOSS) {
304 if (!is_intpercent(argv[c])) { 328 if (!is_intpercent(argv[arg_counter])) {
305 printf(_("<cpl> (%s) must be an integer percentage\n"), argv[c]); 329 printf(_("<cpl> (%s) must be an integer percentage\n"), argv[arg_counter]);
306 return ERROR; 330 result.errorcode = ERROR;
307 } else { 331 return result;
308 cpl = atoi(argv[c++]); 332 }
309 if (c == argc) 333 result.config.cpl = atoi(argv[arg_counter++]);
310 return validate_arguments(); 334 if (arg_counter == argc) {
335 return validate_arguments(result);
311 } 336 }
312 } 337 }
313 338
314 if (wrta < 0.0) { 339 if (result.config.wrta < 0.0) {
315 if (is_negative(argv[c])) { 340 if (is_negative(argv[arg_counter])) {
316 printf(_("<wrta> (%s) must be a non-negative number\n"), argv[c]); 341 printf(_("<wrta> (%s) must be a non-negative number\n"), argv[arg_counter]);
317 return ERROR; 342 result.errorcode = ERROR;
318 } else { 343 return result;
319 wrta = atof(argv[c++]); 344 }
320 if (c == argc) 345 result.config.wrta = atof(argv[arg_counter++]);
321 return validate_arguments(); 346 if (arg_counter == argc) {
347 return validate_arguments(result);
322 } 348 }
323 } 349 }
324 350
325 if (crta < 0.0) { 351 if (result.config.crta < 0.0) {
326 if (is_negative(argv[c])) { 352 if (is_negative(argv[arg_counter])) {
327 printf(_("<crta> (%s) must be a non-negative number\n"), argv[c]); 353 printf(_("<crta> (%s) must be a non-negative number\n"), argv[arg_counter]);
328 return ERROR; 354 result.errorcode = ERROR;
329 } else { 355 return result;
330 crta = atof(argv[c++]); 356 }
331 if (c == argc) 357 result.config.crta = atof(argv[arg_counter++]);
332 return validate_arguments(); 358 if (arg_counter == argc) {
359 return validate_arguments(result);
333 } 360 }
334 } 361 }
335 362
336 if (max_packets == -1) { 363 if (result.config.max_packets == -1) {
337 if (is_intnonneg(argv[c])) { 364 if (is_intnonneg(argv[arg_counter])) {
338 max_packets = atoi(argv[c++]); 365 result.config.max_packets = atoi(argv[arg_counter++]);
339 } else { 366 } else {
340 printf(_("<max_packets> (%s) must be a non-negative number\n"), argv[c]); 367 printf(_("<max_packets> (%s) must be a non-negative number\n"), argv[arg_counter]);
341 return ERROR; 368 result.errorcode = ERROR;
369 return result;
342 } 370 }
343 } 371 }
344 372
345 return validate_arguments(); 373 return validate_arguments(result);
346} 374}
347 375
348int get_threshold(char *arg, float *trta, int *tpl) { 376int get_threshold(char *arg, double *trta, int *tpl) {
349 if (is_intnonneg(arg) && sscanf(arg, "%f", trta) == 1) 377 if (is_intnonneg(arg) && sscanf(arg, "%lf", trta) == 1) {
350 return OK; 378 return OK;
351 else if (strpbrk(arg, ",:") && strstr(arg, "%") && sscanf(arg, "%f%*[:,]%d%%", trta, tpl) == 2) 379 }
380
381 if (strpbrk(arg, ",:") && strstr(arg, "%") && sscanf(arg, "%lf%*[:,]%d%%", trta, tpl) == 2) {
352 return OK; 382 return OK;
353 else if (strstr(arg, "%") && sscanf(arg, "%d%%", tpl) == 1) 383 }
384
385 if (strstr(arg, "%") && sscanf(arg, "%d%%", tpl) == 1) {
354 return OK; 386 return OK;
387 }
355 388
356 usage2(_("%s: Warning threshold must be integer or percentage!\n\n"), arg); 389 usage2(_("%s: Warning threshold must be integer or percentage!\n\n"), arg);
357 return STATE_UNKNOWN; 390 return STATE_UNKNOWN;
358} 391}
359 392
360int validate_arguments() { 393check_ping_config_wrapper validate_arguments(check_ping_config_wrapper config_wrapper) {
361 float max_seconds; 394 if (config_wrapper.config.wrta < 0.0) {
362 int i;
363
364 if (wrta < 0.0) {
365 printf(_("<wrta> was not set\n")); 395 printf(_("<wrta> was not set\n"));
366 return ERROR; 396 config_wrapper.errorcode = ERROR;
367 } else if (crta < 0.0) { 397 return config_wrapper;
398 }
399
400 if (config_wrapper.config.crta < 0.0) {
368 printf(_("<crta> was not set\n")); 401 printf(_("<crta> was not set\n"));
369 return ERROR; 402 config_wrapper.errorcode = ERROR;
370 } else if (wpl == UNKNOWN_PACKET_LOSS) { 403 return config_wrapper;
404 }
405
406 if (config_wrapper.config.wpl == UNKNOWN_PACKET_LOSS) {
371 printf(_("<wpl> was not set\n")); 407 printf(_("<wpl> was not set\n"));
372 return ERROR; 408 config_wrapper.errorcode = ERROR;
373 } else if (cpl == UNKNOWN_PACKET_LOSS) { 409 return config_wrapper;
410 }
411
412 if (config_wrapper.config.cpl == UNKNOWN_PACKET_LOSS) {
374 printf(_("<cpl> was not set\n")); 413 printf(_("<cpl> was not set\n"));
375 return ERROR; 414 config_wrapper.errorcode = ERROR;
376 } else if (wrta > crta) { 415 return config_wrapper;
377 printf(_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), wrta, crta); 416 }
378 return ERROR; 417
379 } else if (wpl > cpl) { 418 if (config_wrapper.config.wrta > config_wrapper.config.crta) {
380 printf(_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), wpl, cpl); 419 printf(_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), config_wrapper.config.wrta,
381 return ERROR; 420 config_wrapper.config.crta);
421 config_wrapper.errorcode = ERROR;
422 return config_wrapper;
382 } 423 }
383 424
384 if (max_packets == -1) 425 if (config_wrapper.config.wpl > config_wrapper.config.cpl) {
385 max_packets = DEFAULT_MAX_PACKETS; 426 printf(_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), config_wrapper.config.wpl,
427 config_wrapper.config.cpl);
428 config_wrapper.errorcode = ERROR;
429 return config_wrapper;
430 }
386 431
387 max_seconds = crta / 1000.0 * max_packets + max_packets; 432 if (config_wrapper.config.max_packets == -1) {
388 if (max_seconds > timeout_interval) 433 config_wrapper.config.max_packets = DEFAULT_MAX_PACKETS;
389 timeout_interval = (int)max_seconds; 434 }
390 435
391 for (i = 0; i < n_addresses; i++) { 436 double max_seconds = (config_wrapper.config.crta / 1000.0 * config_wrapper.config.max_packets) +
392 if (!is_host(addresses[i])) 437 config_wrapper.config.max_packets;
393 usage2(_("Invalid hostname/address"), addresses[i]); 438 if (max_seconds > timeout_interval) {
439 timeout_interval = (unsigned int)max_seconds;
440 }
441
442 for (size_t i = 0; i < config_wrapper.config.n_addresses; i++) {
443 if (!is_host(config_wrapper.config.addresses[i])) {
444 usage2(_("Invalid hostname/address"), config_wrapper.config.addresses[i]);
445 }
394 } 446 }
395 447
396 if (n_addresses == 0) { 448 if (config_wrapper.config.n_addresses == 0) {
397 usage(_("You must specify a server address or host name")); 449 usage(_("You must specify a server address or host name"));
398 } 450 }
399 451
400 return OK; 452 return config_wrapper;
401} 453}
402 454
403int run_ping(const char *cmd, const char *addr) { 455ping_result run_ping(const char *cmd, const char *addr, double crta) {
404 char buf[MAX_INPUT_BUFFER]; 456 if ((child_process = spopen(cmd)) == NULL) {
405 int result = STATE_UNKNOWN;
406 int match;
407
408 if ((child_process = spopen(cmd)) == NULL)
409 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd); 457 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd);
458 }
410 459
411 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r"); 460 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
412 if (child_stderr == NULL) 461 if (child_stderr == NULL) {
413 printf(_("Cannot open stderr for %s\n"), cmd); 462 printf(_("Cannot open stderr for %s\n"), cmd);
463 }
414 464
415 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_process)) { 465 char buf[MAX_INPUT_BUFFER];
466 ping_result result = {
467 .state = STATE_UNKNOWN,
468 .packet_loss = UNKNOWN_PACKET_LOSS,
469 .round_trip_average = UNKNOWN_TRIP_TIME,
470 };
416 471
417 if (verbose >= 3) 472 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_process)) {
473 if (verbose >= 3) {
418 printf("Output: %s", buf); 474 printf("Output: %s", buf);
475 }
419 476
420 result = max_state(result, error_scan(buf, addr)); 477 result.state = max_state(result.state, error_scan(buf, addr));
421 478
422 /* get the percent loss statistics */ 479 /* get the percent loss statistics */
423 match = 0; 480 int match = 0;
424 if ((sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss%n", &pl, &match) && match) || 481 if ((sscanf(
425 (sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet loss%n", &pl, &match) && match) || 482 buf,
426 (sscanf(buf, "%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n", &pl, &match) && match) || 483 "%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss%n",
427 (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% packet loss%n", &pl, &match) && match) || 484 &result.packet_loss, &match) == 1 &&
428 (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% loss, time%n", &pl, &match) && match) || 485 match) ||
429 (sscanf(buf, "%*d packets transmitted, %*d received, %d%% loss, time%n", &pl, &match) && match) || 486 (sscanf(buf,
430 (sscanf(buf, "%*d packets transmitted, %*d received, %d%% packet loss, time%n", &pl, &match) && match) || 487 "%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet "
431 (sscanf(buf, "%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n", &pl, &match) && match) || 488 "loss%n",
432 (sscanf(buf, "%*d packets transmitted %*d received, +%*d errors, %d%% packet loss%n", &pl, &match) && match) || 489 &result.packet_loss, &match) == 1 &&
433 (sscanf(buf, "%*[^(](%d%% %*[^)])%n", &pl, &match) && match)) 490 match) ||
491 (sscanf(buf,
492 "%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n",
493 &result.packet_loss, &match) == 1 &&
494 match) ||
495 (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% packet loss%n",
496 &result.packet_loss, &match) == 1 &&
497 match) ||
498 (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% loss, time%n",
499 &result.packet_loss, &match) == 1 &&
500 match) ||
501 (sscanf(buf, "%*d packets transmitted, %*d received, %d%% loss, time%n",
502 &result.packet_loss, &match) == 1 &&
503 match) ||
504 (sscanf(buf, "%*d packets transmitted, %*d received, %d%% packet loss, time%n",
505 &result.packet_loss, &match) == 1 &&
506 match) == 1 ||
507 (sscanf(buf, "%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n",
508 &result.packet_loss, &match) == 1 &&
509 match) ||
510 (sscanf(buf, "%*d packets transmitted %*d received, +%*d errors, %d%% packet loss%n",
511 &result.packet_loss, &match) == 1 &&
512 match) ||
513 (sscanf(buf, "%*[^(](%d%% %*[^)])%n", &result.packet_loss, &match) == 1 && match)) {
434 continue; 514 continue;
515 }
435 516
436 /* get the round trip average */ 517 /* get the round trip average */
437 else if ((sscanf(buf, "round-trip min/avg/max = %*f/%f/%*f%n", &rta, &match) && match) || 518 if ((sscanf(buf, "round-trip min/avg/max = %*f/%lf/%*f%n", &result.round_trip_average,
438 (sscanf(buf, "round-trip min/avg/max/mdev = %*f/%f/%*f/%*f%n", &rta, &match) && match) || 519 &match) == 1 &&
439 (sscanf(buf, "round-trip min/avg/max/sdev = %*f/%f/%*f/%*f%n", &rta, &match) && match) || 520 match) ||
440 (sscanf(buf, "round-trip min/avg/max/stddev = %*f/%f/%*f/%*f%n", &rta, &match) && match) || 521 (sscanf(buf, "round-trip min/avg/max/mdev = %*f/%lf/%*f/%*f%n",
441 (sscanf(buf, "round-trip min/avg/max/std-dev = %*f/%f/%*f/%*f%n", &rta, &match) && match) || 522 &result.round_trip_average, &match) == 1 &&
442 (sscanf(buf, "round-trip (ms) min/avg/max = %*f/%f/%*f%n", &rta, &match) && match) || 523 match) ||
443 (sscanf(buf, "round-trip (ms) min/avg/max/stddev = %*f/%f/%*f/%*f%n", &rta, &match) && match) || 524 (sscanf(buf, "round-trip min/avg/max/sdev = %*f/%lf/%*f/%*f%n",
444 (sscanf(buf, "rtt min/avg/max/mdev = %*f/%f/%*f/%*f ms%n", &rta, &match) && match) || 525 &result.round_trip_average, &match) == 1 &&
445 (sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %fms%n", &rta, &match) && match)) 526 match) ||
527 (sscanf(buf, "round-trip min/avg/max/stddev = %*f/%lf/%*f/%*f%n",
528 &result.round_trip_average, &match) == 1 &&
529 match) ||
530 (sscanf(buf, "round-trip min/avg/max/std-dev = %*f/%lf/%*f/%*f%n",
531 &result.round_trip_average, &match) == 1 &&
532 match) ||
533 (sscanf(buf, "round-trip (ms) min/avg/max = %*f/%lf/%*f%n", &result.round_trip_average,
534 &match) == 1 &&
535 match) ||
536 (sscanf(buf, "round-trip (ms) min/avg/max/stddev = %*f/%lf/%*f/%*f%n",
537 &result.round_trip_average, &match) == 1 &&
538 match) ||
539 (sscanf(buf, "rtt min/avg/max/mdev = %*f/%lf/%*f/%*f ms%n", &result.round_trip_average,
540 &match) == 1 &&
541 match) ||
542 (sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %lfms%n",
543 &result.round_trip_average, &match) == 1 &&
544 match)) {
446 continue; 545 continue;
546 }
447 } 547 }
448 548
449 /* this is needed because there is no rta if all packets are lost */ 549 /* this is needed because there is no rta if all packets are lost */
450 if (pl == 100) 550 if (result.packet_loss == 100) {
451 rta = crta; 551 result.round_trip_average = crta;
552 }
452 553
453 /* check stderr, setting at least WARNING if there is output here */ 554 /* check stderr, setting at least WARNING if there is output here */
454 /* Add warning into warn_text */ 555 /* Add warning into warn_text */
455 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_stderr)) { 556 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_stderr)) {
456 if (!strstr(buf, "WARNING - no SO_TIMESTAMP support, falling back to SIOCGSTAMP") && !strstr(buf, "Warning: time of day goes back") 557 if (!strstr(buf, "WARNING - no SO_TIMESTAMP support, falling back to SIOCGSTAMP") &&
558 !strstr(buf, "Warning: time of day goes back")
457 559
458 ) { 560 ) {
459 if (verbose >= 3) { 561 if (verbose >= 3) {
460 printf("Got stderr: %s", buf); 562 printf("Got stderr: %s", buf);
461 } 563 }
462 if ((result = error_scan(buf, addr)) == STATE_OK) { 564 if ((result.state = error_scan(buf, addr)) == STATE_OK) {
463 result = STATE_WARNING; 565 result.state = STATE_WARNING;
464 if (warn_text == NULL) { 566 if (warn_text == NULL) {
465 warn_text = strdup(_("System call sent warnings to stderr ")); 567 warn_text = strdup(_("System call sent warnings to stderr "));
466 } else { 568 } else {
467 xasprintf(&warn_text, "%s %s", warn_text, _("System call sent warnings to stderr ")); 569 xasprintf(&warn_text, "%s %s", warn_text,
570 _("System call sent warnings to stderr "));
468 } 571 }
469 } 572 }
470 } 573 }
@@ -474,43 +577,48 @@ int run_ping(const char *cmd, const char *addr) {
474 577
475 spclose(child_process); 578 spclose(child_process);
476 579
477 if (warn_text == NULL) 580 if (warn_text == NULL) {
478 warn_text = strdup(""); 581 warn_text = strdup("");
582 }
479 583
480 return result; 584 return result;
481} 585}
482 586
483int error_scan(char buf[MAX_INPUT_BUFFER], const char *addr) { 587mp_state_enum error_scan(char buf[MAX_INPUT_BUFFER], const char *addr) {
484 if (strstr(buf, "Network is unreachable") || strstr(buf, "Destination Net Unreachable") || strstr(buf, "No route")) 588 if (strstr(buf, "Network is unreachable") || strstr(buf, "Destination Net Unreachable") ||
589 strstr(buf, "No route")) {
485 die(STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr); 590 die(STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr);
486 else if (strstr(buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable")) 591 } else if (strstr(buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable")) {
487 die(STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr); 592 die(STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr);
488 else if (strstr(buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable")) 593 } else if (strstr(buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable")) {
489 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr); 594 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr);
490 else if (strstr(buf, "Destination Protocol Unreachable")) 595 } else if (strstr(buf, "Destination Protocol Unreachable")) {
491 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr); 596 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr);
492 else if (strstr(buf, "Destination Net Prohibited")) 597 } else if (strstr(buf, "Destination Net Prohibited")) {
493 die(STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr); 598 die(STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr);
494 else if (strstr(buf, "Destination Host Prohibited")) 599 } else if (strstr(buf, "Destination Host Prohibited")) {
495 die(STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr); 600 die(STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr);
496 else if (strstr(buf, "Packet filtered") || strstr(buf, "Administratively prohibited")) 601 } else if (strstr(buf, "Packet filtered") || strstr(buf, "Administratively prohibited")) {
497 die(STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr); 602 die(STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr);
498 else if (strstr(buf, "unknown host")) 603 } else if (strstr(buf, "unknown host")) {
499 die(STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr); 604 die(STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr);
500 else if (strstr(buf, "Time to live exceeded") || strstr(buf, "Time exceeded")) 605 } else if (strstr(buf, "Time to live exceeded") || strstr(buf, "Time exceeded")) {
501 die(STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr); 606 die(STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr);
502 else if (strstr(buf, "Destination unreachable: ")) 607 } else if (strstr(buf, "Destination unreachable: ")) {
503 die(STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr); 608 die(STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr);
609 }
504 610
505 if (strstr(buf, "(DUP!)") || strstr(buf, "DUPLICATES FOUND")) { 611 if (strstr(buf, "(DUP!)") || strstr(buf, "DUPLICATES FOUND")) {
506 if (warn_text == NULL) 612 if (warn_text == NULL) {
507 warn_text = strdup(_(WARN_DUPLICATES)); 613 warn_text = strdup(_(WARN_DUPLICATES));
508 else if (!strstr(warn_text, _(WARN_DUPLICATES)) && xasprintf(&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1) 614 } else if (!strstr(warn_text, _(WARN_DUPLICATES)) &&
615 xasprintf(&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1) {
509 die(STATE_UNKNOWN, _("Unable to realloc warn_text\n")); 616 die(STATE_UNKNOWN, _("Unable to realloc warn_text\n"));
510 return (STATE_WARNING); 617 }
618 return STATE_WARNING;
511 } 619 }
512 620
513 return (STATE_OK); 621 return STATE_OK;
514} 622}
515 623
516void print_help(void) { 624void print_help(void) {
@@ -550,10 +658,10 @@ void print_help(void) {
550 printf("%s\n", _("percentage of packet loss to trigger an alarm state.")); 658 printf("%s\n", _("percentage of packet loss to trigger an alarm state."));
551 659
552 printf("\n"); 660 printf("\n");
553 printf("%s\n", _("This plugin uses the ping command to probe the specified host for packet loss")); 661 printf("%s\n",
554 printf("%s\n", _("(percentage) and round trip average (milliseconds). It can produce HTML output")); 662 _("This plugin uses the ping command to probe the specified host for packet loss"));
555 printf("%s\n", _("linking to a traceroute CGI contributed by Ian Cass. The CGI can be found in")); 663 printf("%s\n",
556 printf("%s\n", _("the contrib area of the downloads section at http://www.nagios.org/")); 664 _("(percentage) and round trip average (milliseconds). It can produce HTML output."));
557 665
558 printf(UT_SUPPORT); 666 printf(UT_SUPPORT);
559} 667}
diff --git a/plugins/check_ping.d/config.h b/plugins/check_ping.d/config.h
new file mode 100644
index 00000000..eb2735a7
--- /dev/null
+++ b/plugins/check_ping.d/config.h
@@ -0,0 +1,46 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#include <stdlib.h>
6
7enum {
8 UNKNOWN_PACKET_LOSS = 200, /* 200% */
9 DEFAULT_MAX_PACKETS = 5 /* default no. of ICMP ECHO packets */
10};
11
12#define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */
13
14#define MAX_ADDR_START 1
15
16typedef struct {
17 bool display_html;
18 int max_packets;
19
20 char **addresses;
21 size_t n_addresses;
22
23 int wpl;
24 int cpl;
25 double wrta;
26 double crta;
27} check_ping_config;
28
29check_ping_config check_ping_config_init() {
30 check_ping_config tmp = {
31 .display_html = false,
32 .max_packets = -1,
33
34 .addresses = NULL,
35 .n_addresses = 0,
36
37 .wpl = UNKNOWN_PACKET_LOSS,
38 .cpl = UNKNOWN_PACKET_LOSS,
39 .wrta = UNKNOWN_TRIP_TIME,
40 .crta = UNKNOWN_TRIP_TIME,
41 };
42
43 tmp.addresses = calloc(MAX_ADDR_START, sizeof(char *));
44 tmp.addresses[0] = NULL;
45 return tmp;
46}
diff --git a/plugins/check_procs.c b/plugins/check_procs.c
index 1d78ccee..ae6e9c23 100644
--- a/plugins/check_procs.c
+++ b/plugins/check_procs.c
@@ -1,41 +1,41 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_procs plugin 3 * Monitoring check_procs plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2024 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_procs plugin 10 * This file contains the check_procs plugin
11* 11 *
12* Checks all processes and generates WARNING or CRITICAL states if the 12 * Checks all processes and generates WARNING or CRITICAL states if the
13* specified metric is outside the required threshold ranges. The metric 13 * specified metric is outside the required threshold ranges. The metric
14* defaults to number of processes. Search filters can be applied to limit 14 * defaults to number of processes. Search filters can be applied to limit
15* the processes to check. 15 * the processes to check.
16* 16 *
17* The parent process, check_procs itself and any child process of 17 * The parent process, check_procs itself and any child process of
18* check_procs (ps) are excluded from any checks to prevent false positives. 18 * check_procs (ps) are excluded from any checks to prevent false positives.
19* 19 *
20* 20 *
21* This program is free software: you can redistribute it and/or modify 21 * This program is free software: you can redistribute it and/or modify
22* it under the terms of the GNU General Public License as published by 22 * it under the terms of the GNU General Public License as published by
23* the Free Software Foundation, either version 3 of the License, or 23 * the Free Software Foundation, either version 3 of the License, or
24* (at your option) any later version. 24 * (at your option) any later version.
25* 25 *
26* This program is distributed in the hope that it will be useful, 26 * This program is distributed in the hope that it will be useful,
27* but WITHOUT ANY WARRANTY; without even the implied warranty of 27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29* GNU General Public License for more details. 29 * GNU General Public License for more details.
30* 30 *
31* You should have received a copy of the GNU General Public License 31 * You should have received a copy of the GNU General Public License
32* along with this program. If not, see <http://www.gnu.org/licenses/>. 32 * along with this program. If not, see <http://www.gnu.org/licenses/>.
33* 33 *
34* 34 *
35*****************************************************************************/ 35 *****************************************************************************/
36 36
37const char *progname = "check_procs"; 37const char *progname = "check_procs";
38const char *program_name = "check_procs"; /* Required for coreutils libs */ 38const char *program_name = "check_procs"; /* Required for coreutils libs */
39const char *copyright = "2000-2024"; 39const char *copyright = "2000-2024";
40const char *email = "devel@monitoring-plugins.org"; 40const char *email = "devel@monitoring-plugins.org";
41 41
@@ -43,313 +43,297 @@ const char *email = "devel@monitoring-plugins.org";
43#include "utils.h" 43#include "utils.h"
44#include "utils_cmd.h" 44#include "utils_cmd.h"
45#include "regex.h" 45#include "regex.h"
46#include "states.h"
47#include "check_procs.d/config.h"
46 48
47#include <pwd.h> 49#include <pwd.h>
48#include <errno.h> 50#include <errno.h>
49 51
50#ifdef HAVE_SYS_STAT_H 52#ifdef HAVE_SYS_STAT_H
51#include <sys/stat.h> 53# include <sys/stat.h>
52#endif 54#endif
53 55
54static int process_arguments (int /*argc*/, char ** /*argv*/); 56typedef struct {
55static int validate_arguments (void); 57 int errorcode;
56static int convert_to_seconds (char * /*etime*/); 58 check_procs_config config;
57static void print_help (void); 59} check_procs_config_wrapper;
58void print_usage (void); 60static check_procs_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
59 61static check_procs_config_wrapper validate_arguments(check_procs_config_wrapper /*config_wrapper*/);
60static char *warning_range = NULL; 62
61static char *critical_range = NULL; 63static int convert_to_seconds(char * /*etime*/, enum metric /*metric*/);
62static thresholds *procs_thresholds = NULL; 64static void print_help(void);
63 65void print_usage(void);
64static int options = 0; /* bitmask of filter criteria to test against */ 66
65#define ALL 1 67#define ALL 1
66#define STAT 2 68#define STAT 2
67#define PPID 4 69#define PPID 4
68#define USER 8 70#define USER 8
69#define PROG 16 71#define PROG 16
70#define ARGS 32 72#define ARGS 32
71#define VSZ 64 73#define VSZ 64
72#define RSS 128 74#define RSS 128
73#define PCPU 256 75#define PCPU 256
74#define ELAPSED 512 76#define ELAPSED 512
75#define EREG_ARGS 1024 77#define EREG_ARGS 1024
76#define EXCLUDE_PROGS 2048 78#define EXCLUDE_PROGS 2048
77 79
78#define KTHREAD_PARENT "kthreadd" /* the parent process of kernel threads: 80#define KTHREAD_PARENT \
79 ppid of procs are compared to pid of this proc*/ 81 "kthreadd" /* the parent process of kernel threads: \
80 82 ppid of procs are compared to pid of this proc*/
81/* Different metrics */
82char *metric_name;
83enum metric {
84 METRIC_PROCS,
85 METRIC_VSZ,
86 METRIC_RSS,
87 METRIC_CPU,
88 METRIC_ELAPSED
89};
90enum metric metric = METRIC_PROCS;
91 83
92static int verbose = 0; 84static int verbose = 0;
93static int uid; 85
94static pid_t ppid; 86static int stat_exe(const pid_t pid, struct stat *buf) {
95static int vsz;
96static int rss;
97static float pcpu;
98static char *statopts;
99static char *prog;
100static char *exclude_progs;
101static char **exclude_progs_arr = NULL;
102static char exclude_progs_counter = 0;
103static char *args;
104static char *input_filename = NULL;
105static regex_t re_args;
106static char *fmt;
107static char *fails;
108static char tmp[MAX_INPUT_BUFFER];
109static int kthread_filter = 0;
110static int usepid = 0; /* whether to test for pid or /proc/pid/exe */
111
112static int
113stat_exe (const pid_t pid, struct stat *buf) {
114 char *path; 87 char *path;
115 int ret;
116 xasprintf(&path, "/proc/%d/exe", pid); 88 xasprintf(&path, "/proc/%d/exe", pid);
117 ret = stat(path, buf); 89 int ret = stat(path, buf);
118 free(path); 90 free(path);
119 return ret; 91 return ret;
120} 92}
121 93
122 94int main(int argc, char **argv) {
123int 95 setlocale(LC_ALL, "");
124main (int argc, char **argv)
125{
126 char *input_buffer;
127 char *input_line;
128 char *procprog;
129
130 pid_t mypid = 0;
131 pid_t myppid = 0;
132 struct stat statbuf;
133 dev_t mydev = 0;
134 ino_t myino = 0;
135 int procuid = 0;
136 pid_t procpid = 0;
137 pid_t procppid = 0;
138 pid_t kthread_ppid = 0;
139 int procvsz = 0;
140 int procrss = 0;
141 int procseconds = 0;
142 float procpcpu = 0;
143 char procstat[8];
144 char procetime[MAX_INPUT_BUFFER] = { '\0' };
145 char *procargs;
146
147 const char *zombie = "Z";
148
149 int resultsum = 0; /* bitmask of the filter criteria met by a process */
150 int found = 0; /* counter for number of lines returned in `ps` output */
151 int procs = 0; /* counter for number of processes meeting filter criteria */
152 int pos; /* number of spaces before 'args' in `ps` output */
153 int cols; /* number of columns in ps output */
154 int expected_cols = PS_COLS - 1;
155 int warn = 0; /* number of processes in warn state */
156 int crit = 0; /* number of processes in crit state */
157 int i = 0;
158 int result = STATE_UNKNOWN;
159 int ret = 0;
160 output chld_out, chld_err;
161
162 setlocale (LC_ALL, "");
163 bindtextdomain (PACKAGE, LOCALEDIR);
164 textdomain (PACKAGE);
165 setlocale(LC_NUMERIC, "POSIX"); 96 setlocale(LC_NUMERIC, "POSIX");
166 97 bindtextdomain(PACKAGE, LOCALEDIR);
167 input_buffer = malloc (MAX_INPUT_BUFFER); 98 textdomain(PACKAGE);
168 procprog = malloc (MAX_INPUT_BUFFER);
169
170 xasprintf (&metric_name, "PROCS");
171 metric = METRIC_PROCS;
172 99
173 /* Parse extra opts if any */ 100 /* Parse extra opts if any */
174 argv=np_extra_opts (&argc, argv, progname); 101 argv = np_extra_opts(&argc, argv, progname);
102
103 check_procs_config_wrapper tmp_config = process_arguments(argc, argv);
104 if (tmp_config.errorcode == ERROR) {
105 usage4(_("Could not parse arguments"));
106 }
175 107
176 if (process_arguments (argc, argv) == ERROR) 108 check_procs_config config = tmp_config.config;
177 usage4 (_("Could not parse arguments"));
178 109
179 /* find ourself */ 110 /* find ourself */
180 mypid = getpid(); 111 pid_t mypid = getpid();
181 myppid = getppid(); 112 pid_t myppid = getppid();
182 if (usepid || stat_exe(mypid, &statbuf) == -1) { 113 dev_t mydev = 0;
114 ino_t myino = 0;
115 struct stat statbuf;
116 if (config.usepid || stat_exe(mypid, &statbuf) == -1) {
183 /* usepid might have been set by -T */ 117 /* usepid might have been set by -T */
184 usepid = 1; 118 config.usepid = true;
185 } else { 119 } else {
186 usepid = 0; 120 config.usepid = false;
187 mydev = statbuf.st_dev; 121 mydev = statbuf.st_dev;
188 myino = statbuf.st_ino; 122 myino = statbuf.st_ino;
189 } 123 }
190 124
191 /* Set signal handling and alarm timeout */ 125 /* Set signal handling and alarm timeout */
192 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 126 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
193 die (STATE_UNKNOWN, _("Cannot catch SIGALRM")); 127 die(STATE_UNKNOWN, _("Cannot catch SIGALRM"));
194 } 128 }
195 (void) alarm ((unsigned) timeout_interval); 129 (void)alarm(timeout_interval);
196 130
197 if (verbose >= 2) 131 if (verbose >= 2) {
198 printf (_("CMD: %s\n"), PS_COMMAND); 132 printf(_("CMD: %s\n"), PS_COMMAND);
133 }
199 134
200 if (input_filename == NULL) { 135 output chld_out;
201 result = cmd_run( PS_COMMAND, &chld_out, &chld_err, 0); 136 output chld_err;
137 mp_state_enum result = STATE_UNKNOWN;
138 if (config.input_filename == NULL) {
139 result = cmd_run(PS_COMMAND, &chld_out, &chld_err, 0);
202 if (chld_err.lines > 0) { 140 if (chld_err.lines > 0) {
203 printf ("%s: %s", _("System call sent warnings to stderr"), chld_err.line[0]); 141 printf("%s: %s", _("System call sent warnings to stderr"), chld_err.line[0]);
204 exit(STATE_WARNING); 142 exit(STATE_WARNING);
205 } 143 }
206 } else { 144 } else {
207 result = cmd_file_read( input_filename, &chld_out, 0); 145 result = cmd_file_read(config.input_filename, &chld_out, 0);
208 } 146 }
209 147
148 int pos; /* number of spaces before 'args' in `ps` output */
149 uid_t procuid = 0;
150 pid_t procpid = 0;
151 pid_t procppid = 0;
152 pid_t kthread_ppid = 0;
153 int warn = 0; /* number of processes in warn state */
154 int crit = 0; /* number of processes in crit state */
155 int procvsz = 0;
156 int procrss = 0;
157 int procseconds = 0;
158 float procpcpu = 0;
159 char procstat[8];
160 char procetime[MAX_INPUT_BUFFER] = {'\0'};
161 int resultsum = 0; /* bitmask of the filter criteria met by a process */
162 int found = 0; /* counter for number of lines returned in `ps` output */
163 int procs = 0; /* counter for number of processes meeting filter criteria */
164 char *input_buffer = malloc(MAX_INPUT_BUFFER);
165 char *procprog = malloc(MAX_INPUT_BUFFER);
166 const int expected_cols = PS_COLS - 1;
167
210 /* flush first line: j starts at 1 */ 168 /* flush first line: j starts at 1 */
211 for (size_t j = 1; j < chld_out.lines; j++) { 169 for (size_t j = 1; j < chld_out.lines; j++) {
212 input_line = chld_out.line[j]; 170 char *input_line = chld_out.line[j];
213 171
214 if (verbose >= 3) 172 if (verbose >= 3) {
215 printf ("%s", input_line); 173 printf("%s", input_line);
174 }
216 175
217 strcpy (procprog, ""); 176 strcpy(procprog, "");
218 xasprintf (&procargs, "%s", ""); 177 char *procargs;
178 xasprintf(&procargs, "%s", "");
219 179
220 cols = sscanf (input_line, PS_FORMAT, PS_VARLIST); 180 /* number of columns in ps output */
181 int cols = sscanf(input_line, PS_FORMAT, PS_VARLIST);
221 182
222 /* Zombie processes do not give a procprog command */ 183 /* Zombie processes do not give a procprog command */
223 if ( cols < expected_cols && strstr(procstat, zombie) ) { 184 const char *zombie = "Z";
185 if (cols < expected_cols && strstr(procstat, zombie)) {
224 cols = expected_cols; 186 cols = expected_cols;
225 } 187 }
226 if ( cols >= expected_cols ) { 188 if (cols >= expected_cols) {
227 resultsum = 0; 189 resultsum = 0;
228 xasprintf (&procargs, "%s", input_line + pos); 190 xasprintf(&procargs, "%s", input_line + pos);
229 strip (procargs); 191 strip(procargs);
230 192
231 /* Some ps return full pathname for command. This removes path */ 193 /* Some ps return full pathname for command. This removes path */
232 strcpy(procprog, base_name(procprog)); 194 strcpy(procprog, base_name(procprog));
233 195
234 /* we need to convert the elapsed time to seconds */ 196 /* we need to convert the elapsed time to seconds */
235 procseconds = convert_to_seconds(procetime); 197 procseconds = convert_to_seconds(procetime, config.metric);
236 198
237 if (verbose >= 3) 199 if (verbose >= 3) {
238 printf ("proc#=%d uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n", 200 printf("proc#=%d uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s "
239 procs, procuid, procvsz, procrss, 201 "prog=%s args=%s\n",
240 procpid, procppid, procpcpu, procstat, 202 procs, procuid, procvsz, procrss, procpid, procppid, procpcpu, procstat,
241 procetime, procprog, procargs); 203 procetime, procprog, procargs);
204 }
242 205
243 /* Ignore self */ 206 /* Ignore self */
244 if ((usepid && mypid == procpid) || 207 int ret = 0;
245 ( ((!usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) && statbuf.st_dev == mydev && statbuf.st_ino == myino)) || 208 if ((config.usepid && mypid == procpid) ||
246 (ret == -1 && errno == ENOENT)) 209 (((!config.usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) &&
247 ) { 210 statbuf.st_dev == mydev && statbuf.st_ino == myino)) ||
248 if (verbose >= 3) 211 (ret == -1 && errno == ENOENT))) {
249 printf("not considering - is myself or gone\n"); 212 if (verbose >= 3) {
213 printf("not considering - is myself or gone\n");
214 }
250 continue; 215 continue;
251 } 216 }
252 /* Ignore parent*/ 217 /* Ignore parent*/
253 else if (myppid == procpid) { 218 if (myppid == procpid) {
254 if (verbose >= 3) 219 if (verbose >= 3) {
255 printf("not considering - is parent\n"); 220 printf("not considering - is parent\n");
221 }
256 continue; 222 continue;
257 } 223 }
258 224
259 /* Ignore our own children */ 225 /* Ignore our own children */
260 if (procppid == mypid) { 226 if (procppid == mypid) {
261 if (verbose >= 3) 227 if (verbose >= 3) {
262 printf("not considering - is our child\n"); 228 printf("not considering - is our child\n");
229 }
263 continue; 230 continue;
264 } 231 }
265 232
266 /* Ignore excluded processes by name */ 233 /* Ignore excluded processes by name */
267 if(options & EXCLUDE_PROGS) { 234 if (config.options & EXCLUDE_PROGS) {
268 int found = 0; 235 bool found = false;
269 int i = 0; 236 for (int i = 0; i < (config.exclude_progs_counter); i++) {
270 237 if (!strcmp(procprog, config.exclude_progs_arr[i])) {
271 for(i=0; i < (exclude_progs_counter); i++) { 238 found = true;
272 if(!strcmp(procprog, exclude_progs_arr[i])) { 239 }
273 found = 1; 240 }
274 } 241 if (!found) {
275 } 242 resultsum |= EXCLUDE_PROGS;
276 if(found == 0) { 243 } else {
277 resultsum |= EXCLUDE_PROGS; 244 if (verbose >= 3) {
278 } else 245 printf("excluding - by ignorelist\n");
279 { 246 }
280 if(verbose >= 3) 247 }
281 printf("excluding - by ignorelist\n");
282 }
283 } 248 }
284 249
285 /* filter kernel threads (children of KTHREAD_PARENT)*/ 250 /* filter kernel threads (children of KTHREAD_PARENT)*/
286 /* TODO adapt for other OSes than GNU/Linux 251 /* TODO adapt for other OSes than GNU/Linux
287 sorry for not doing that, but I've no other OSes to test :-( */ 252 sorry for not doing that, but I've no other OSes to test :-( */
288 if (kthread_filter == 1) { 253 if (config.kthread_filter) {
289 /* get pid KTHREAD_PARENT */ 254 /* get pid KTHREAD_PARENT */
290 if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT) ) 255 if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT)) {
291 kthread_ppid = procpid; 256 kthread_ppid = procpid;
257 }
292 258
293 if (kthread_ppid == procppid) { 259 if (kthread_ppid == procppid) {
294 if (verbose >= 2) 260 if (verbose >= 2) {
295 printf ("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid, procppid, procprog, procargs); 261 printf("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid,
262 procppid, procprog, procargs);
263 }
296 continue; 264 continue;
297 } 265 }
298 } 266 }
299 267
300 if ((options & STAT) && (strstr (procstat, statopts))) 268 if ((config.options & STAT) && (strstr(procstat, config.statopts))) {
301 resultsum |= STAT; 269 resultsum |= STAT;
302 if ((options & ARGS) && procargs && (strstr (procargs, args) != NULL)) 270 }
271 if ((config.options & ARGS) && procargs && (strstr(procargs, config.args) != NULL)) {
303 resultsum |= ARGS; 272 resultsum |= ARGS;
304 if ((options & EREG_ARGS) && procargs && (regexec(&re_args, procargs, (size_t) 0, NULL, 0) == 0)) 273 }
274 if ((config.options & EREG_ARGS) && procargs &&
275 (regexec(&config.re_args, procargs, (size_t)0, NULL, 0) == 0)) {
305 resultsum |= EREG_ARGS; 276 resultsum |= EREG_ARGS;
306 if ((options & PROG) && procprog && (strcmp (prog, procprog) == 0)) 277 }
278 if ((config.options & PROG) && procprog && (strcmp(config.prog, procprog) == 0)) {
307 resultsum |= PROG; 279 resultsum |= PROG;
308 if ((options & PPID) && (procppid == ppid)) 280 }
281 if ((config.options & PPID) && (procppid == config.ppid)) {
309 resultsum |= PPID; 282 resultsum |= PPID;
310 if ((options & USER) && (procuid == uid)) 283 }
284 if ((config.options & USER) && (procuid == config.uid)) {
311 resultsum |= USER; 285 resultsum |= USER;
312 if ((options & VSZ) && (procvsz >= vsz)) 286 }
287 if ((config.options & VSZ) && (procvsz >= config.vsz)) {
313 resultsum |= VSZ; 288 resultsum |= VSZ;
314 if ((options & RSS) && (procrss >= rss)) 289 }
290 if ((config.options & RSS) && (procrss >= config.rss)) {
315 resultsum |= RSS; 291 resultsum |= RSS;
316 if ((options & PCPU) && (procpcpu >= pcpu)) 292 }
293 if ((config.options & PCPU) && (procpcpu >= config.pcpu)) {
317 resultsum |= PCPU; 294 resultsum |= PCPU;
295 }
318 296
319 found++; 297 found++;
320 298
321 /* Next line if filters not matched */ 299 /* Next line if filters not matched */
322 if (!(options == resultsum || options == ALL)) 300 if (!(config.options == resultsum || config.options == ALL)) {
323 continue; 301 continue;
302 }
324 303
325 procs++; 304 procs++;
326 if (verbose >= 2) { 305 if (verbose >= 2) {
327 printf ("Matched: uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n", 306 printf("Matched: uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s "
328 procuid, procvsz, procrss, 307 "prog=%s args=%s\n",
329 procpid, procppid, procpcpu, procstat, 308 procuid, procvsz, procrss, procpid, procppid, procpcpu, procstat, procetime,
330 procetime, procprog, procargs); 309 procprog, procargs);
331 } 310 }
332 311
333 if (metric == METRIC_VSZ) 312 mp_state_enum temporary_result = STATE_OK;
334 i = get_status ((double)procvsz, procs_thresholds); 313 if (config.metric == METRIC_VSZ) {
335 else if (metric == METRIC_RSS) 314 temporary_result = get_status((double)procvsz, config.procs_thresholds);
336 i = get_status ((double)procrss, procs_thresholds); 315 } else if (config.metric == METRIC_RSS) {
316 temporary_result = get_status((double)procrss, config.procs_thresholds);
317 }
337 /* TODO? float thresholds for --metric=CPU */ 318 /* TODO? float thresholds for --metric=CPU */
338 else if (metric == METRIC_CPU) 319 else if (config.metric == METRIC_CPU) {
339 i = get_status (procpcpu, procs_thresholds); 320 temporary_result = get_status(procpcpu, config.procs_thresholds);
340 else if (metric == METRIC_ELAPSED) 321 } else if (config.metric == METRIC_ELAPSED) {
341 i = get_status ((double)procseconds, procs_thresholds); 322 temporary_result = get_status((double)procseconds, config.procs_thresholds);
323 }
342 324
343 if (metric != METRIC_PROCS) { 325 if (config.metric != METRIC_PROCS) {
344 if (i == STATE_WARNING) { 326 if (temporary_result == STATE_WARNING) {
345 warn++; 327 warn++;
346 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog); 328 xasprintf(&config.fails, "%s%s%s", config.fails,
347 result = max_state (result, i); 329 (strcmp(config.fails, "") ? ", " : ""), procprog);
330 result = max_state(result, temporary_result);
348 } 331 }
349 if (i == STATE_CRITICAL) { 332 if (temporary_result == STATE_CRITICAL) {
350 crit++; 333 crit++;
351 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog); 334 xasprintf(&config.fails, "%s%s%s", config.fails,
352 result = max_state (result, i); 335 (strcmp(config.fails, "") ? ", " : ""), procprog);
336 result = max_state(result, temporary_result);
353 } 337 }
354 } 338 }
355 } 339 }
@@ -359,339 +343,366 @@ main (int argc, char **argv)
359 } 343 }
360 } 344 }
361 345
362 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */ 346 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */
363 printf (_("Unable to read output\n")); 347 printf(_("Unable to read output\n"));
364 return STATE_UNKNOWN; 348 return STATE_UNKNOWN;
365 } 349 }
366 350
367 if ( result == STATE_UNKNOWN ) 351 if (result == STATE_UNKNOWN) {
368 result = STATE_OK; 352 result = STATE_OK;
353 }
369 354
370 /* Needed if procs found, but none match filter */ 355 /* Needed if procs found, but none match filter */
371 if ( metric == METRIC_PROCS ) { 356 if (config.metric == METRIC_PROCS) {
372 result = max_state (result, get_status ((double)procs, procs_thresholds) ); 357 result = max_state(result, get_status((double)procs, config.procs_thresholds));
373 } 358 }
374 359
375 if ( result == STATE_OK ) { 360 if (result == STATE_OK) {
376 printf ("%s %s: ", metric_name, _("OK")); 361 printf("%s %s: ", config.metric_name, _("OK"));
377 } else if (result == STATE_WARNING) { 362 } else if (result == STATE_WARNING) {
378 printf ("%s %s: ", metric_name, _("WARNING")); 363 printf("%s %s: ", config.metric_name, _("WARNING"));
379 if ( metric != METRIC_PROCS ) { 364 if (config.metric != METRIC_PROCS) {
380 printf (_("%d warn out of "), warn); 365 printf(_("%d warn out of "), warn);
381 } 366 }
382 } else if (result == STATE_CRITICAL) { 367 } else if (result == STATE_CRITICAL) {
383 printf ("%s %s: ", metric_name, _("CRITICAL")); 368 printf("%s %s: ", config.metric_name, _("CRITICAL"));
384 if (metric != METRIC_PROCS) { 369 if (config.metric != METRIC_PROCS) {
385 printf (_("%d crit, %d warn out of "), crit, warn); 370 printf(_("%d crit, %d warn out of "), crit, warn);
386 } 371 }
387 } 372 }
388 printf (ngettext ("%d process", "%d processes", (unsigned long) procs), procs); 373 printf(ngettext("%d process", "%d processes", (unsigned long)procs), procs);
389 374
390 if (strcmp(fmt,"") != 0) { 375 if (strcmp(config.fmt, "") != 0) {
391 printf (_(" with %s"), fmt); 376 printf(_(" with %s"), config.fmt);
392 } 377 }
393 378
394 if ( verbose >= 1 && strcmp(fails,"") ) 379 if (verbose >= 1 && strcmp(config.fails, "")) {
395 printf (" [%s]", fails); 380 printf(" [%s]", config.fails);
381 }
396 382
397 if (metric == METRIC_PROCS) 383 if (config.metric == METRIC_PROCS) {
398 printf (" | procs=%d;%s;%s;0;", procs, 384 printf(" | procs=%d;%s;%s;0;", procs, config.warning_range ? config.warning_range : "",
399 warning_range ? warning_range : "", 385 config.critical_range ? config.critical_range : "");
400 critical_range ? critical_range : ""); 386 } else {
401 else 387 printf(" | procs=%d;;;0; procs_warn=%d;;;0; procs_crit=%d;;;0;", procs, warn, crit);
402 printf (" | procs=%d;;;0; procs_warn=%d;;;0; procs_crit=%d;;;0;", procs, warn, crit); 388 }
403 389
404 printf ("\n"); 390 printf("\n");
405 return result; 391 exit(result);
406} 392}
407 393
408
409
410/* process command-line arguments */ 394/* process command-line arguments */
411int 395check_procs_config_wrapper process_arguments(int argc, char **argv) {
412process_arguments (int argc, char **argv) 396 static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
413{ 397 {"critical", required_argument, 0, 'c'},
414 int c = 1; 398 {"metric", required_argument, 0, 'm'},
415 char *user; 399 {"timeout", required_argument, 0, 't'},
416 struct passwd *pw; 400 {"status", required_argument, 0, 's'},
417 int option = 0; 401 {"ppid", required_argument, 0, 'p'},
418 int err; 402 {"user", required_argument, 0, 'u'},
419 int cflags = REG_NOSUB | REG_EXTENDED; 403 {"command", required_argument, 0, 'C'},
420 char errbuf[MAX_INPUT_BUFFER]; 404 {"vsz", required_argument, 0, 'z'},
421 char *temp_string; 405 {"rss", required_argument, 0, 'r'},
422 int i=0; 406 {"pcpu", required_argument, 0, 'P'},
423 static struct option longopts[] = { 407 {"elapsed", required_argument, 0, 'e'},
424 {"warning", required_argument, 0, 'w'}, 408 {"argument-array", required_argument, 0, 'a'},
425 {"critical", required_argument, 0, 'c'}, 409 {"help", no_argument, 0, 'h'},
426 {"metric", required_argument, 0, 'm'}, 410 {"version", no_argument, 0, 'V'},
427 {"timeout", required_argument, 0, 't'}, 411 {"verbose", no_argument, 0, 'v'},
428 {"status", required_argument, 0, 's'}, 412 {"ereg-argument-array", required_argument, 0, CHAR_MAX + 1},
429 {"ppid", required_argument, 0, 'p'}, 413 {"input-file", required_argument, 0, CHAR_MAX + 2},
430 {"user", required_argument, 0, 'u'}, 414 {"no-kthreads", required_argument, 0, 'k'},
431 {"command", required_argument, 0, 'C'}, 415 {"traditional-filter", no_argument, 0, 'T'},
432 {"vsz", required_argument, 0, 'z'}, 416 {"exclude-process", required_argument, 0, 'X'},
433 {"rss", required_argument, 0, 'r'}, 417 {0, 0, 0, 0}};
434 {"pcpu", required_argument, 0, 'P'}, 418
435 {"elapsed", required_argument, 0, 'e'}, 419 for (int index = 1; index < argc; index++) {
436 {"argument-array", required_argument, 0, 'a'}, 420 if (strcmp("-to", argv[index]) == 0) {
437 {"help", no_argument, 0, 'h'}, 421 strcpy(argv[index], "-t");
438 {"version", no_argument, 0, 'V'}, 422 }
439 {"verbose", no_argument, 0, 'v'}, 423 }
440 {"ereg-argument-array", required_argument, 0, CHAR_MAX+1},
441 {"input-file", required_argument, 0, CHAR_MAX+2},
442 {"no-kthreads", required_argument, 0, 'k'},
443 {"traditional-filter", no_argument, 0, 'T'},
444 {"exclude-process", required_argument, 0, 'X'},
445 {0, 0, 0, 0}
446 };
447 424
448 for (c = 1; c < argc; c++) 425 check_procs_config_wrapper result = {
449 if (strcmp ("-to", argv[c]) == 0) 426 .errorcode = OK,
450 strcpy (argv[c], "-t"); 427 .config = check_procs_config_init(),
428 };
451 429
452 while (1) { 430 while (true) {
453 c = getopt_long (argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:", 431 int option = 0;
454 longopts, &option); 432 int option_index =
433 getopt_long(argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:", longopts, &option);
455 434
456 if (c == -1 || c == EOF) 435 if (option_index == -1 || option_index == EOF) {
457 break; 436 break;
437 }
458 438
459 switch (c) { 439 switch (option_index) {
460 case '?': /* help */ 440 case '?': /* help */
461 usage5 (); 441 usage5();
462 case 'h': /* help */ 442 case 'h': /* help */
463 print_help (); 443 print_help();
464 exit (STATE_UNKNOWN); 444 exit(STATE_UNKNOWN);
465 case 'V': /* version */ 445 case 'V': /* version */
466 print_revision (progname, NP_VERSION); 446 print_revision(progname, NP_VERSION);
467 exit (STATE_UNKNOWN); 447 exit(STATE_UNKNOWN);
468 case 't': /* timeout period */ 448 case 't': /* timeout period */
469 if (!is_integer (optarg)) 449 if (!is_integer(optarg)) {
470 usage2 (_("Timeout interval must be a positive integer"), optarg); 450 usage2(_("Timeout interval must be a positive integer"), optarg);
471 else 451 } else {
472 timeout_interval = atoi (optarg); 452 timeout_interval = atoi(optarg);
453 }
473 break; 454 break;
474 case 'c': /* critical threshold */ 455 case 'c': /* critical threshold */
475 critical_range = optarg; 456 result.config.critical_range = optarg;
476 break; 457 break;
477 case 'w': /* warning threshold */ 458 case 'w': /* warning threshold */
478 warning_range = optarg; 459 result.config.warning_range = optarg;
479 break; 460 break;
480 case 'p': /* process id */ 461 case 'p': { /* process id */
481 if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) { 462 static char tmp[MAX_INPUT_BUFFER];
482 xasprintf (&fmt, "%s%sPPID = %d", (fmt ? fmt : "") , (options ? ", " : ""), ppid); 463 if (sscanf(optarg, "%d%[^0-9]", &result.config.ppid, tmp) == 1) {
483 options |= PPID; 464 xasprintf(&result.config.fmt, "%s%sPPID = %d",
465 (result.config.fmt ? result.config.fmt : ""),
466 (result.config.options ? ", " : ""), result.config.ppid);
467 result.config.options |= PPID;
484 break; 468 break;
485 } 469 }
486 usage4 (_("Parent Process ID must be an integer!")); 470 usage4(_("Parent Process ID must be an integer!"));
487 case 's': /* status */ 471 }
488 if (statopts) 472 case 's': /* status */
473 if (result.config.statopts) {
489 break; 474 break;
490 else 475 } else {
491 statopts = optarg; 476 result.config.statopts = optarg;
492 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); 477 }
493 options |= STAT; 478 xasprintf(&result.config.fmt, _("%s%sSTATE = %s"),
479 (result.config.fmt ? result.config.fmt : ""),
480 (result.config.options ? ", " : ""), result.config.statopts);
481 result.config.options |= STAT;
494 break; 482 break;
495 case 'u': /* user or user id */ 483 case 'u': /* user or user id */ {
496 if (is_integer (optarg)) { 484 struct passwd *pw;
497 uid = atoi (optarg); 485 if (is_integer(optarg)) {
498 pw = getpwuid ((uid_t) uid); 486 result.config.uid = atoi(optarg);
487 pw = getpwuid(result.config.uid);
499 /* check to be sure user exists */ 488 /* check to be sure user exists */
500 if (pw == NULL) 489 if (pw == NULL) {
501 usage2 (_("UID was not found"), optarg); 490 usage2(_("UID was not found"), optarg);
502 } 491 }
503 else { 492 } else {
504 pw = getpwnam (optarg); 493 pw = getpwnam(optarg);
505 /* check to be sure user exists */ 494 /* check to be sure user exists */
506 if (pw == NULL) 495 if (pw == NULL) {
507 usage2 (_("User name was not found"), optarg); 496 usage2(_("User name was not found"), optarg);
497 }
508 /* then get uid */ 498 /* then get uid */
509 uid = pw->pw_uid; 499 result.config.uid = pw->pw_uid;
510 } 500 }
511 user = pw->pw_name; 501
512 xasprintf (&fmt, "%s%sUID = %d (%s)", (fmt ? fmt : ""), (options ? ", " : ""), 502 char *user = pw->pw_name;
513 uid, user); 503 xasprintf(&result.config.fmt, "%s%sUID = %d (%s)",
514 options |= USER; 504 (result.config.fmt ? result.config.fmt : ""),
515 break; 505 (result.config.options ? ", " : ""), result.config.uid, user);
516 case 'C': /* command */ 506 result.config.options |= USER;
507 } break;
508 case 'C': /* command */
517 /* TODO: allow this to be passed in with --metric */ 509 /* TODO: allow this to be passed in with --metric */
518 if (prog) 510 if (result.config.prog) {
519 break; 511 break;
520 else 512 } else {
521 prog = optarg; 513 result.config.prog = optarg;
522 xasprintf (&fmt, _("%s%scommand name '%s'"), (fmt ? fmt : ""), (options ? ", " : ""), 514 }
523 prog); 515 xasprintf(&result.config.fmt, _("%s%scommand name '%s'"),
524 options |= PROG; 516 (result.config.fmt ? result.config.fmt : ""),
517 (result.config.options ? ", " : ""), result.config.prog);
518 result.config.options |= PROG;
525 break; 519 break;
526 case 'X': 520 case 'X':
527 if(exclude_progs) 521 if (result.config.exclude_progs) {
528 break; 522 break;
529 else 523 } else {
530 exclude_progs = optarg; 524 result.config.exclude_progs = optarg;
531 xasprintf (&fmt, _("%s%sexclude progs '%s'"), (fmt ? fmt : ""), (options ? ", " : ""), 525 }
532 exclude_progs); 526 xasprintf(&result.config.fmt, _("%s%sexclude progs '%s'"),
533 char *p = strtok(exclude_progs, ","); 527 (result.config.fmt ? result.config.fmt : ""),
534 528 (result.config.options ? ", " : ""), result.config.exclude_progs);
535 while(p){ 529 char *tmp_pointer = strtok(result.config.exclude_progs, ",");
536 exclude_progs_arr = realloc(exclude_progs_arr, sizeof(char*) * ++exclude_progs_counter); 530
537 exclude_progs_arr[exclude_progs_counter-1] = p; 531 while (tmp_pointer) {
538 p = strtok(NULL, ","); 532 result.config.exclude_progs_arr =
533 realloc(result.config.exclude_progs_arr,
534 sizeof(char *) * ++result.config.exclude_progs_counter);
535 result.config.exclude_progs_arr[result.config.exclude_progs_counter - 1] =
536 tmp_pointer;
537 tmp_pointer = strtok(NULL, ",");
539 } 538 }
540 539
541 options |= EXCLUDE_PROGS; 540 result.config.options |= EXCLUDE_PROGS;
542 break; 541 break;
543 case 'a': /* args (full path name with args) */ 542 case 'a': /* args (full path name with args) */
544 /* TODO: allow this to be passed in with --metric */ 543 /* TODO: allow this to be passed in with --metric */
545 if (args) 544 if (result.config.args) {
546 break; 545 break;
547 else 546 } else {
548 args = optarg; 547 result.config.args = optarg;
549 xasprintf (&fmt, "%s%sargs '%s'", (fmt ? fmt : ""), (options ? ", " : ""), args); 548 }
550 options |= ARGS; 549 xasprintf(&result.config.fmt, "%s%sargs '%s'",
550 (result.config.fmt ? result.config.fmt : ""),
551 (result.config.options ? ", " : ""), result.config.args);
552 result.config.options |= ARGS;
551 break; 553 break;
552 case CHAR_MAX+1: 554 case CHAR_MAX + 1: {
553 err = regcomp(&re_args, optarg, cflags); 555 int cflags = REG_NOSUB | REG_EXTENDED;
556 int err = regcomp(&result.config.re_args, optarg, cflags);
554 if (err != 0) { 557 if (err != 0) {
555 regerror (err, &re_args, errbuf, MAX_INPUT_BUFFER); 558 char errbuf[MAX_INPUT_BUFFER];
556 die (STATE_UNKNOWN, "PROCS %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf); 559 regerror(err, &result.config.re_args, errbuf, MAX_INPUT_BUFFER);
560 die(STATE_UNKNOWN, "PROCS %s: %s - %s\n", _("UNKNOWN"),
561 _("Could not compile regular expression"), errbuf);
557 } 562 }
558 /* Strip off any | within the regex optarg */ 563 /* Strip off any | within the regex optarg */
559 temp_string = strdup(optarg); 564 char *temp_string = strdup(optarg);
560 while(temp_string[i]!='\0'){ 565 int index = 0;
561 if(temp_string[i]=='|') 566 while (temp_string[index] != '\0') {
562 temp_string[i]=','; 567 if (temp_string[index] == '|') {
563 i++; 568 temp_string[index] = ',';
564 } 569 }
565 xasprintf (&fmt, "%s%sregex args '%s'", (fmt ? fmt : ""), (options ? ", " : ""), temp_string); 570 index++;
566 options |= EREG_ARGS; 571 }
567 break; 572 xasprintf(&result.config.fmt, "%s%sregex args '%s'",
568 case 'r': /* RSS */ 573 (result.config.fmt ? result.config.fmt : ""),
569 if (sscanf (optarg, "%d%[^0-9]", &rss, tmp) == 1) { 574 (result.config.options ? ", " : ""), temp_string);
570 xasprintf (&fmt, "%s%sRSS >= %d", (fmt ? fmt : ""), (options ? ", " : ""), rss); 575 result.config.options |= EREG_ARGS;
571 options |= RSS; 576 } break;
577 case 'r': { /* RSS */
578 static char tmp[MAX_INPUT_BUFFER];
579 if (sscanf(optarg, "%d%[^0-9]", &result.config.rss, tmp) == 1) {
580 xasprintf(&result.config.fmt, "%s%sRSS >= %d",
581 (result.config.fmt ? result.config.fmt : ""),
582 (result.config.options ? ", " : ""), result.config.rss);
583 result.config.options |= RSS;
572 break; 584 break;
573 } 585 }
574 usage4 (_("RSS must be an integer!")); 586 usage4(_("RSS must be an integer!"));
575 case 'z': /* VSZ */ 587 }
576 if (sscanf (optarg, "%d%[^0-9]", &vsz, tmp) == 1) { 588 case 'z': { /* VSZ */
577 xasprintf (&fmt, "%s%sVSZ >= %d", (fmt ? fmt : ""), (options ? ", " : ""), vsz); 589 static char tmp[MAX_INPUT_BUFFER];
578 options |= VSZ; 590 if (sscanf(optarg, "%d%[^0-9]", &result.config.vsz, tmp) == 1) {
591 xasprintf(&result.config.fmt, "%s%sVSZ >= %d",
592 (result.config.fmt ? result.config.fmt : ""),
593 (result.config.options ? ", " : ""), result.config.vsz);
594 result.config.options |= VSZ;
579 break; 595 break;
580 } 596 }
581 usage4 (_("VSZ must be an integer!")); 597 usage4(_("VSZ must be an integer!"));
582 case 'P': /* PCPU */ 598 }
599 case 'P': { /* PCPU */
583 /* TODO: -P 1.5.5 is accepted */ 600 /* TODO: -P 1.5.5 is accepted */
584 if (sscanf (optarg, "%f%[^0-9.]", &pcpu, tmp) == 1) { 601 static char tmp[MAX_INPUT_BUFFER];
585 xasprintf (&fmt, "%s%sPCPU >= %.2f", (fmt ? fmt : ""), (options ? ", " : ""), pcpu); 602 if (sscanf(optarg, "%f%[^0-9.]", &result.config.pcpu, tmp) == 1) {
586 options |= PCPU; 603 xasprintf(&result.config.fmt, "%s%sPCPU >= %.2f",
604 (result.config.fmt ? result.config.fmt : ""),
605 (result.config.options ? ", " : ""), result.config.pcpu);
606 result.config.options |= PCPU;
587 break; 607 break;
588 } 608 }
589 usage4 (_("PCPU must be a float!")); 609 usage4(_("PCPU must be a float!"));
610 }
590 case 'm': 611 case 'm':
591 xasprintf (&metric_name, "%s", optarg); 612 xasprintf(&result.config.metric_name, "%s", optarg);
592 if ( strcmp(optarg, "PROCS") == 0) { 613 if (strcmp(optarg, "PROCS") == 0) {
593 metric = METRIC_PROCS; 614 result.config.metric = METRIC_PROCS;
594 break; 615 break;
595 } 616 }
596 else if ( strcmp(optarg, "VSZ") == 0) { 617 if (strcmp(optarg, "VSZ") == 0) {
597 metric = METRIC_VSZ; 618 result.config.metric = METRIC_VSZ;
598 break; 619 break;
599 } 620 }
600 else if ( strcmp(optarg, "RSS") == 0 ) { 621 if (strcmp(optarg, "RSS") == 0) {
601 metric = METRIC_RSS; 622 result.config.metric = METRIC_RSS;
602 break; 623 break;
603 } 624 }
604 else if ( strcmp(optarg, "CPU") == 0 ) { 625 if (strcmp(optarg, "CPU") == 0) {
605 metric = METRIC_CPU; 626 result.config.metric = METRIC_CPU;
606 break; 627 break;
607 } 628 }
608 else if ( strcmp(optarg, "ELAPSED") == 0) { 629 if (strcmp(optarg, "ELAPSED") == 0) {
609 metric = METRIC_ELAPSED; 630 result.config.metric = METRIC_ELAPSED;
610 break; 631 break;
611 } 632 }
612 633
613 usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!")); 634 usage4(_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!"));
614 case 'k': /* linux kernel thread filter */ 635 case 'k': /* linux kernel thread filter */
615 kthread_filter = 1; 636 result.config.kthread_filter = true;
616 break; 637 break;
617 case 'v': /* command */ 638 case 'v': /* command */
618 verbose++; 639 verbose++;
619 break; 640 break;
620 case 'T': 641 case 'T':
621 usepid = 1; 642 result.config.usepid = true;
622 break; 643 break;
623 case CHAR_MAX+2: 644 case CHAR_MAX + 2:
624 input_filename = optarg; 645 result.config.input_filename = optarg;
625 break; 646 break;
626 } 647 }
627 } 648 }
628 649
629 c = optind; 650 int index = optind;
630 if ((! warning_range) && argv[c]) 651 if ((!result.config.warning_range) && argv[index]) {
631 warning_range = argv[c++]; 652 result.config.warning_range = argv[index++];
632 if ((! critical_range) && argv[c]) 653 }
633 critical_range = argv[c++]; 654 if ((!result.config.critical_range) && argv[index]) {
634 if (statopts == NULL && argv[c]) { 655 result.config.critical_range = argv[index++];
635 xasprintf (&statopts, "%s", argv[c++]); 656 }
636 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); 657 if (result.config.statopts == NULL && argv[index]) {
637 options |= STAT; 658 xasprintf(&result.config.statopts, "%s", argv[index++]);
659 xasprintf(&result.config.fmt, _("%s%sSTATE = %s"),
660 (result.config.fmt ? result.config.fmt : ""), (result.config.options ? ", " : ""),
661 result.config.statopts);
662 result.config.options |= STAT;
638 } 663 }
639 664
640 /* this will abort in case of invalid ranges */ 665 /* this will abort in case of invalid ranges */
641 set_thresholds (&procs_thresholds, warning_range, critical_range); 666 set_thresholds(&result.config.procs_thresholds, result.config.warning_range,
667 result.config.critical_range);
642 668
643 return validate_arguments (); 669 return validate_arguments(result);
644} 670}
645 671
672check_procs_config_wrapper validate_arguments(check_procs_config_wrapper config_wrapper) {
673 if (config_wrapper.config.options == 0) {
674 config_wrapper.config.options = ALL;
675 }
646 676
677 if (config_wrapper.config.statopts == NULL) {
678 config_wrapper.config.statopts = strdup("");
679 }
647 680
648int 681 if (config_wrapper.config.prog == NULL) {
649validate_arguments () 682 config_wrapper.config.prog = strdup("");
650{ 683 }
651 if (options == 0)
652 options = ALL;
653
654 if (statopts==NULL)
655 statopts = strdup("");
656
657 if (prog==NULL)
658 prog = strdup("");
659 684
660 if (args==NULL) 685 if (config_wrapper.config.args == NULL) {
661 args = strdup(""); 686 config_wrapper.config.args = strdup("");
687 }
662 688
663 if (fmt==NULL) 689 if (config_wrapper.config.fmt == NULL) {
664 fmt = strdup(""); 690 config_wrapper.config.fmt = strdup("");
691 }
665 692
666 if (fails==NULL) 693 if (config_wrapper.config.fails == NULL) {
667 fails = strdup(""); 694 config_wrapper.config.fails = strdup("");
695 }
668 696
669 return options; 697 // return options;
698 return config_wrapper;
670} 699}
671 700
672
673/* convert the elapsed time to seconds */ 701/* convert the elapsed time to seconds */
674int 702int convert_to_seconds(char *etime, enum metric metric) {
675convert_to_seconds(char *etime) { 703 int hyphcnt = 0;
676 704 int coloncnt = 0;
677 char *ptr; 705 for (char *ptr = etime; *ptr != '\0'; ptr++) {
678 int total;
679
680 int hyphcnt;
681 int coloncnt;
682 int days;
683 int hours;
684 int minutes;
685 int seconds;
686
687 hyphcnt = 0;
688 coloncnt = 0;
689 days = 0;
690 hours = 0;
691 minutes = 0;
692 seconds = 0;
693
694 for (ptr = etime; *ptr != '\0'; ptr++) {
695 706
696 if (*ptr == '-') { 707 if (*ptr == '-') {
697 hyphcnt++; 708 hyphcnt++;
@@ -703,9 +714,12 @@ convert_to_seconds(char *etime) {
703 } 714 }
704 } 715 }
705 716
717 int days = 0;
718 int hours = 0;
719 int minutes = 0;
720 int seconds = 0;
706 if (hyphcnt > 0) { 721 if (hyphcnt > 0) {
707 sscanf(etime, "%d-%d:%d:%d", 722 sscanf(etime, "%d-%d:%d:%d", &days, &hours, &minutes, &seconds);
708 &days, &hours, &minutes, &seconds);
709 /* linux 2.6.5/2.6.6 reporting some processes with infinite 723 /* linux 2.6.5/2.6.6 reporting some processes with infinite
710 * elapsed times for some reason */ 724 * elapsed times for some reason */
711 if (days == 49710) { 725 if (days == 49710) {
@@ -713,135 +727,129 @@ convert_to_seconds(char *etime) {
713 } 727 }
714 } else { 728 } else {
715 if (coloncnt == 2) { 729 if (coloncnt == 2) {
716 sscanf(etime, "%d:%d:%d", 730 sscanf(etime, "%d:%d:%d", &hours, &minutes, &seconds);
717 &hours, &minutes, &seconds);
718 } else if (coloncnt == 1) { 731 } else if (coloncnt == 1) {
719 sscanf(etime, "%d:%d", 732 sscanf(etime, "%d:%d", &minutes, &seconds);
720 &minutes, &seconds);
721 } 733 }
722 } 734 }
723 735
724 total = (days * 86400) + 736 int total = (days * 86400) + (hours * 3600) + (minutes * 60) + seconds;
725 (hours * 3600) +
726 (minutes * 60) +
727 seconds;
728 737
729 if (verbose >= 3 && metric == METRIC_ELAPSED) { 738 if (verbose >= 3 && metric == METRIC_ELAPSED) {
730 printf("seconds: %d\n", total); 739 printf("seconds: %d\n", total);
731 } 740 }
732 return total; 741 return total;
733} 742}
734 743
735 744void print_help(void) {
736void 745 print_revision(progname, NP_VERSION);
737print_help (void) 746
738{ 747 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
739 print_revision (progname, NP_VERSION); 748 printf(COPYRIGHT, copyright, email);
740 749
741 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 750 printf("%s\n",
742 printf (COPYRIGHT, copyright, email); 751 _("Checks all processes and generates WARNING or CRITICAL states if the specified"));
743 752 printf("%s\n",
744 printf ("%s\n", _("Checks all processes and generates WARNING or CRITICAL states if the specified")); 753 _("metric is outside the required threshold ranges. The metric defaults to number"));
745 printf ("%s\n", _("metric is outside the required threshold ranges. The metric defaults to number")); 754 printf("%s\n",
746 printf ("%s\n", _("of processes. Search filters can be applied to limit the processes to check.")); 755 _("of processes. Search filters can be applied to limit the processes to check."));
747 756
748 printf ("\n\n"); 757 printf("\n\n");
749 758
750 printf ("%s\n", _("The parent process, check_procs itself and any child process of check_procs (ps)")); 759 printf("%s\n",
751 printf ("%s\n", _("are excluded from any checks to prevent false positives.")); 760 _("The parent process, check_procs itself and any child process of check_procs (ps)"));
752 761 printf("%s\n", _("are excluded from any checks to prevent false positives."));
753 printf ("\n\n"); 762
754 763 printf("\n\n");
755 print_usage (); 764
756 765 print_usage();
757 printf (UT_HELP_VRSN); 766
758 printf (UT_EXTRA_OPTS); 767 printf(UT_HELP_VRSN);
759 printf (" %s\n", "-w, --warning=RANGE"); 768 printf(UT_EXTRA_OPTS);
760 printf (" %s\n", _("Generate warning state if metric is outside this range")); 769 printf(" %s\n", "-w, --warning=RANGE");
761 printf (" %s\n", "-c, --critical=RANGE"); 770 printf(" %s\n", _("Generate warning state if metric is outside this range"));
762 printf (" %s\n", _("Generate critical state if metric is outside this range")); 771 printf(" %s\n", "-c, --critical=RANGE");
763 printf (" %s\n", "-m, --metric=TYPE"); 772 printf(" %s\n", _("Generate critical state if metric is outside this range"));
764 printf (" %s\n", _("Check thresholds against metric. Valid types:")); 773 printf(" %s\n", "-m, --metric=TYPE");
765 printf (" %s\n", _("PROCS - number of processes (default)")); 774 printf(" %s\n", _("Check thresholds against metric. Valid types:"));
766 printf (" %s\n", _("VSZ - virtual memory size")); 775 printf(" %s\n", _("PROCS - number of processes (default)"));
767 printf (" %s\n", _("RSS - resident set memory size")); 776 printf(" %s\n", _("VSZ - virtual memory size"));
768 printf (" %s\n", _("CPU - percentage CPU")); 777 printf(" %s\n", _("RSS - resident set memory size"));
778 printf(" %s\n", _("CPU - percentage CPU"));
769/* only linux etime is support currently */ 779/* only linux etime is support currently */
770#if defined( __linux__ ) 780#if defined(__linux__)
771 printf (" %s\n", _("ELAPSED - time elapsed in seconds")); 781 printf(" %s\n", _("ELAPSED - time elapsed in seconds"));
772#endif /* defined(__linux__) */ 782#endif /* defined(__linux__) */
773 printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 783 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
774 784
775 printf (" %s\n", "-v, --verbose"); 785 printf(" %s\n", "-v, --verbose");
776 printf (" %s\n", _("Extra information. Up to 3 verbosity levels")); 786 printf(" %s\n", _("Extra information. Up to 3 verbosity levels"));
777 787
778 printf (" %s\n", "-T, --traditional"); 788 printf(" %s\n", "-T, --traditional");
779 printf (" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe")); 789 printf(" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe"));
780 790
781 printf ("\n"); 791 printf("\n");
782 printf ("%s\n", "Filters:"); 792 printf("%s\n", "Filters:");
783 printf (" %s\n", "-s, --state=STATUSFLAGS"); 793 printf(" %s\n", "-s, --state=STATUSFLAGS");
784 printf (" %s\n", _("Only scan for processes that have, in the output of `ps`, one or")); 794 printf(" %s\n", _("Only scan for processes that have, in the output of `ps`, one or"));
785 printf (" %s\n", _("more of the status flags you specify (for example R, Z, S, RS,")); 795 printf(" %s\n", _("more of the status flags you specify (for example R, Z, S, RS,"));
786 printf (" %s\n", _("RSZDT, plus others based on the output of your 'ps' command).")); 796 printf(" %s\n", _("RSZDT, plus others based on the output of your 'ps' command)."));
787 printf (" %s\n", "-p, --ppid=PPID"); 797 printf(" %s\n", "-p, --ppid=PPID");
788 printf (" %s\n", _("Only scan for children of the parent process ID indicated.")); 798 printf(" %s\n", _("Only scan for children of the parent process ID indicated."));
789 printf (" %s\n", "-z, --vsz=VSZ"); 799 printf(" %s\n", "-z, --vsz=VSZ");
790 printf (" %s\n", _("Only scan for processes with VSZ higher than indicated.")); 800 printf(" %s\n", _("Only scan for processes with VSZ higher than indicated."));
791 printf (" %s\n", "-r, --rss=RSS"); 801 printf(" %s\n", "-r, --rss=RSS");
792 printf (" %s\n", _("Only scan for processes with RSS higher than indicated.")); 802 printf(" %s\n", _("Only scan for processes with RSS higher than indicated."));
793 printf (" %s\n", "-P, --pcpu=PCPU"); 803 printf(" %s\n", "-P, --pcpu=PCPU");
794 printf (" %s\n", _("Only scan for processes with PCPU higher than indicated.")); 804 printf(" %s\n", _("Only scan for processes with PCPU higher than indicated."));
795 printf (" %s\n", "-u, --user=USER"); 805 printf(" %s\n", "-u, --user=USER");
796 printf (" %s\n", _("Only scan for processes with user name or ID indicated.")); 806 printf(" %s\n", _("Only scan for processes with user name or ID indicated."));
797 printf (" %s\n", "-a, --argument-array=STRING"); 807 printf(" %s\n", "-a, --argument-array=STRING");
798 printf (" %s\n", _("Only scan for processes with args that contain STRING.")); 808 printf(" %s\n", _("Only scan for processes with args that contain STRING."));
799 printf (" %s\n", "--ereg-argument-array=STRING"); 809 printf(" %s\n", "--ereg-argument-array=STRING");
800 printf (" %s\n", _("Only scan for processes with args that contain the regex STRING.")); 810 printf(" %s\n", _("Only scan for processes with args that contain the regex STRING."));
801 printf (" %s\n", "-C, --command=COMMAND"); 811 printf(" %s\n", "-C, --command=COMMAND");
802 printf (" %s\n", _("Only scan for exact matches of COMMAND (without path).")); 812 printf(" %s\n", _("Only scan for exact matches of COMMAND (without path)."));
803 printf (" %s\n", "-X, --exclude-process"); 813 printf(" %s\n", "-X, --exclude-process");
804 printf (" %s\n", _("Exclude processes which match this comma separated list")); 814 printf(" %s\n", _("Exclude processes which match this comma separated list"));
805 printf (" %s\n", "-k, --no-kthreads"); 815 printf(" %s\n", "-k, --no-kthreads");
806 printf (" %s\n", _("Only scan for non kernel threads (works on Linux only).")); 816 printf(" %s\n", _("Only scan for non kernel threads (works on Linux only)."));
807 817
808 printf(_("\n\ 818 printf(_("\n\
809RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\ 819RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\
810specified 'max:min', a warning status will be generated if the\n\ 820specified 'max:min', a warning status will be generated if the\n\
811count is inside the specified range\n\n")); 821count is inside the specified range\n\n"));
812 822
813 printf(_("\ 823 printf(_("\
814This plugin checks the number of currently running processes and\n\ 824This plugin checks the number of currently running processes and\n\
815generates WARNING or CRITICAL states if the process count is outside\n\ 825generates WARNING or CRITICAL states if the process count is outside\n\
816the specified threshold ranges. The process count can be filtered by\n\ 826the specified threshold ranges. The process count can be filtered by\n\
817process owner, parent process PID, current state (e.g., 'Z'), or may\n\ 827process owner, parent process PID, current state (e.g., 'Z'), or may\n\
818be the total number of running processes\n\n")); 828be the total number of running processes\n\n"));
819 829
820 printf ("%s\n", _("Examples:")); 830 printf("%s\n", _("Examples:"));
821 printf (" %s\n", "check_procs -w 2:2 -c 2:1024 -C portsentry"); 831 printf(" %s\n", "check_procs -w 2:2 -c 2:1024 -C portsentry");
822 printf (" %s\n", _("Warning if not two processes with command name portsentry.")); 832 printf(" %s\n", _("Warning if not two processes with command name portsentry."));
823 printf (" %s\n\n", _("Critical if < 2 or > 1024 processes")); 833 printf(" %s\n\n", _("Critical if < 2 or > 1024 processes"));
824 printf (" %s\n", "check_procs -c 1: -C sshd"); 834 printf(" %s\n", "check_procs -c 1: -C sshd");
825 printf (" %s\n", _("Critical if not at least 1 process with command sshd")); 835 printf(" %s\n", _("Critical if not at least 1 process with command sshd"));
826 printf (" %s\n", "check_procs -w 1024 -c 1: -C sshd"); 836 printf(" %s\n", "check_procs -w 1024 -c 1: -C sshd");
827 printf (" %s\n", _("Warning if > 1024 processes with command name sshd.")); 837 printf(" %s\n", _("Warning if > 1024 processes with command name sshd."));
828 printf (" %s\n\n", _("Critical if < 1 processes with command name sshd.")); 838 printf(" %s\n\n", _("Critical if < 1 processes with command name sshd."));
829 printf (" %s\n", "check_procs -w 10 -a '/usr/local/bin/perl' -u root"); 839 printf(" %s\n", "check_procs -w 10 -a '/usr/local/bin/perl' -u root");
830 printf (" %s\n", _("Warning alert if > 10 processes with command arguments containing")); 840 printf(" %s\n", _("Warning alert if > 10 processes with command arguments containing"));
831 printf (" %s\n\n", _("'/usr/local/bin/perl' and owned by root")); 841 printf(" %s\n\n", _("'/usr/local/bin/perl' and owned by root"));
832 printf (" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ"); 842 printf(" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ");
833 printf (" %s\n\n", _("Alert if VSZ of any processes over 50K or 100K")); 843 printf(" %s\n\n", _("Alert if VSZ of any processes over 50K or 100K"));
834 printf (" %s\n", "check_procs -w 10 -c 20 --metric=CPU"); 844 printf(" %s\n", "check_procs -w 10 -c 20 --metric=CPU");
835 printf (" %s\n", _("Alert if CPU of any processes over 10%% or 20%%")); 845 printf(" %s\n", _("Alert if CPU of any processes over 10%% or 20%%"));
836 846
837 printf (UT_SUPPORT); 847 printf(UT_SUPPORT);
838} 848}
839 849
840void 850void print_usage(void) {
841print_usage (void) 851 printf("%s\n", _("Usage:"));
842{ 852 printf("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname);
843 printf ("%s\n", _("Usage:")); 853 printf(" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n");
844 printf ("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname); 854 printf(" [-C command] [-X process_to_exclude] [-k] [-t timeout] [-v]\n");
845 printf (" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n");
846 printf (" [-C command] [-X process_to_exclude] [-k] [-t timeout] [-v]\n");
847} 855}
diff --git a/plugins/check_procs.d/config.h b/plugins/check_procs.d/config.h
new file mode 100644
index 00000000..e32ca066
--- /dev/null
+++ b/plugins/check_procs.d/config.h
@@ -0,0 +1,75 @@
1#pragma once
2
3#include "../../config.h"
4#include "regex.h"
5#include "thresholds.h"
6#include <stddef.h>
7#include <string.h>
8#include <sys/types.h>
9
10enum metric {
11 METRIC_PROCS,
12 METRIC_VSZ,
13 METRIC_RSS,
14 METRIC_CPU,
15 METRIC_ELAPSED
16};
17
18typedef struct {
19 int options; /* bitmask of filter criteria to test against */
20 enum metric metric;
21 char *metric_name;
22 char *input_filename;
23 char *prog;
24 char *args;
25 char *fmt;
26 char *fails;
27 char *exclude_progs;
28 char **exclude_progs_arr;
29 char exclude_progs_counter;
30 regex_t re_args;
31
32 bool kthread_filter;
33 bool usepid; /* whether to test for pid or /proc/pid/exe */
34 uid_t uid;
35 pid_t ppid;
36 int vsz;
37 int rss;
38 float pcpu;
39 char *statopts;
40
41 char *warning_range;
42 char *critical_range;
43 thresholds *procs_thresholds;
44} check_procs_config;
45
46check_procs_config check_procs_config_init() {
47 check_procs_config tmp = {
48 .options = 0,
49 .metric = METRIC_PROCS,
50 .metric_name = strdup("PROCS"),
51 .input_filename = NULL,
52 .prog = NULL,
53 .args = NULL,
54 .fmt = NULL,
55 .fails = NULL,
56 .exclude_progs = NULL,
57 .exclude_progs_arr = NULL,
58 .exclude_progs_counter = 0,
59 .re_args = {0},
60
61 .kthread_filter = false,
62 .usepid = false,
63 .uid = 0,
64 .ppid = 0,
65 .vsz = 0,
66 .rss = 0,
67 .pcpu = 0,
68 .statopts = NULL,
69
70 .warning_range = NULL,
71 .critical_range = NULL,
72 .procs_thresholds = NULL,
73 };
74 return tmp;
75}
diff --git a/plugins/check_radius.c b/plugins/check_radius.c
index d9ff8fa7..d26f7cf3 100644
--- a/plugins/check_radius.c
+++ b/plugins/check_radius.c
@@ -1,32 +1,32 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_radius plugin 3 * Monitoring check_radius plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2024 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_radius plugin 10 * This file contains the check_radius plugin
11* 11 *
12* Tests to see if a radius server is accepting connections. 12 * Tests to see if a radius server is accepting connections.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31const char *progname = "check_radius"; 31const char *progname = "check_radius";
32const char *copyright = "2000-2024"; 32const char *copyright = "2000-2024";
@@ -35,64 +35,58 @@ const char *email = "devel@monitoring-plugins.org";
35#include "common.h" 35#include "common.h"
36#include "utils.h" 36#include "utils.h"
37#include "netutils.h" 37#include "netutils.h"
38#include "states.h"
39#include "check_radius.d/config.h"
38 40
39#if defined(HAVE_LIBRADCLI) 41#if defined(HAVE_LIBRADCLI)
40#include <radcli/radcli.h> 42# include <radcli/radcli.h>
41#elif defined(HAVE_LIBFREERADIUS_CLIENT) 43#elif defined(HAVE_LIBFREERADIUS_CLIENT)
42#include <freeradius-client.h> 44# include <freeradius-client.h>
43#elif defined(HAVE_LIBRADIUSCLIENT_NG) 45#elif defined(HAVE_LIBRADIUSCLIENT_NG)
44#include <radiusclient-ng.h> 46# include <radiusclient-ng.h>
45#else 47#else
46#include <radiusclient.h> 48# include <radiusclient.h>
47#endif 49#endif
48 50
49static int process_arguments (int /*argc*/, char ** /*argv*/); 51typedef struct {
50static void print_help (void); 52 int errorcode;
51void print_usage (void); 53 check_radius_config config;
52 54} check_radius_config_wrapper;
53#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI) 55static check_radius_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
54#define my_rc_conf_str(a) rc_conf_str(rch,a) 56static void print_help(void);
55#if defined(HAVE_LIBRADCLI) 57void print_usage(void);
56#define my_rc_send_server(a,b) rc_send_server(rch,a,b,AUTH) 58
57#else 59#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || \
58#define my_rc_send_server(a,b) rc_send_server(rch,a,b) 60 defined(HAVE_LIBRADCLI)
59#endif 61# define my_rc_conf_str(a) rc_conf_str(rch, a)
60#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADCLI) 62# if defined(HAVE_LIBRADCLI)
61#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(rch,a,b,c,d,(a)->secret,e,f) 63# define my_rc_send_server(a, b) rc_send_server(rch, a, b, AUTH)
64# else
65# define my_rc_send_server(a, b) rc_send_server(rch, a, b)
66# endif
67# if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADCLI)
68# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(rch, a, b, c, d, (a)->secret, e, f)
69# else
70# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(rch, a, b, c, d, e, f)
71# endif
72# define my_rc_avpair_add(a, b, c, d) rc_avpair_add(rch, a, b, c, -1, d)
73# define my_rc_read_dictionary(a) rc_read_dictionary(rch, a)
62#else 74#else
63#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(rch,a,b,c,d,e,f) 75# define my_rc_conf_str(a) rc_conf_str(a)
64#endif 76# define my_rc_send_server(a, b) rc_send_server(a, b)
65#define my_rc_avpair_add(a,b,c,d) rc_avpair_add(rch,a,b,c,-1,d) 77# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(a, b, c, d, e, f)
66#define my_rc_read_dictionary(a) rc_read_dictionary(rch, a) 78# define my_rc_avpair_add(a, b, c, d) rc_avpair_add(a, b, c, d)
67#else 79# define my_rc_read_dictionary(a) rc_read_dictionary(a)
68#define my_rc_conf_str(a) rc_conf_str(a)
69#define my_rc_send_server(a,b) rc_send_server(a, b)
70#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(a,b,c,d,e,f)
71#define my_rc_avpair_add(a,b,c,d) rc_avpair_add(a, b, c, d)
72#define my_rc_read_dictionary(a) rc_read_dictionary(a)
73#endif 80#endif
74 81
75/* REJECT_RC is only defined in some version of radiusclient. It has 82/* REJECT_RC is only defined in some version of radiusclient. It has
76 * been reported from radiusclient-ng 0.5.6 on FreeBSD 7.2-RELEASE */ 83 * been reported from radiusclient-ng 0.5.6 on FreeBSD 7.2-RELEASE */
77#ifndef REJECT_RC 84#ifndef REJECT_RC
78#define REJECT_RC BADRESP_RC 85# define REJECT_RC BADRESP_RC
79#endif 86#endif
80 87
81static int my_rc_read_config(char * /*a*/); 88static int my_rc_read_config(char * /*a*/, rc_handle ** /*rch*/);
82
83#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
84static rc_handle *rch = NULL;
85#endif
86 89
87static char *server = NULL;
88static char *username = NULL;
89static char *password = NULL;
90static char *nasid = NULL;
91static char *nasipaddress = NULL;
92static char *expect = NULL;
93static char *config_file = NULL;
94static unsigned short port = PW_AUTH_UDP_PORT;
95static int retries = 1;
96static bool verbose = false; 90static bool verbose = false;
97 91
98/****************************************************************************** 92/******************************************************************************
@@ -148,149 +142,171 @@ Please note that all tags must be lowercase to use the DocBook XML DTD.
148-@@ 142-@@
149******************************************************************************/ 143******************************************************************************/
150 144
145int main(int argc, char **argv) {
146 setlocale(LC_ALL, "");
147 bindtextdomain(PACKAGE, LOCALEDIR);
148 textdomain(PACKAGE);
151 149
150 /* Parse extra opts if any */
151 argv = np_extra_opts(&argc, argv, progname);
152
153 check_radius_config_wrapper tmp_config = process_arguments(argc, argv);
154
155 if (tmp_config.errorcode == ERROR) {
156 usage4(_("Could not parse arguments"));
157 }
158
159 check_radius_config config = tmp_config.config;
160
161#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || \
162 defined(HAVE_LIBRADCLI)
163 rc_handle *rch = NULL;
164#endif
165
166 char *str = strdup("dictionary");
167 if ((config.config_file && my_rc_read_config(config.config_file, &rch)) ||
168 my_rc_read_dictionary(my_rc_conf_str(str))) {
169 die(STATE_UNKNOWN, _("Config file error\n"));
170 }
171
172 uint32_t service = PW_AUTHENTICATE_ONLY;
173
174 SEND_DATA data;
175 memset(&data, 0, sizeof(data));
176 if (!(my_rc_avpair_add(&data.send_pairs, PW_SERVICE_TYPE, &service, 0) &&
177 my_rc_avpair_add(&data.send_pairs, PW_USER_NAME, config.username, 0) &&
178 my_rc_avpair_add(&data.send_pairs, PW_USER_PASSWORD, config.password, 0))) {
179 die(STATE_UNKNOWN, _("Out of Memory?\n"));
180 }
181
182 if (config.nas_id != NULL) {
183 if (!(my_rc_avpair_add(&data.send_pairs, PW_NAS_IDENTIFIER, config.nas_id, 0))) {
184 die(STATE_UNKNOWN, _("Invalid NAS-Identifier\n"));
185 }
186 }
152 187
153int
154main (int argc, char **argv)
155{
156 struct sockaddr_storage ss;
157 char name[HOST_NAME_MAX]; 188 char name[HOST_NAME_MAX];
189 if (config.nas_ip_address == NULL) {
190 if (gethostname(name, sizeof(name)) != 0) {
191 die(STATE_UNKNOWN, _("gethostname() failed!\n"));
192 }
193 config.nas_ip_address = name;
194 }
195
196 struct sockaddr_storage radius_server_socket;
197 if (!dns_lookup(config.nas_ip_address, &radius_server_socket, AF_UNSPEC)) {
198 die(STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
199 }
200
201 uint32_t client_id = ntohl(((struct sockaddr_in *)&radius_server_socket)->sin_addr.s_addr);
202 if (my_rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL) {
203 die(STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
204 }
205
206 my_rc_buildreq(&data, PW_ACCESS_REQUEST, config.server, config.port, (int)timeout_interval,
207 config.retries);
208
158#ifdef RC_BUFFER_LEN 209#ifdef RC_BUFFER_LEN
159 char msg[RC_BUFFER_LEN]; 210 char msg[RC_BUFFER_LEN];
160#else 211#else
161 char msg[BUFFER_LEN]; 212 char msg[BUFFER_LEN];
162#endif 213#endif
163 SEND_DATA data;
164 int result = STATE_UNKNOWN;
165 uint32_t client_id, service;
166 char *str;
167 214
168 setlocale (LC_ALL, ""); 215 int result = my_rc_send_server(&data, msg);
169 bindtextdomain (PACKAGE, LOCALEDIR); 216 rc_avpair_free(data.send_pairs);
170 textdomain (PACKAGE); 217 if (data.receive_pairs) {
171 218 rc_avpair_free(data.receive_pairs);
172 /* Parse extra opts if any */ 219 }
173 argv=np_extra_opts (&argc, argv, progname);
174 220
175 if (process_arguments (argc, argv) == ERROR) 221 if (result == TIMEOUT_RC) {
176 usage4 (_("Could not parse arguments")); 222 printf("Timeout\n");
223 exit(STATE_CRITICAL);
224 }
177 225
178 str = strdup ("dictionary"); 226 if (result == ERROR_RC) {
179 if ((config_file && my_rc_read_config (config_file)) || 227 printf(_("Auth Error\n"));
180 my_rc_read_dictionary (my_rc_conf_str (str))) 228 exit(STATE_CRITICAL);
181 die (STATE_UNKNOWN, _("Config file error\n")); 229 }
182 230
183 service = PW_AUTHENTICATE_ONLY; 231 if (result == REJECT_RC) {
232 printf(_("Auth Failed\n"));
233 exit(STATE_WARNING);
234 }
184 235
185 memset (&data, 0, sizeof(data)); 236 if (result == BADRESP_RC) {
186 if (!(my_rc_avpair_add (&data.send_pairs, PW_SERVICE_TYPE, &service, 0) && 237 printf(_("Bad Response\n"));
187 my_rc_avpair_add (&data.send_pairs, PW_USER_NAME, username, 0) && 238 exit(STATE_WARNING);
188 my_rc_avpair_add (&data.send_pairs, PW_USER_PASSWORD, password, 0) 239 }
189 ))
190 die (STATE_UNKNOWN, _("Out of Memory?\n"));
191 240
192 if (nasid != NULL) { 241 if (config.expect && !strstr(msg, config.expect)) {
193 if (!(my_rc_avpair_add (&data.send_pairs, PW_NAS_IDENTIFIER, nasid, 0))) 242 printf("%s\n", msg);
194 die (STATE_UNKNOWN, _("Invalid NAS-Identifier\n")); 243 exit(STATE_WARNING);
195 } 244 }
196 245
197 if (nasipaddress == NULL) { 246 if (result == OK_RC) {
198 if (gethostname (name, sizeof(name)) != 0) 247 printf(_("Auth OK\n"));
199 die (STATE_UNKNOWN, _("gethostname() failed!\n")); 248 exit(STATE_OK);
200 nasipaddress = name;
201 } 249 }
202 if (!dns_lookup (nasipaddress, &ss, AF_INET)) /* TODO: Support IPv6. */ 250
203 die (STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
204 client_id = ntohl (((struct sockaddr_in *)&ss)->sin_addr.s_addr);
205 if (my_rc_avpair_add (&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL)
206 die (STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
207
208 my_rc_buildreq (&data, PW_ACCESS_REQUEST, server, port, (int)timeout_interval,
209 retries);
210
211 result = my_rc_send_server (&data, msg);
212 rc_avpair_free (data.send_pairs);
213 if (data.receive_pairs)
214 rc_avpair_free (data.receive_pairs);
215
216 if (result == TIMEOUT_RC)
217 die (STATE_CRITICAL, _("Timeout\n"));
218 if (result == ERROR_RC)
219 die (STATE_CRITICAL, _("Auth Error\n"));
220 if (result == REJECT_RC)
221 die (STATE_WARNING, _("Auth Failed\n"));
222 if (result == BADRESP_RC)
223 die (STATE_WARNING, _("Bad Response\n"));
224 if (expect && !strstr (msg, expect))
225 die (STATE_WARNING, "%s\n", msg);
226 if (result == OK_RC)
227 die (STATE_OK, _("Auth OK\n"));
228 (void)snprintf(msg, sizeof(msg), _("Unexpected result code %d"), result); 251 (void)snprintf(msg, sizeof(msg), _("Unexpected result code %d"), result);
229 die (STATE_UNKNOWN, "%s\n", msg); 252 printf("%s\n", msg);
253 exit(STATE_UNKNOWN);
230} 254}
231 255
232
233
234/* process command-line arguments */ 256/* process command-line arguments */
235int 257check_radius_config_wrapper process_arguments(int argc, char **argv) {
236process_arguments (int argc, char **argv)
237{
238 int c;
239
240 int option = 0;
241 static struct option longopts[] = { 258 static struct option longopts[] = {
242 {"hostname", required_argument, 0, 'H'}, 259 {"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'P'},
243 {"port", required_argument, 0, 'P'}, 260 {"username", required_argument, 0, 'u'}, {"password", required_argument, 0, 'p'},
244 {"username", required_argument, 0, 'u'}, 261 {"nas-id", required_argument, 0, 'n'}, {"nas-ip-address", required_argument, 0, 'N'},
245 {"password", required_argument, 0, 'p'}, 262 {"filename", required_argument, 0, 'F'}, {"expect", required_argument, 0, 'e'},
246 {"nas-id", required_argument, 0, 'n'}, 263 {"retries", required_argument, 0, 'r'}, {"timeout", required_argument, 0, 't'},
247 {"nas-ip-address", required_argument, 0, 'N'}, 264 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
248 {"filename", required_argument, 0, 'F'}, 265 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
249 {"expect", required_argument, 0, 'e'}, 266
250 {"retries", required_argument, 0, 'r'}, 267 check_radius_config_wrapper result = {
251 {"timeout", required_argument, 0, 't'}, 268 .errorcode = OK,
252 {"verbose", no_argument, 0, 'v'}, 269 .config = check_radius_config_init(),
253 {"version", no_argument, 0, 'V'},
254 {"help", no_argument, 0, 'h'},
255 {0, 0, 0, 0}
256 }; 270 };
257 271
258 while (1) { 272 while (true) {
259 c = getopt_long (argc, argv, "+hVvH:P:F:u:p:n:N:t:r:e:", longopts, 273 int option = 0;
260 &option); 274 int option_index = getopt_long(argc, argv, "+hVvH:P:F:u:p:n:N:t:r:e:", longopts, &option);
261 275
262 if (c == -1 || c == EOF || c == 1) 276 if (option_index == -1 || option_index == EOF || option_index == 1) {
263 break; 277 break;
278 }
264 279
265 switch (c) { 280 switch (option_index) {
266 case '?': /* print short usage statement if args not parsable */ 281 case '?': /* print short usage statement if args not parsable */
267 usage5 (); 282 usage5();
268 case 'h': /* help */ 283 case 'h': /* help */
269 print_help (); 284 print_help();
270 exit (STATE_UNKNOWN); 285 exit(STATE_UNKNOWN);
271 case 'V': /* version */ 286 case 'V': /* version */
272 print_revision (progname, NP_VERSION); 287 print_revision(progname, NP_VERSION);
273 exit (STATE_UNKNOWN); 288 exit(STATE_UNKNOWN);
274 case 'v': /* verbose mode */ 289 case 'v': /* verbose mode */
275 verbose = true; 290 verbose = true;
276 break; 291 break;
277 case 'H': /* hostname */ 292 case 'H': /* hostname */
278 if (!is_host (optarg)) { 293 if (!is_host(optarg)) {
279 usage2 (_("Invalid hostname/address"), optarg); 294 usage2(_("Invalid hostname/address"), optarg);
280 } 295 }
281 server = optarg; 296 result.config.server = optarg;
282 break; 297 break;
283 case 'P': /* port */ 298 case 'P': /* port */
284 if (is_intnonneg (optarg)) 299 if (is_intnonneg(optarg)) {
285 port = (unsigned short)atoi (optarg); 300 result.config.port = (unsigned short)atoi(optarg);
286 else 301 } else {
287 usage4 (_("Port must be a positive integer")); 302 usage4(_("Port must be a positive integer"));
303 }
288 break; 304 break;
289 case 'u': /* username */ 305 case 'u': /* username */
290 username = optarg; 306 result.config.username = optarg;
291 break; 307 break;
292 case 'p': /* password */ 308 case 'p': /* password */
293 password = strdup(optarg); 309 result.config.password = strdup(optarg);
294 310
295 /* Delete the password from process list */ 311 /* Delete the password from process list */
296 while (*optarg != '\0') { 312 while (*optarg != '\0') {
@@ -298,119 +314,118 @@ process_arguments (int argc, char **argv)
298 optarg++; 314 optarg++;
299 } 315 }
300 break; 316 break;
301 case 'n': /* nas id */ 317 case 'n': /* nas id */
302 nasid = optarg; 318 result.config.nas_id = optarg;
303 break; 319 break;
304 case 'N': /* nas ip address */ 320 case 'N': /* nas ip address */
305 nasipaddress = optarg; 321 result.config.nas_ip_address = optarg;
306 break; 322 break;
307 case 'F': /* configuration file */ 323 case 'F': /* configuration file */
308 config_file = optarg; 324 result.config.config_file = optarg;
309 break; 325 break;
310 case 'e': /* expect */ 326 case 'e': /* expect */
311 expect = optarg; 327 result.config.expect = optarg;
312 break; 328 break;
313 case 'r': /* retries */ 329 case 'r': /* retries */
314 if (is_intpos (optarg)) 330 if (is_intpos(optarg)) {
315 retries = atoi (optarg); 331 result.config.retries = atoi(optarg);
316 else 332 } else {
317 usage4 (_("Number of retries must be a positive integer")); 333 usage4(_("Number of retries must be a positive integer"));
334 }
318 break; 335 break;
319 case 't': /* timeout */ 336 case 't': /* timeout */
320 if (is_intpos (optarg)) 337 if (is_intpos(optarg)) {
321 timeout_interval = (unsigned)atoi (optarg); 338 timeout_interval = (unsigned)atoi(optarg);
322 else 339 } else {
323 usage2 (_("Timeout interval must be a positive integer"), optarg); 340 usage2(_("Timeout interval must be a positive integer"), optarg);
341 }
324 break; 342 break;
325 } 343 }
326 } 344 }
327 345
328 if (server == NULL) 346 if (result.config.server == NULL) {
329 usage4 (_("Hostname was not supplied")); 347 usage4(_("Hostname was not supplied"));
330 if (username == NULL) 348 }
331 usage4 (_("User not specified")); 349 if (result.config.username == NULL) {
332 if (password == NULL) 350 usage4(_("User not specified"));
333 usage4 (_("Password not specified")); 351 }
334 if (config_file == NULL) 352 if (result.config.password == NULL) {
335 usage4 (_("Configuration file not specified")); 353 usage4(_("Password not specified"));
354 }
355 if (result.config.config_file == NULL) {
356 usage4(_("Configuration file not specified"));
357 }
336 358
337 return OK; 359 return result;
338} 360}
339 361
340 362void print_help(void) {
341
342void
343print_help (void)
344{
345 char *myport; 363 char *myport;
346 xasprintf (&myport, "%d", PW_AUTH_UDP_PORT); 364 xasprintf(&myport, "%d", PW_AUTH_UDP_PORT);
347 365
348 print_revision (progname, NP_VERSION); 366 print_revision(progname, NP_VERSION);
349 367
350 printf ("Copyright (c) 1999 Robert August Vincent II\n"); 368 printf("Copyright (c) 1999 Robert August Vincent II\n");
351 printf (COPYRIGHT, copyright, email); 369 printf(COPYRIGHT, copyright, email);
352 370
353 printf("%s\n", _("Tests to see if a RADIUS server is accepting connections.")); 371 printf("%s\n", _("Tests to see if a RADIUS server is accepting connections."));
354 372
355 printf ("\n\n"); 373 printf("\n\n");
356 374
357 print_usage (); 375 print_usage();
358 376
359 printf (UT_HELP_VRSN); 377 printf(UT_HELP_VRSN);
360 printf (UT_EXTRA_OPTS); 378 printf(UT_EXTRA_OPTS);
361 379
362 printf (UT_HOST_PORT, 'P', myport); 380 printf(UT_HOST_PORT, 'P', myport);
363 381
364 printf (" %s\n", "-u, --username=STRING"); 382 printf(" %s\n", "-u, --username=STRING");
365 printf (" %s\n", _("The user to authenticate")); 383 printf(" %s\n", _("The user to authenticate"));
366 printf (" %s\n", "-p, --password=STRING"); 384 printf(" %s\n", "-p, --password=STRING");
367 printf (" %s\n", _("Password for authentication (SECURITY RISK)")); 385 printf(" %s\n", _("Password for authentication (SECURITY RISK)"));
368 printf (" %s\n", "-n, --nas-id=STRING"); 386 printf(" %s\n", "-n, --nas-id=STRING");
369 printf (" %s\n", _("NAS identifier")); 387 printf(" %s\n", _("NAS identifier"));
370 printf (" %s\n", "-N, --nas-ip-address=STRING"); 388 printf(" %s\n", "-N, --nas-ip-address=STRING");
371 printf (" %s\n", _("NAS IP Address")); 389 printf(" %s\n", _("NAS IP Address"));
372 printf (" %s\n", "-F, --filename=STRING"); 390 printf(" %s\n", "-F, --filename=STRING");
373 printf (" %s\n", _("Configuration file")); 391 printf(" %s\n", _("Configuration file"));
374 printf (" %s\n", "-e, --expect=STRING"); 392 printf(" %s\n", "-e, --expect=STRING");
375 printf (" %s\n", _("Response string to expect from the server")); 393 printf(" %s\n", _("Response string to expect from the server"));
376 printf (" %s\n", "-r, --retries=INTEGER"); 394 printf(" %s\n", "-r, --retries=INTEGER");
377 printf (" %s\n", _("Number of times to retry a failed connection")); 395 printf(" %s\n", _("Number of times to retry a failed connection"));
378 396
379 printf (UT_CONN_TIMEOUT, timeout_interval); 397 printf(UT_CONN_TIMEOUT, timeout_interval);
380 398
381 printf ("\n"); 399 printf("\n");
382 printf ("%s\n", _("This plugin tests a RADIUS server to see if it is accepting connections.")); 400 printf("%s\n", _("This plugin tests a RADIUS server to see if it is accepting connections."));
383 printf ("%s\n", _("The server to test must be specified in the invocation, as well as a user")); 401 printf("%s\n", _("The server to test must be specified in the invocation, as well as a user"));
384 printf ("%s\n", _("name and password. A configuration file must be present. The format of")); 402 printf("%s\n", _("name and password. A configuration file must be present. The format of"));
385 printf ("%s\n", _("the configuration file is described in the radiusclient library sources.")); 403 printf("%s\n", _("the configuration file is described in the radiusclient library sources."));
386 printf ("%s\n", _("The password option presents a substantial security issue because the")); 404 printf("%s\n", _("The password option presents a substantial security issue because the"));
387 printf ("%s\n", _("password can possibly be determined by careful watching of the command line")); 405 printf("%s\n",
388 printf ("%s\n", _("in a process listing. This risk is exacerbated because the plugin will")); 406 _("password can possibly be determined by careful watching of the command line"));
389 printf ("%s\n", _("typically be executed at regular predictable intervals. Please be sure that")); 407 printf("%s\n", _("in a process listing. This risk is exacerbated because the plugin will"));
390 printf ("%s\n", _("the password used does not allow access to sensitive system resources.")); 408 printf("%s\n",
391 409 _("typically be executed at regular predictable intervals. Please be sure that"));
392 printf (UT_SUPPORT); 410 printf("%s\n", _("the password used does not allow access to sensitive system resources."));
411
412 printf(UT_SUPPORT);
393} 413}
394 414
395 415void print_usage(void) {
396 416 printf("%s\n", _("Usage:"));
397void 417 printf("%s -H host -F config_file -u username -p password\n\
398print_usage (void)
399{
400 printf ("%s\n", _("Usage:"));
401 printf ("%s -H host -F config_file -u username -p password\n\
402 [-P port] [-t timeout] [-r retries] [-e expect]\n\ 418 [-P port] [-t timeout] [-r retries] [-e expect]\n\
403 [-n nas-id] [-N nas-ip-addr]\n", progname); 419 [-n nas-id] [-N nas-ip-addr]\n",
420 progname);
404} 421}
405 422
406 423int my_rc_read_config(char *config_file_name, rc_handle **rch) {
407 424#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || \
408int my_rc_read_config(char * a) 425 defined(HAVE_LIBRADCLI)
409{ 426 *rch = rc_read_config(config_file_name);
410#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
411 rch = rc_read_config(a);
412 return (rch == NULL) ? 1 : 0; 427 return (rch == NULL) ? 1 : 0;
413#else 428#else
414 return rc_read_config(a); 429 return rc_read_config(config_file_name);
415#endif 430#endif
416} 431}
diff --git a/plugins/check_radius.d/config.h b/plugins/check_radius.d/config.h
new file mode 100644
index 00000000..b27d31e7
--- /dev/null
+++ b/plugins/check_radius.d/config.h
@@ -0,0 +1,42 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#if defined(HAVE_LIBRADCLI)
6# include <radcli/radcli.h>
7#elif defined(HAVE_LIBFREERADIUS_CLIENT)
8# include <freeradius-client.h>
9#elif defined(HAVE_LIBRADIUSCLIENT_NG)
10# include <radiusclient-ng.h>
11#else
12# include <radiusclient.h>
13#endif
14
15typedef struct {
16 char *server;
17 char *username;
18 char *password;
19 char *config_file;
20 char *nas_id;
21 char *nas_ip_address;
22 int retries;
23 unsigned short port;
24
25 char *expect;
26} check_radius_config;
27
28check_radius_config check_radius_config_init() {
29 check_radius_config tmp = {
30 .server = NULL,
31 .username = NULL,
32 .password = NULL,
33 .config_file = NULL,
34 .nas_id = NULL,
35 .nas_ip_address = NULL,
36 .retries = 1,
37 .port = PW_AUTH_UDP_PORT,
38
39 .expect = NULL,
40 };
41 return tmp;
42}
diff --git a/plugins/check_real.c b/plugins/check_real.c
index 369a88b1..66d07f8f 100644
--- a/plugins/check_real.c
+++ b/plugins/check_real.c
@@ -28,6 +28,8 @@
28 * 28 *
29 *****************************************************************************/ 29 *****************************************************************************/
30 30
31#include "states.h"
32#include <stdio.h>
31const char *progname = "check_real"; 33const char *progname = "check_real";
32const char *copyright = "2000-2024"; 34const char *copyright = "2000-2024";
33const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
@@ -35,27 +37,20 @@ const char *email = "devel@monitoring-plugins.org";
35#include "common.h" 37#include "common.h"
36#include "netutils.h" 38#include "netutils.h"
37#include "utils.h" 39#include "utils.h"
38 40#include "check_real.d/config.h"
39enum {
40 PORT = 554
41};
42 41
43#define EXPECT "RTSP/1." 42#define EXPECT "RTSP/1."
44#define URL "" 43#define URL ""
45 44
46static int process_arguments(int, char **); 45typedef struct {
46 int errorcode;
47 check_real_config config;
48} check_real_config_wrapper;
49static check_real_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50
47static void print_help(void); 51static void print_help(void);
48void print_usage(void); 52void print_usage(void);
49 53
50static int server_port = PORT;
51static char *server_address;
52static char *host_name;
53static char *server_url = NULL;
54static char *server_expect;
55static int warning_time = 0;
56static bool check_warning_time = false;
57static int critical_time = 0;
58static bool check_critical_time = false;
59static bool verbose = false; 54static bool verbose = false;
60 55
61int main(int argc, char **argv) { 56int main(int argc, char **argv) {
@@ -66,8 +61,12 @@ int main(int argc, char **argv) {
66 /* Parse extra opts if any */ 61 /* Parse extra opts if any */
67 argv = np_extra_opts(&argc, argv, progname); 62 argv = np_extra_opts(&argc, argv, progname);
68 63
69 if (process_arguments(argc, argv) == ERROR) 64 check_real_config_wrapper tmp_config = process_arguments(argc, argv);
65 if (tmp_config.errorcode == ERROR) {
70 usage4(_("Could not parse arguments")); 66 usage4(_("Could not parse arguments"));
67 }
68
69 const check_real_config config = tmp_config.config;
71 70
72 /* initialize alarm signal handling */ 71 /* initialize alarm signal handling */
73 signal(SIGALRM, socket_timeout_alarm_handler); 72 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -78,38 +77,52 @@ int main(int argc, char **argv) {
78 77
79 /* try to connect to the host at the given port number */ 78 /* try to connect to the host at the given port number */
80 int socket; 79 int socket;
81 if (my_tcp_connect(server_address, server_port, &socket) != STATE_OK) 80 if (my_tcp_connect(config.server_address, config.server_port, &socket) != STATE_OK) {
82 die(STATE_CRITICAL, _("Unable to connect to %s on port %d\n"), server_address, server_port); 81 die(STATE_CRITICAL, _("Unable to connect to %s on port %d\n"), config.server_address,
82 config.server_port);
83 }
83 84
84 /* Part I - Server Check */ 85 /* Part I - Server Check */
85 86
86 /* send the OPTIONS request */ 87 /* send the OPTIONS request */
87 char buffer[MAX_INPUT_BUFFER]; 88 char buffer[MAX_INPUT_BUFFER];
88 sprintf(buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", host_name, server_port); 89 sprintf(buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", config.host_name, config.server_port);
89 int result = send(socket, buffer, strlen(buffer), 0); 90 ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0);
91 if (sent_bytes == -1) {
92 die(STATE_CRITICAL, _("Sending options to %s failed\n"), config.host_name);
93 }
90 94
91 /* send the header sync */ 95 /* send the header sync */
92 sprintf(buffer, "CSeq: 1\r\n"); 96 sprintf(buffer, "CSeq: 1\r\n");
93 result = send(socket, buffer, strlen(buffer), 0); 97 sent_bytes = send(socket, buffer, strlen(buffer), 0);
98 if (sent_bytes == -1) {
99 die(STATE_CRITICAL, _("Sending header sync to %s failed\n"), config.host_name);
100 }
94 101
95 /* send a newline so the server knows we're done with the request */ 102 /* send a newline so the server knows we're done with the request */
96 sprintf(buffer, "\r\n"); 103 sprintf(buffer, "\r\n");
97 result = send(socket, buffer, strlen(buffer), 0); 104 sent_bytes = send(socket, buffer, strlen(buffer), 0);
105 if (sent_bytes == -1) {
106 die(STATE_CRITICAL, _("Sending newline to %s failed\n"), config.host_name);
107 }
98 108
99 /* watch for the REAL connection string */ 109 /* watch for the REAL connection string */
100 result = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0); 110 ssize_t received_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
101 111
102 /* return a CRITICAL status if we couldn't read any data */ 112 /* return a CRITICAL status if we couldn't read any data */
103 if (result == -1) 113 if (received_bytes == -1) {
104 die(STATE_CRITICAL, _("No data received from %s\n"), host_name); 114 die(STATE_CRITICAL, _("No data received from %s\n"), config.host_name);
115 }
105 116
117 mp_state_enum result = STATE_OK;
106 char *status_line = NULL; 118 char *status_line = NULL;
107 /* make sure we find the response we are looking for */ 119 /* make sure we find the response we are looking for */
108 if (!strstr(buffer, server_expect)) { 120 if (!strstr(buffer, config.server_expect)) {
109 if (server_port == PORT) 121 if (config.server_port == PORT) {
110 printf("%s\n", _("Invalid REAL response received from host")); 122 printf("%s\n", _("Invalid REAL response received from host"));
111 else 123 } else {
112 printf(_("Invalid REAL response received from host on port %d\n"), server_port); 124 printf(_("Invalid REAL response received from host on port %d\n"), config.server_port);
125 }
113 } else { 126 } else {
114 /* else we got the REAL string, so check the return code */ 127 /* else we got the REAL string, so check the return code */
115 128
@@ -117,69 +130,81 @@ int main(int argc, char **argv) {
117 130
118 result = STATE_OK; 131 result = STATE_OK;
119 132
120 status_line = (char *)strtok(buffer, "\n"); 133 status_line = strtok(buffer, "\n");
121 134
122 if (strstr(status_line, "200")) 135 if (strstr(status_line, "200")) {
123 result = STATE_OK; 136 result = STATE_OK;
137 }
124 138
125 /* client errors result in a warning state */ 139 /* client errors result in a warning state */
126 else if (strstr(status_line, "400")) 140 else if (strstr(status_line, "400")) {
127 result = STATE_WARNING; 141 result = STATE_WARNING;
128 else if (strstr(status_line, "401")) 142 } else if (strstr(status_line, "401")) {
129 result = STATE_WARNING; 143 result = STATE_WARNING;
130 else if (strstr(status_line, "402")) 144 } else if (strstr(status_line, "402")) {
131 result = STATE_WARNING; 145 result = STATE_WARNING;
132 else if (strstr(status_line, "403")) 146 } else if (strstr(status_line, "403")) {
133 result = STATE_WARNING; 147 result = STATE_WARNING;
134 else if (strstr(status_line, "404")) 148 } else if (strstr(status_line, "404")) {
135 result = STATE_WARNING; 149 result = STATE_WARNING;
136 150 } else if (strstr(status_line, "500")) {
137 /* server errors result in a critical state */ 151 /* server errors result in a critical state */
138 else if (strstr(status_line, "500"))
139 result = STATE_CRITICAL; 152 result = STATE_CRITICAL;
140 else if (strstr(status_line, "501")) 153 } else if (strstr(status_line, "501")) {
141 result = STATE_CRITICAL; 154 result = STATE_CRITICAL;
142 else if (strstr(status_line, "502")) 155 } else if (strstr(status_line, "502")) {
143 result = STATE_CRITICAL; 156 result = STATE_CRITICAL;
144 else if (strstr(status_line, "503")) 157 } else if (strstr(status_line, "503")) {
145 result = STATE_CRITICAL; 158 result = STATE_CRITICAL;
146 159 } else {
147 else
148 result = STATE_UNKNOWN; 160 result = STATE_UNKNOWN;
161 }
149 } 162 }
150 163
151 /* Part II - Check stream exists and is ok */ 164 /* Part II - Check stream exists and is ok */
152 if ((result == STATE_OK) && (server_url != NULL)) { 165 if ((result == STATE_OK) && (config.server_url != NULL)) {
153 166
154 /* Part I - Server Check */ 167 /* Part I - Server Check */
155 168
156 /* send the DESCRIBE request */ 169 /* send the DESCRIBE request */
157 sprintf(buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", host_name, server_port, server_url); 170 sprintf(buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", config.host_name,
158 result = send(socket, buffer, strlen(buffer), 0); 171 config.server_port, config.server_url);
172
173 ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0);
174 if (sent_bytes == -1) {
175 die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
176 }
159 177
160 /* send the header sync */ 178 /* send the header sync */
161 sprintf(buffer, "CSeq: 2\r\n"); 179 sprintf(buffer, "CSeq: 2\r\n");
162 result = send(socket, buffer, strlen(buffer), 0); 180 sent_bytes = send(socket, buffer, strlen(buffer), 0);
181 if (sent_bytes == -1) {
182 die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
183 }
163 184
164 /* send a newline so the server knows we're done with the request */ 185 /* send a newline so the server knows we're done with the request */
165 sprintf(buffer, "\r\n"); 186 sprintf(buffer, "\r\n");
166 result = send(socket, buffer, strlen(buffer), 0); 187 sent_bytes = send(socket, buffer, strlen(buffer), 0);
188 if (sent_bytes == -1) {
189 die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
190 }
167 191
168 /* watch for the REAL connection string */ 192 /* watch for the REAL connection string */
169 result = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0); 193 ssize_t recv_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
170 buffer[result] = '\0'; /* null terminate received buffer */ 194 if (recv_bytes == -1) {
171 195 /* return a CRITICAL status if we couldn't read any data */
172 /* return a CRITICAL status if we couldn't read any data */
173 if (result == -1) {
174 printf(_("No data received from host\n")); 196 printf(_("No data received from host\n"));
175 result = STATE_CRITICAL; 197 result = STATE_CRITICAL;
176 } else { 198 } else {
199 buffer[result] = '\0'; /* null terminate received buffer */
177 /* make sure we find the response we are looking for */ 200 /* make sure we find the response we are looking for */
178 if (!strstr(buffer, server_expect)) { 201 if (!strstr(buffer, config.server_expect)) {
179 if (server_port == PORT) 202 if (config.server_port == PORT) {
180 printf("%s\n", _("Invalid REAL response received from host")); 203 printf("%s\n", _("Invalid REAL response received from host"));
181 else 204 } else {
182 printf(_("Invalid REAL response received from host on port %d\n"), server_port); 205 printf(_("Invalid REAL response received from host on port %d\n"),
206 config.server_port);
207 }
183 } else { 208 } else {
184 209
185 /* else we got the REAL string, so check the return code */ 210 /* else we got the REAL string, so check the return code */
@@ -188,51 +213,57 @@ int main(int argc, char **argv) {
188 213
189 result = STATE_OK; 214 result = STATE_OK;
190 215
191 status_line = (char *)strtok(buffer, "\n"); 216 status_line = strtok(buffer, "\n");
192 217
193 if (strstr(status_line, "200")) 218 if (strstr(status_line, "200")) {
194 result = STATE_OK; 219 result = STATE_OK;
220 }
195 221
196 /* client errors result in a warning state */ 222 /* client errors result in a warning state */
197 else if (strstr(status_line, "400")) 223 else if (strstr(status_line, "400")) {
198 result = STATE_WARNING; 224 result = STATE_WARNING;
199 else if (strstr(status_line, "401")) 225 } else if (strstr(status_line, "401")) {
200 result = STATE_WARNING; 226 result = STATE_WARNING;
201 else if (strstr(status_line, "402")) 227 } else if (strstr(status_line, "402")) {
202 result = STATE_WARNING; 228 result = STATE_WARNING;
203 else if (strstr(status_line, "403")) 229 } else if (strstr(status_line, "403")) {
204 result = STATE_WARNING; 230 result = STATE_WARNING;
205 else if (strstr(status_line, "404")) 231 } else if (strstr(status_line, "404")) {
206 result = STATE_WARNING; 232 result = STATE_WARNING;
233 }
207 234
208 /* server errors result in a critical state */ 235 /* server errors result in a critical state */
209 else if (strstr(status_line, "500")) 236 else if (strstr(status_line, "500")) {
210 result = STATE_CRITICAL; 237 result = STATE_CRITICAL;
211 else if (strstr(status_line, "501")) 238 } else if (strstr(status_line, "501")) {
212 result = STATE_CRITICAL; 239 result = STATE_CRITICAL;
213 else if (strstr(status_line, "502")) 240 } else if (strstr(status_line, "502")) {
214 result = STATE_CRITICAL; 241 result = STATE_CRITICAL;
215 else if (strstr(status_line, "503")) 242 } else if (strstr(status_line, "503")) {
216 result = STATE_CRITICAL; 243 result = STATE_CRITICAL;
244 }
217 245
218 else 246 else {
219 result = STATE_UNKNOWN; 247 result = STATE_UNKNOWN;
248 }
220 } 249 }
221 } 250 }
222 } 251 }
223 252
224 /* Return results */ 253 /* Return results */
225 if (result == STATE_OK) { 254 if (result == STATE_OK) {
226 255 if (config.check_critical_time && (end_time - start_time) > config.critical_time) {
227 if (check_critical_time && (end_time - start_time) > critical_time)
228 result = STATE_CRITICAL; 256 result = STATE_CRITICAL;
229 else if (check_warning_time && (end_time - start_time) > warning_time) 257 } else if (config.check_warning_time && (end_time - start_time) > config.warning_time) {
230 result = STATE_WARNING; 258 result = STATE_WARNING;
259 }
231 260
232 /* Put some HTML in here to create a dynamic link */ 261 /* Put some HTML in here to create a dynamic link */
233 printf(_("REAL %s - %d second response time\n"), state_text(result), (int)(end_time - start_time)); 262 printf(_("REAL %s - %d second response time\n"), state_text(result),
234 } else 263 (int)(end_time - start_time));
264 } else {
235 printf("%s\n", status_line); 265 printf("%s\n", status_line);
266 }
236 267
237 /* close the connection */ 268 /* close the connection */
238 close(socket); 269 close(socket);
@@ -240,73 +271,83 @@ int main(int argc, char **argv) {
240 /* reset the alarm */ 271 /* reset the alarm */
241 alarm(0); 272 alarm(0);
242 273
243 return result; 274 exit(result);
244} 275}
245 276
246/* process command-line arguments */ 277/* process command-line arguments */
247int process_arguments(int argc, char **argv) { 278check_real_config_wrapper process_arguments(int argc, char **argv) {
248 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, {"IPaddress", required_argument, 0, 'I'}, 279 static struct option longopts[] = {
249 {"expect", required_argument, 0, 'e'}, {"url", required_argument, 0, 'u'}, 280 {"hostname", required_argument, 0, 'H'}, {"IPaddress", required_argument, 0, 'I'},
250 {"port", required_argument, 0, 'p'}, {"critical", required_argument, 0, 'c'}, 281 {"expect", required_argument, 0, 'e'}, {"url", required_argument, 0, 'u'},
251 {"warning", required_argument, 0, 'w'}, {"timeout", required_argument, 0, 't'}, 282 {"port", required_argument, 0, 'p'}, {"critical", required_argument, 0, 'c'},
252 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, 283 {"warning", required_argument, 0, 'w'}, {"timeout", required_argument, 0, 't'},
253 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}}; 284 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
254 285 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
255 if (argc < 2) 286
256 return ERROR; 287 check_real_config_wrapper result = {
288 .errorcode = OK,
289 .config = check_real_config_init(),
290 };
291
292 if (argc < 2) {
293 result.errorcode = ERROR;
294 return result;
295 }
257 296
258 for (int i = 1; i < argc; i++) { 297 for (int i = 1; i < argc; i++) {
259 if (strcmp("-to", argv[i]) == 0) 298 if (strcmp("-to", argv[i]) == 0) {
260 strcpy(argv[i], "-t"); 299 strcpy(argv[i], "-t");
261 else if (strcmp("-wt", argv[i]) == 0) 300 } else if (strcmp("-wt", argv[i]) == 0) {
262 strcpy(argv[i], "-w"); 301 strcpy(argv[i], "-w");
263 else if (strcmp("-ct", argv[i]) == 0) 302 } else if (strcmp("-ct", argv[i]) == 0) {
264 strcpy(argv[i], "-c"); 303 strcpy(argv[i], "-c");
304 }
265 } 305 }
266 306
267 int option_char;
268 while (true) { 307 while (true) {
269 int option = 0; 308 int option = 0;
270 option_char = getopt_long(argc, argv, "+hvVI:H:e:u:p:w:c:t:", longopts, &option); 309 int option_char = getopt_long(argc, argv, "+hvVI:H:e:u:p:w:c:t:", longopts, &option);
271 310
272 if (option_char == -1 || option_char == EOF) 311 if (option_char == -1 || option_char == EOF) {
273 break; 312 break;
313 }
274 314
275 switch (option_char) { 315 switch (option_char) {
276 case 'I': /* hostname */ 316 case 'I': /* hostname */
277 case 'H': /* hostname */ 317 case 'H': /* hostname */
278 if (server_address) 318 if (result.config.server_address) {
279 break; 319 break;
280 else if (is_host(optarg)) 320 } else if (is_host(optarg)) {
281 server_address = optarg; 321 result.config.server_address = optarg;
282 else 322 } else {
283 usage2(_("Invalid hostname/address"), optarg); 323 usage2(_("Invalid hostname/address"), optarg);
324 }
284 break; 325 break;
285 case 'e': /* string to expect in response header */ 326 case 'e': /* string to expect in response header */
286 server_expect = optarg; 327 result.config.server_expect = optarg;
287 break; 328 break;
288 case 'u': /* server URL */ 329 case 'u': /* server URL */
289 server_url = optarg; 330 result.config.server_url = optarg;
290 break; 331 break;
291 case 'p': /* port */ 332 case 'p': /* port */
292 if (is_intpos(optarg)) { 333 if (is_intpos(optarg)) {
293 server_port = atoi(optarg); 334 result.config.server_port = atoi(optarg);
294 } else { 335 } else {
295 usage4(_("Port must be a positive integer")); 336 usage4(_("Port must be a positive integer"));
296 } 337 }
297 break; 338 break;
298 case 'w': /* warning time threshold */ 339 case 'w': /* warning time threshold */
299 if (is_intnonneg(optarg)) { 340 if (is_intnonneg(optarg)) {
300 warning_time = atoi(optarg); 341 result.config.warning_time = atoi(optarg);
301 check_warning_time = true; 342 result.config.check_warning_time = true;
302 } else { 343 } else {
303 usage4(_("Warning time must be a positive integer")); 344 usage4(_("Warning time must be a positive integer"));
304 } 345 }
305 break; 346 break;
306 case 'c': /* critical time threshold */ 347 case 'c': /* critical time threshold */
307 if (is_intnonneg(optarg)) { 348 if (is_intnonneg(optarg)) {
308 critical_time = atoi(optarg); 349 result.config.critical_time = atoi(optarg);
309 check_critical_time = true; 350 result.config.check_critical_time = true;
310 } else { 351 } else {
311 usage4(_("Critical time must be a positive integer")); 352 usage4(_("Critical time must be a positive integer"));
312 } 353 }
@@ -332,25 +373,28 @@ int process_arguments(int argc, char **argv) {
332 } 373 }
333 } 374 }
334 375
335 option_char = optind; 376 int option_char = optind;
336 if (server_address == NULL && argc > option_char) { 377 if (result.config.server_address == NULL && argc > option_char) {
337 if (is_host(argv[option_char])) { 378 if (is_host(argv[option_char])) {
338 server_address = argv[option_char++]; 379 result.config.server_address = argv[option_char++];
339 } else { 380 } else {
340 usage2(_("Invalid hostname/address"), argv[option_char]); 381 usage2(_("Invalid hostname/address"), argv[option_char]);
341 } 382 }
342 } 383 }
343 384
344 if (server_address == NULL) 385 if (result.config.server_address == NULL) {
345 usage4(_("You must provide a server to check")); 386 usage4(_("You must provide a server to check"));
387 }
346 388
347 if (host_name == NULL) 389 if (result.config.host_name == NULL) {
348 host_name = strdup(server_address); 390 result.config.host_name = strdup(result.config.server_address);
391 }
349 392
350 if (server_expect == NULL) 393 if (result.config.server_expect == NULL) {
351 server_expect = strdup(EXPECT); 394 result.config.server_expect = strdup(EXPECT);
395 }
352 396
353 return OK; 397 return result;
354} 398}
355 399
356void print_help(void) { 400void print_help(void) {
@@ -388,7 +432,8 @@ void print_help(void) {
388 printf("%s\n", _("This plugin will attempt to open an RTSP connection with the host.")); 432 printf("%s\n", _("This plugin will attempt to open an RTSP connection with the host."));
389 printf("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return")); 433 printf("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return"));
390 printf("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful connects,")); 434 printf("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful connects,"));
391 printf("%s\n", _("but incorrect response messages from the host result in STATE_WARNING return")); 435 printf("%s\n",
436 _("but incorrect response messages from the host result in STATE_WARNING return"));
392 printf("%s\n", _("values.")); 437 printf("%s\n", _("values."));
393 438
394 printf(UT_SUPPORT); 439 printf(UT_SUPPORT);
diff --git a/plugins/check_real.d/config.h b/plugins/check_real.d/config.h
new file mode 100644
index 00000000..c4663cf9
--- /dev/null
+++ b/plugins/check_real.d/config.h
@@ -0,0 +1,37 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6enum {
7 PORT = 554
8};
9
10typedef struct {
11 char *server_address;
12 char *host_name;
13 int server_port;
14 char *server_url;
15
16 char *server_expect;
17 int warning_time;
18 bool check_warning_time;
19 int critical_time;
20 bool check_critical_time;
21} check_real_config;
22
23check_real_config check_real_config_init() {
24 check_real_config tmp = {
25 .server_address = NULL,
26 .host_name = NULL,
27 .server_port = PORT,
28 .server_url = NULL,
29
30 .server_expect = NULL,
31 .warning_time = 0,
32 .check_warning_time = false,
33 .critical_time = 0,
34 .check_critical_time = false,
35 };
36 return tmp;
37}
diff --git a/plugins/check_smtp.c b/plugins/check_smtp.c
index 44b735f9..e8c35f58 100644
--- a/plugins/check_smtp.c
+++ b/plugins/check_smtp.c
@@ -28,20 +28,24 @@
28 * 28 *
29 *****************************************************************************/ 29 *****************************************************************************/
30 30
31const char *progname = "check_smtp";
32const char *copyright = "2000-2024";
33const char *email = "devel@monitoring-plugins.org";
34
35#include "common.h" 31#include "common.h"
36#include "netutils.h" 32#include "netutils.h"
33#include "output.h"
34#include "perfdata.h"
35#include "thresholds.h"
37#include "utils.h" 36#include "utils.h"
38#include "base64.h" 37#include "base64.h"
39#include "regex.h" 38#include "regex.h"
40 39
41#include <ctype.h> 40#include <ctype.h>
41#include <string.h>
42#include "check_smtp.d/config.h" 42#include "check_smtp.d/config.h"
43#include "../lib/states.h" 43#include "../lib/states.h"
44 44
45const char *progname = "check_smtp";
46const char *copyright = "2000-2024";
47const char *email = "devel@monitoring-plugins.org";
48
45#define PROXY_PREFIX "PROXY TCP4 0.0.0.0 0.0.0.0 25 25\r\n" 49#define PROXY_PREFIX "PROXY TCP4 0.0.0.0 0.0.0.0 25 25\r\n"
46#define SMTP_HELO "HELO " 50#define SMTP_HELO "HELO "
47#define SMTP_EHLO "EHLO " 51#define SMTP_EHLO "EHLO "
@@ -58,7 +62,8 @@ typedef struct {
58} check_smtp_config_wrapper; 62} check_smtp_config_wrapper;
59static check_smtp_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); 63static check_smtp_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
60 64
61int my_recv(check_smtp_config config, void *buf, int num, int socket_descriptor, bool ssl_established) { 65int my_recv(check_smtp_config config, void *buf, int num, int socket_descriptor,
66 bool ssl_established) {
62#ifdef HAVE_SSL 67#ifdef HAVE_SSL
63 if ((config.use_starttls || config.use_ssl) && ssl_established) { 68 if ((config.use_starttls || config.use_ssl) && ssl_established) {
64 return np_net_ssl_read(buf, num); 69 return np_net_ssl_read(buf, num);
@@ -69,7 +74,8 @@ int my_recv(check_smtp_config config, void *buf, int num, int socket_descriptor,
69#endif 74#endif
70} 75}
71 76
72int my_send(check_smtp_config config, void *buf, int num, int socket_descriptor, bool ssl_established) { 77int my_send(check_smtp_config config, void *buf, int num, int socket_descriptor,
78 bool ssl_established) {
73#ifdef HAVE_SSL 79#ifdef HAVE_SSL
74 if ((config.use_starttls || config.use_ssl) && ssl_established) { 80 if ((config.use_starttls || config.use_ssl) && ssl_established) {
75 81
@@ -83,10 +89,12 @@ int my_send(check_smtp_config config, void *buf, int num, int socket_descriptor,
83 89
84static void print_help(void); 90static void print_help(void);
85void print_usage(void); 91void print_usage(void);
86static char *smtp_quit(check_smtp_config /*config*/, char /*buffer*/[MAX_INPUT_BUFFER], int /*socket_descriptor*/, 92static char *smtp_quit(check_smtp_config /*config*/, char /*buffer*/[MAX_INPUT_BUFFER],
87 bool /*ssl_established*/); 93 int /*socket_descriptor*/, bool /*ssl_established*/);
88static int recvline(char * /*buf*/, size_t /*bufsize*/, check_smtp_config /*config*/, int /*socket_descriptor*/, bool /*ssl_established*/); 94static int recvline(char * /*buf*/, size_t /*bufsize*/, check_smtp_config /*config*/,
89static int recvlines(check_smtp_config /*config*/, char * /*buf*/, size_t /*bufsize*/, int /*socket_descriptor*/, bool /*ssl_established*/); 95 int /*socket_descriptor*/, bool /*ssl_established*/);
96static int recvlines(check_smtp_config /*config*/, char * /*buf*/, size_t /*bufsize*/,
97 int /*socket_descriptor*/, bool /*ssl_established*/);
90static int my_close(int /*socket_descriptor*/); 98static int my_close(int /*socket_descriptor*/);
91 99
92static int verbose = 0; 100static int verbose = 0;
@@ -107,6 +115,10 @@ int main(int argc, char **argv) {
107 115
108 const check_smtp_config config = tmp_config.config; 116 const check_smtp_config config = tmp_config.config;
109 117
118 if (config.output_format_is_set) {
119 mp_set_format(config.output_format);
120 }
121
110 /* If localhostname not set on command line, use gethostname to set */ 122 /* If localhostname not set on command line, use gethostname to set */
111 char *localhostname = config.localhostname; 123 char *localhostname = config.localhostname;
112 if (!localhostname) { 124 if (!localhostname) {
@@ -157,342 +169,459 @@ int main(int argc, char **argv) {
157 gettimeofday(&start_time, NULL); 169 gettimeofday(&start_time, NULL);
158 170
159 int socket_descriptor = 0; 171 int socket_descriptor = 0;
172
160 /* try to connect to the host at the given port number */ 173 /* try to connect to the host at the given port number */
161 mp_state_enum result = my_tcp_connect(config.server_address, config.server_port, &socket_descriptor); 174 mp_state_enum tcp_result =
175 my_tcp_connect(config.server_address, config.server_port, &socket_descriptor);
162 176
163 char *error_msg = ""; 177 mp_check overall = mp_check_init();
178 mp_subcheck sc_tcp_connect = mp_subcheck_init();
164 char buffer[MAX_INPUT_BUFFER]; 179 char buffer[MAX_INPUT_BUFFER];
165 bool ssl_established = false; 180 bool ssl_established = false;
166 if (result == STATE_OK) { /* we connected */ 181
167 /* If requested, send PROXY header */ 182 if (tcp_result != STATE_OK) {
168 if (config.use_proxy_prefix) { 183 // Connect failed
169 if (verbose) { 184 sc_tcp_connect = mp_set_subcheck_state(sc_tcp_connect, STATE_CRITICAL);
170 printf("Sending header %s\n", PROXY_PREFIX); 185 xasprintf(&sc_tcp_connect.output, "TCP connect to '%s' failed", config.server_address);
171 } 186 mp_add_subcheck_to_check(&overall, sc_tcp_connect);
172 my_send(config, PROXY_PREFIX, strlen(PROXY_PREFIX), socket_descriptor, ssl_established); 187 mp_exit(overall);
188 }
189
190 /* we connected */
191 /* If requested, send PROXY header */
192 if (config.use_proxy_prefix) {
193 if (verbose) {
194 printf("Sending header %s\n", PROXY_PREFIX);
173 } 195 }
196 my_send(config, PROXY_PREFIX, strlen(PROXY_PREFIX), socket_descriptor, ssl_established);
197 }
174 198
175#ifdef HAVE_SSL 199#ifdef HAVE_SSL
176 if (config.use_ssl) { 200 if (config.use_ssl) {
177 result = np_net_ssl_init_with_hostname(socket_descriptor, (config.use_sni ? config.server_address : NULL)); 201 int tls_result = np_net_ssl_init_with_hostname(
178 if (result != STATE_OK) { 202 socket_descriptor, (config.use_sni ? config.server_address : NULL));
179 printf(_("CRITICAL - Cannot create SSL context.\n")); 203
180 close(socket_descriptor); 204 mp_subcheck sc_tls_connection = mp_subcheck_init();
181 np_net_ssl_cleanup(); 205
182 exit(STATE_CRITICAL); 206 if (tls_result != STATE_OK) {
183 } 207 close(socket_descriptor);
184 ssl_established = true; 208 np_net_ssl_cleanup();
209
210 sc_tls_connection = mp_set_subcheck_state(sc_tls_connection, STATE_CRITICAL);
211 xasprintf(&sc_tls_connection.output, "cannot create TLS context");
212 mp_add_subcheck_to_check(&overall, sc_tls_connection);
213 mp_exit(overall);
185 } 214 }
215
216 sc_tls_connection = mp_set_subcheck_state(sc_tls_connection, STATE_OK);
217 xasprintf(&sc_tls_connection.output, "TLS context established");
218 mp_add_subcheck_to_check(&overall, sc_tls_connection);
219 ssl_established = true;
220 }
186#endif 221#endif
187 222
188 /* watch for the SMTP connection string and */ 223 /* watch for the SMTP connection string and */
189 /* return a WARNING status if we couldn't read any data */ 224 /* return a WARNING status if we couldn't read any data */
190 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) { 225 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) {
191 printf(_("recv() failed\n")); 226 mp_subcheck sc_read_data = mp_subcheck_init();
192 exit(STATE_WARNING); 227 sc_read_data = mp_set_subcheck_state(sc_read_data, STATE_WARNING);
193 } 228 xasprintf(&sc_read_data.output, "recv() failed");
229 mp_add_subcheck_to_check(&overall, sc_read_data);
230 mp_exit(overall);
231 }
194 232
195 char *server_response = NULL; 233 char *server_response = NULL;
196 /* save connect return (220 hostname ..) for later use */ 234 /* save connect return (220 hostname ..) for later use */
197 xasprintf(&server_response, "%s", buffer); 235 xasprintf(&server_response, "%s", buffer);
198 236
199 /* send the HELO/EHLO command */ 237 /* send the HELO/EHLO command */
200 my_send(config, helocmd, (int)strlen(helocmd), socket_descriptor, ssl_established); 238 my_send(config, helocmd, (int)strlen(helocmd), socket_descriptor, ssl_established);
201 239
202 /* allow for response to helo command to reach us */ 240 /* allow for response to helo command to reach us */
203 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) { 241 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) {
204 printf(_("recv() failed\n")); 242 mp_subcheck sc_read_data = mp_subcheck_init();
205 exit(STATE_WARNING); 243 sc_read_data = mp_set_subcheck_state(sc_read_data, STATE_WARNING);
206 } 244 xasprintf(&sc_read_data.output, "recv() failed");
245 mp_add_subcheck_to_check(&overall, sc_read_data);
246 mp_exit(overall);
247 }
207 248
208 bool supports_tls = false; 249 bool supports_tls = false;
209 if (config.use_ehlo || config.use_lhlo) { 250 if (config.use_ehlo || config.use_lhlo) {
210 if (strstr(buffer, "250 STARTTLS") != NULL || strstr(buffer, "250-STARTTLS") != NULL) { 251 if (strstr(buffer, "250 STARTTLS") != NULL || strstr(buffer, "250-STARTTLS") != NULL) {
211 supports_tls = true; 252 supports_tls = true;
212 }
213 } 253 }
254 }
214 255
215 if (config.use_starttls && !supports_tls) { 256 if (config.use_starttls && !supports_tls) {
216 printf(_("WARNING - TLS not supported by server\n")); 257 smtp_quit(config, buffer, socket_descriptor, ssl_established);
258
259 mp_subcheck sc_read_data = mp_subcheck_init();
260 sc_read_data = mp_set_subcheck_state(sc_read_data, STATE_WARNING);
261 xasprintf(&sc_read_data.output, "StartTLS not supported by server");
262 mp_add_subcheck_to_check(&overall, sc_read_data);
263 mp_exit(overall);
264 }
265
266#ifdef HAVE_SSL
267 if (config.use_starttls) {
268 /* send the STARTTLS command */
269 send(socket_descriptor, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0);
270
271 mp_subcheck sc_starttls_init = mp_subcheck_init();
272 recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor,
273 ssl_established); /* wait for it */
274 if (!strstr(buffer, SMTP_EXPECT)) {
217 smtp_quit(config, buffer, socket_descriptor, ssl_established); 275 smtp_quit(config, buffer, socket_descriptor, ssl_established);
218 exit(STATE_WARNING); 276
277 xasprintf(&sc_starttls_init.output, "StartTLS not supported by server");
278 sc_starttls_init = mp_set_subcheck_state(sc_starttls_init, STATE_UNKNOWN);
279 mp_add_subcheck_to_check(&overall, sc_starttls_init);
280 mp_exit(overall);
219 } 281 }
220 282
221#ifdef HAVE_SSL 283 mp_state_enum starttls_result = np_net_ssl_init_with_hostname(
222 if (config.use_starttls) { 284 socket_descriptor, (config.use_sni ? config.server_address : NULL));
223 /* send the STARTTLS command */ 285 if (starttls_result != STATE_OK) {
224 send(socket_descriptor, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0); 286 close(socket_descriptor);
225 287 np_net_ssl_cleanup();
226 recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established); /* wait for it */
227 if (!strstr(buffer, SMTP_EXPECT)) {
228 printf(_("Server does not support STARTTLS\n"));
229 smtp_quit(config, buffer, socket_descriptor, ssl_established);
230 exit(STATE_UNKNOWN);
231 }
232 288
233 result = np_net_ssl_init_with_hostname(socket_descriptor, (config.use_sni ? config.server_address : NULL)); 289 sc_starttls_init = mp_set_subcheck_state(sc_starttls_init, STATE_CRITICAL);
234 if (result != STATE_OK) { 290 xasprintf(&sc_starttls_init.output, "failed to create StartTLS context");
235 printf(_("CRITICAL - Cannot create SSL context.\n")); 291 mp_add_subcheck_to_check(&overall, sc_starttls_init);
236 close(socket_descriptor); 292 mp_exit(overall);
237 np_net_ssl_cleanup(); 293 }
238 exit(STATE_CRITICAL); 294 sc_starttls_init = mp_set_subcheck_state(sc_starttls_init, STATE_OK);
239 } 295 xasprintf(&sc_starttls_init.output, "created StartTLS context");
296 mp_add_subcheck_to_check(&overall, sc_starttls_init);
297
298 ssl_established = true;
299
300 /*
301 * Resend the EHLO command.
302 *
303 * RFC 3207 (4.2) says: ``The client MUST discard any knowledge
304 * obtained from the server, such as the list of SMTP service
305 * extensions, which was not obtained from the TLS negotiation
306 * itself. The client SHOULD send an EHLO command as the first
307 * command after a successful TLS negotiation.'' For this
308 * reason, some MTAs will not allow an AUTH LOGIN command before
309 * we resent EHLO via TLS.
310 */
311 if (my_send(config, helocmd, (int)strlen(helocmd), socket_descriptor, ssl_established) <=
312 0) {
313 my_close(socket_descriptor);
314
315 mp_subcheck sc_ehlo = mp_subcheck_init();
316 sc_ehlo = mp_set_subcheck_state(sc_ehlo, STATE_UNKNOWN);
317 xasprintf(&sc_ehlo.output, "cannot send EHLO command via StartTLS");
318 mp_add_subcheck_to_check(&overall, sc_ehlo);
319 mp_exit(overall);
320 }
240 321
241 ssl_established = true; 322 if (verbose) {
242 323 printf(_("sent %s"), helocmd);
243 /* 324 }
244 * Resend the EHLO command.
245 *
246 * RFC 3207 (4.2) says: ``The client MUST discard any knowledge
247 * obtained from the server, such as the list of SMTP service
248 * extensions, which was not obtained from the TLS negotiation
249 * itself. The client SHOULD send an EHLO command as the first
250 * command after a successful TLS negotiation.'' For this
251 * reason, some MTAs will not allow an AUTH LOGIN command before
252 * we resent EHLO via TLS.
253 */
254 if (my_send(config, helocmd, strlen(helocmd), socket_descriptor, ssl_established) <= 0) {
255 printf("%s\n", _("SMTP UNKNOWN - Cannot send EHLO command via TLS."));
256 my_close(socket_descriptor);
257 exit(STATE_UNKNOWN);
258 }
259 325
260 if (verbose) { 326 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) {
261 printf(_("sent %s"), helocmd); 327 my_close(socket_descriptor);
262 }
263 328
264 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) { 329 mp_subcheck sc_ehlo = mp_subcheck_init();
265 printf("%s\n", _("SMTP UNKNOWN - Cannot read EHLO response via TLS.")); 330 sc_ehlo = mp_set_subcheck_state(sc_ehlo, STATE_UNKNOWN);
266 my_close(socket_descriptor); 331 xasprintf(&sc_ehlo.output, "cannot read EHLO response via StartTLS");
267 exit(STATE_UNKNOWN); 332 mp_add_subcheck_to_check(&overall, sc_ehlo);
268 } 333 mp_exit(overall);
334 }
269 335
270 if (verbose) { 336 if (verbose) {
271 printf("%s", buffer); 337 printf("%s", buffer);
272 } 338 }
339 }
273 340
274# ifdef USE_OPENSSL 341# ifdef USE_OPENSSL
275 if (config.check_cert) { 342 if (ssl_established) {
276 result = np_net_ssl_check_cert(config.days_till_exp_warn, config.days_till_exp_crit); 343 net_ssl_check_cert_result cert_check_result =
277 smtp_quit(config, buffer, socket_descriptor, ssl_established); 344 np_net_ssl_check_cert2(config.days_till_exp_warn, config.days_till_exp_crit);
278 my_close(socket_descriptor); 345
279 exit(result); 346 mp_subcheck sc_cert_check = mp_subcheck_init();
347
348 switch (cert_check_result.errors) {
349 case ALL_OK: {
350
351 if (cert_check_result.result_state != STATE_OK &&
352 config.ignore_certificate_expiration) {
353 xasprintf(&sc_cert_check.output,
354 "Remaining certificate lifetime: %d days. Expiration will be ignored",
355 (int)(cert_check_result.remaining_seconds / 86400));
356 sc_cert_check = mp_set_subcheck_state(sc_cert_check, STATE_OK);
357 } else {
358 xasprintf(&sc_cert_check.output, "Remaining certificate lifetime: %d days",
359 (int)(cert_check_result.remaining_seconds / 86400));
360 sc_cert_check =
361 mp_set_subcheck_state(sc_cert_check, cert_check_result.result_state);
280 } 362 }
363 } break;
364 case NO_SERVER_CERTIFICATE_PRESENT: {
365 xasprintf(&sc_cert_check.output, "no server certificate present");
366 sc_cert_check = mp_set_subcheck_state(sc_cert_check, cert_check_result.result_state);
367 } break;
368 case UNABLE_TO_RETRIEVE_CERTIFICATE_SUBJECT: {
369 xasprintf(&sc_cert_check.output, "can not retrieve certificate subject");
370 sc_cert_check = mp_set_subcheck_state(sc_cert_check, cert_check_result.result_state);
371 } break;
372 case WRONG_TIME_FORMAT_IN_CERTIFICATE: {
373 xasprintf(&sc_cert_check.output, "wrong time format in certificate");
374 sc_cert_check = mp_set_subcheck_state(sc_cert_check, cert_check_result.result_state);
375 } break;
376 };
377
378 mp_add_subcheck_to_check(&overall, sc_cert_check);
379 }
281# endif /* USE_OPENSSL */ 380# endif /* USE_OPENSSL */
282 } 381
283#endif 382#endif
284 383
285 if (verbose) { 384 if (verbose) {
385 printf("%s", buffer);
386 }
387
388 /* save buffer for later use */
389 xasprintf(&server_response, "%s%s", server_response, buffer);
390 /* strip the buffer of carriage returns */
391 strip(server_response);
392
393 /* make sure we find the droids we are looking for */
394 mp_subcheck sc_expect_response = mp_subcheck_init();
395
396 if (!strstr(server_response, config.server_expect)) {
397 sc_expect_response = mp_set_subcheck_state(sc_expect_response, STATE_WARNING);
398 if (config.server_port == SMTP_PORT) {
399 xasprintf(&sc_expect_response.output, _("invalid SMTP response received from host: %s"),
400 server_response);
401 } else {
402 xasprintf(&sc_expect_response.output,
403 _("invalid SMTP response received from host on port %d: %s"),
404 config.server_port, server_response);
405 }
406 exit(STATE_WARNING);
407 } else {
408 xasprintf(&sc_expect_response.output, "received valid SMTP response '%s' from host: '%s'",
409 config.server_expect, server_response);
410 sc_expect_response = mp_set_subcheck_state(sc_expect_response, STATE_OK);
411 }
412
413 mp_add_subcheck_to_check(&overall, sc_expect_response);
414
415 if (config.send_mail_from) {
416 my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established);
417 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= 1 &&
418 verbose) {
286 printf("%s", buffer); 419 printf("%s", buffer);
287 } 420 }
421 }
288 422
289 /* save buffer for later use */ 423 size_t counter = 0;
290 xasprintf(&server_response, "%s%s", server_response, buffer); 424 while (counter < config.ncommands) {
291 /* strip the buffer of carriage returns */ 425 xasprintf(&cmd_str, "%s%s", config.commands[counter], "\r\n");
292 strip(server_response); 426 my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established);
427 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= 1 &&
428 verbose) {
429 printf("%s", buffer);
430 }
293 431
294 /* make sure we find the droids we are looking for */ 432 strip(buffer);
295 if (!strstr(server_response, config.server_expect)) { 433
296 if (config.server_port == SMTP_PORT) { 434 if (counter < config.nresponses) {
297 printf(_("Invalid SMTP response received from host: %s\n"), server_response); 435 int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
298 } else { 436 regex_t preg;
299 printf(_("Invalid SMTP response received from host on port %d: %s\n"), config.server_port, server_response); 437 int errcode = regcomp(&preg, config.responses[counter], cflags);
438 char errbuf[MAX_INPUT_BUFFER];
439 if (errcode != 0) {
440 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
441 printf(_("Could Not Compile Regular Expression"));
442 exit(STATE_UNKNOWN);
300 } 443 }
301 exit(STATE_WARNING);
302 }
303 444
304 if (config.send_mail_from) { 445 regmatch_t pmatch[10];
305 my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established); 446 int eflags = 0;
306 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= 1 && verbose) { 447 int excode = regexec(&preg, buffer, 10, pmatch, eflags);
307 printf("%s", buffer); 448 mp_subcheck sc_expected_responses = mp_subcheck_init();
449 if (excode == 0) {
450 xasprintf(&sc_expected_responses.output, "valid response '%s' to command '%s'",
451 buffer, config.commands[counter]);
452 sc_expected_responses = mp_set_subcheck_state(sc_expected_responses, STATE_OK);
453 } else if (excode == REG_NOMATCH) {
454 sc_expected_responses = mp_set_subcheck_state(sc_expected_responses, STATE_WARNING);
455 xasprintf(&sc_expected_responses.output, "invalid response '%s' to command '%s'",
456 buffer, config.commands[counter]);
457 } else {
458 regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER);
459 xasprintf(&sc_expected_responses.output, "regexec execute error: %s", errbuf);
460 sc_expected_responses = mp_set_subcheck_state(sc_expected_responses, STATE_UNKNOWN);
308 } 461 }
309 } 462 }
463 counter++;
464 }
310 465
311 int counter = 0; 466 if (config.authtype != NULL) {
312 while (counter < config.ncommands) { 467 mp_subcheck sc_auth = mp_subcheck_init();
313 xasprintf(&cmd_str, "%s%s", config.commands[counter], "\r\n"); 468
314 my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established); 469 if (strcmp(config.authtype, "LOGIN") == 0) {
315 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= 1 && verbose) { 470 char *abuf;
316 printf("%s", buffer); 471 int ret;
317 } 472 do {
318 strip(buffer); 473 /* send AUTH LOGIN */
319 if (counter < config.nresponses) { 474 my_send(config, SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN), socket_descriptor,
320 int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 475 ssl_established);
321 regex_t preg; 476
322 int errcode = regcomp(&preg, config.responses[counter], cflags); 477 if (verbose) {
323 char errbuf[MAX_INPUT_BUFFER]; 478 printf(_("sent %s\n"), "AUTH LOGIN");
324 if (errcode != 0) {
325 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
326 printf(_("Could Not Compile Regular Expression"));
327 exit(STATE_UNKNOWN);
328 } 479 }
329 480
330 regmatch_t pmatch[10]; 481 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor,
331 int eflags = 0; 482 ssl_established)) <= 0) {
332 int excode = regexec(&preg, buffer, 10, pmatch, eflags); 483 xasprintf(&sc_auth.output, _("recv() failed after AUTH LOGIN"));
333 if (excode == 0) { 484 sc_auth = mp_set_subcheck_state(sc_auth, STATE_WARNING);
334 result = STATE_OK; 485 break;
335 } else if (excode == REG_NOMATCH) {
336 result = STATE_WARNING;
337 printf(_("SMTP %s - Invalid response '%s' to command '%s'\n"), state_text(result), buffer, config.commands[counter]);
338 } else {
339 regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER);
340 printf(_("Execute Error: %s\n"), errbuf);
341 result = STATE_UNKNOWN;
342 } 486 }
343 }
344 counter++;
345 }
346 487
347 if (config.authtype != NULL) { 488 if (verbose) {
348 if (strcmp(config.authtype, "LOGIN") == 0) { 489 printf(_("received %s\n"), buffer);
349 char *abuf; 490 }
350 int ret; 491
351 do { 492 if (strncmp(buffer, "334", 3) != 0) {
352 if (config.authuser == NULL) { 493 xasprintf(&sc_auth.output, "invalid response received after AUTH LOGIN");
353 result = STATE_CRITICAL; 494 sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL);
354 xasprintf(&error_msg, _("no authuser specified, "));
355 break;
356 }
357 if (config.authpass == NULL) {
358 result = STATE_CRITICAL;
359 xasprintf(&error_msg, _("no authpass specified, "));
360 break;
361 }
362
363 /* send AUTH LOGIN */
364 my_send(config, SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN), socket_descriptor, ssl_established);
365 if (verbose) {
366 printf(_("sent %s\n"), "AUTH LOGIN");
367 }
368
369 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established)) <= 0) {
370 xasprintf(&error_msg, _("recv() failed after AUTH LOGIN, "));
371 result = STATE_WARNING;
372 break;
373 }
374 if (verbose) {
375 printf(_("received %s\n"), buffer);
376 }
377
378 if (strncmp(buffer, "334", 3) != 0) {
379 result = STATE_CRITICAL;
380 xasprintf(&error_msg, _("invalid response received after AUTH LOGIN, "));
381 break;
382 }
383
384 /* encode authuser with base64 */
385 base64_encode_alloc(config.authuser, strlen(config.authuser), &abuf);
386 xasprintf(&abuf, "%s\r\n", abuf);
387 my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established);
388 if (verbose) {
389 printf(_("sent %s\n"), abuf);
390 }
391
392 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established)) <= 0) {
393 result = STATE_CRITICAL;
394 xasprintf(&error_msg, _("recv() failed after sending authuser, "));
395 break;
396 }
397 if (verbose) {
398 printf(_("received %s\n"), buffer);
399 }
400 if (strncmp(buffer, "334", 3) != 0) {
401 result = STATE_CRITICAL;
402 xasprintf(&error_msg, _("invalid response received after authuser, "));
403 break;
404 }
405 /* encode authpass with base64 */
406 base64_encode_alloc(config.authpass, strlen(config.authpass), &abuf);
407 xasprintf(&abuf, "%s\r\n", abuf);
408 my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established);
409 if (verbose) {
410 printf(_("sent %s\n"), abuf);
411 }
412 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established)) <= 0) {
413 result = STATE_CRITICAL;
414 xasprintf(&error_msg, _("recv() failed after sending authpass, "));
415 break;
416 }
417 if (verbose) {
418 printf(_("received %s\n"), buffer);
419 }
420 if (strncmp(buffer, "235", 3) != 0) {
421 result = STATE_CRITICAL;
422 xasprintf(&error_msg, _("invalid response received after authpass, "));
423 break;
424 }
425 break; 495 break;
426 } while (false); 496 }
427 } else {
428 result = STATE_CRITICAL;
429 xasprintf(&error_msg, _("only authtype LOGIN is supported, "));
430 }
431 }
432 497
433 /* tell the server we're done */ 498 /* encode authuser with base64 */
434 smtp_quit(config, buffer, socket_descriptor, ssl_established); 499 base64_encode_alloc(config.authuser, strlen(config.authuser), &abuf);
500 xasprintf(&abuf, "%s\r\n", abuf);
501 my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established);
502 if (verbose) {
503 printf(_("sent %s\n"), abuf);
504 }
505
506 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor,
507 ssl_established)) <= 0) {
508 xasprintf(&sc_auth.output, "recv() failed after sending authuser");
509 sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL);
510 break;
511 }
512
513 if (verbose) {
514 printf(_("received %s\n"), buffer);
515 }
516
517 if (strncmp(buffer, "334", 3) != 0) {
518 xasprintf(&sc_auth.output, "invalid response received after authuser");
519 sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL);
520 break;
521 }
435 522
436 /* finally close the connection */ 523 /* encode authpass with base64 */
437 close(socket_descriptor); 524 base64_encode_alloc(config.authpass, strlen(config.authpass), &abuf);
525 xasprintf(&abuf, "%s\r\n", abuf);
526 my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established);
527
528 if (verbose) {
529 printf(_("sent %s\n"), abuf);
530 }
531
532 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor,
533 ssl_established)) <= 0) {
534 xasprintf(&sc_auth.output, "recv() failed after sending authpass");
535 sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL);
536 break;
537 }
538
539 if (verbose) {
540 printf(_("received %s\n"), buffer);
541 }
542
543 if (strncmp(buffer, "235", 3) != 0) {
544 xasprintf(&sc_auth.output, "invalid response received after authpass");
545 sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL);
546 break;
547 }
548 break;
549 } while (false);
550 } else {
551 sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL);
552 xasprintf(&sc_auth.output, "only authtype LOGIN is supported");
553 }
554
555 mp_add_subcheck_to_check(&overall, sc_auth);
438 } 556 }
439 557
558 /* tell the server we're done */
559 smtp_quit(config, buffer, socket_descriptor, ssl_established);
560
561 /* finally close the connection */
562 close(socket_descriptor);
563
440 /* reset the alarm */ 564 /* reset the alarm */
441 alarm(0); 565 alarm(0);
442 566
443 long microsec = deltime(start_time); 567 long microsec = deltime(start_time);
444 double elapsed_time = (double)microsec / 1.0e6; 568 double elapsed_time = (double)microsec / 1.0e6;
445 569
446 if (result == STATE_OK) { 570 mp_perfdata pd_elapsed_time = perfdata_init();
447 if (config.check_critical_time && elapsed_time > config.critical_time) { 571 pd_elapsed_time = mp_set_pd_value(pd_elapsed_time, elapsed_time);
448 result = STATE_CRITICAL; 572 pd_elapsed_time.label = "time";
449 } else if (config.check_warning_time && elapsed_time > config.warning_time) { 573 pd_elapsed_time.uom = "s";
450 result = STATE_WARNING; 574
451 } 575 pd_elapsed_time = mp_pd_set_thresholds(pd_elapsed_time, config.connection_time);
452 }
453 576
454 printf(_("SMTP %s - %s%.3f sec. response time%s%s|%s\n"), state_text(result), error_msg, elapsed_time, verbose ? ", " : "", 577 mp_subcheck sc_connection_time = mp_subcheck_init();
455 verbose ? buffer : "", 578 xasprintf(&sc_connection_time.output, "connection time: %.3gs", elapsed_time);
456 fperfdata("time", elapsed_time, "s", config.check_warning_time, config.warning_time, config.check_critical_time, 579 sc_connection_time =
457 config.critical_time, true, 0, false, 0)); 580 mp_set_subcheck_state(sc_connection_time, mp_get_pd_status(pd_elapsed_time));
581 mp_add_subcheck_to_check(&overall, sc_connection_time);
458 582
459 exit(result); 583 mp_exit(overall);
460} 584}
461 585
462/* process command-line arguments */ 586/* process command-line arguments */
463check_smtp_config_wrapper process_arguments(int argc, char **argv) { 587check_smtp_config_wrapper process_arguments(int argc, char **argv) {
464 enum { 588 enum {
465 SNI_OPTION = CHAR_MAX + 1 589 SNI_OPTION = CHAR_MAX + 1,
590 output_format_index,
591 ignore_certificate_expiration_index,
466 }; 592 };
467 593
468 int option = 0; 594 int option = 0;
469 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 595 static struct option longopts[] = {
470 {"expect", required_argument, 0, 'e'}, 596 {"hostname", required_argument, 0, 'H'},
471 {"critical", required_argument, 0, 'c'}, 597 {"expect", required_argument, 0, 'e'},
472 {"warning", required_argument, 0, 'w'}, 598 {"critical", required_argument, 0, 'c'},
473 {"timeout", required_argument, 0, 't'}, 599 {"warning", required_argument, 0, 'w'},
474 {"port", required_argument, 0, 'p'}, 600 {"timeout", required_argument, 0, 't'},
475 {"from", required_argument, 0, 'f'}, 601 {"port", required_argument, 0, 'p'},
476 {"fqdn", required_argument, 0, 'F'}, 602 {"from", required_argument, 0, 'f'},
477 {"authtype", required_argument, 0, 'A'}, 603 {"fqdn", required_argument, 0, 'F'},
478 {"authuser", required_argument, 0, 'U'}, 604 {"authtype", required_argument, 0, 'A'},
479 {"authpass", required_argument, 0, 'P'}, 605 {"authuser", required_argument, 0, 'U'},
480 {"command", required_argument, 0, 'C'}, 606 {"authpass", required_argument, 0, 'P'},
481 {"response", required_argument, 0, 'R'}, 607 {"command", required_argument, 0, 'C'},
482 {"verbose", no_argument, 0, 'v'}, 608 {"response", required_argument, 0, 'R'},
483 {"version", no_argument, 0, 'V'}, 609 {"verbose", no_argument, 0, 'v'},
484 {"use-ipv4", no_argument, 0, '4'}, 610 {"version", no_argument, 0, 'V'},
485 {"use-ipv6", no_argument, 0, '6'}, 611 {"use-ipv4", no_argument, 0, '4'},
486 {"help", no_argument, 0, 'h'}, 612 {"use-ipv6", no_argument, 0, '6'},
487 {"lmtp", no_argument, 0, 'L'}, 613 {"help", no_argument, 0, 'h'},
488 {"ssl", no_argument, 0, 's'}, 614 {"lmtp", no_argument, 0, 'L'},
489 {"tls", no_argument, 0, 's'}, 615 {"ssl", no_argument, 0, 's'},
490 {"starttls", no_argument, 0, 'S'}, 616 {"tls", no_argument, 0, 's'},
491 {"sni", no_argument, 0, SNI_OPTION}, 617 {"starttls", no_argument, 0, 'S'},
492 {"certificate", required_argument, 0, 'D'}, 618 {"sni", no_argument, 0, SNI_OPTION},
493 {"ignore-quit-failure", no_argument, 0, 'q'}, 619 {"certificate", required_argument, 0, 'D'},
494 {"proxy", no_argument, 0, 'r'}, 620 {"ignore-quit-failure", no_argument, 0, 'q'},
495 {0, 0, 0, 0}}; 621 {"proxy", no_argument, 0, 'r'},
622 {"ignore-certificate-expiration", no_argument, 0, ignore_certificate_expiration_index},
623 {"output-format", required_argument, 0, output_format_index},
624 {0, 0, 0, 0}};
496 625
497 check_smtp_config_wrapper result = { 626 check_smtp_config_wrapper result = {
498 .config = check_smtp_config_init(), 627 .config = check_smtp_config_init(),
@@ -514,12 +643,13 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) {
514 } 643 }
515 } 644 }
516 645
517 int command_size = 0; 646 unsigned long command_size = 0;
518 int response_size = 0; 647 unsigned long response_size = 0;
519 bool implicit_tls = false; 648 bool implicit_tls = false;
520 int server_port_option = 0; 649 int server_port_option = 0;
521 while (true) { 650 while (true) {
522 int opt_index = getopt_long(argc, argv, "+hVv46Lrt:p:f:e:c:w:H:C:R:sSD:F:A:U:P:q", longopts, &option); 651 int opt_index =
652 getopt_long(argc, argv, "+hVv46Lrt:p:f:e:c:w:H:C:R:sSD:F:A:U:P:q", longopts, &option);
523 653
524 if (opt_index == -1 || opt_index == EOF) { 654 if (opt_index == -1 || opt_index == EOF) {
525 break; 655 break;
@@ -546,7 +676,8 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) {
546 break; 676 break;
547 case 'f': /* from argument */ 677 case 'f': /* from argument */
548 result.config.from_arg = optarg + strspn(optarg, "<"); 678 result.config.from_arg = optarg + strspn(optarg, "<");
549 result.config.from_arg = strndup(result.config.from_arg, strcspn(result.config.from_arg, ">")); 679 result.config.from_arg =
680 strndup(result.config.from_arg, strcspn(result.config.from_arg, ">"));
550 result.config.send_mail_from = true; 681 result.config.send_mail_from = true;
551 break; 682 break;
552 case 'A': 683 case 'A':
@@ -565,9 +696,11 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) {
565 case 'C': /* commands */ 696 case 'C': /* commands */
566 if (result.config.ncommands >= command_size) { 697 if (result.config.ncommands >= command_size) {
567 command_size += 8; 698 command_size += 8;
568 result.config.commands = realloc(result.config.commands, sizeof(char *) * command_size); 699 result.config.commands =
700 realloc(result.config.commands, sizeof(char *) * command_size);
569 if (result.config.commands == NULL) { 701 if (result.config.commands == NULL) {
570 die(STATE_UNKNOWN, _("Could not realloc() units [%d]\n"), result.config.ncommands); 702 die(STATE_UNKNOWN, _("Could not realloc() units [%lu]\n"),
703 result.config.ncommands);
571 } 704 }
572 } 705 }
573 result.config.commands[result.config.ncommands] = (char *)malloc(sizeof(char) * 255); 706 result.config.commands[result.config.ncommands] = (char *)malloc(sizeof(char) * 255);
@@ -577,31 +710,33 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) {
577 case 'R': /* server responses */ 710 case 'R': /* server responses */
578 if (result.config.nresponses >= response_size) { 711 if (result.config.nresponses >= response_size) {
579 response_size += 8; 712 response_size += 8;
580 result.config.responses = realloc(result.config.responses, sizeof(char *) * response_size); 713 result.config.responses =
714 realloc(result.config.responses, sizeof(char *) * response_size);
581 if (result.config.responses == NULL) { 715 if (result.config.responses == NULL) {
582 die(STATE_UNKNOWN, _("Could not realloc() units [%d]\n"), result.config.nresponses); 716 die(STATE_UNKNOWN, _("Could not realloc() units [%lu]\n"),
717 result.config.nresponses);
583 } 718 }
584 } 719 }
585 result.config.responses[result.config.nresponses] = (char *)malloc(sizeof(char) * 255); 720 result.config.responses[result.config.nresponses] = (char *)malloc(sizeof(char) * 255);
586 strncpy(result.config.responses[result.config.nresponses], optarg, 255); 721 strncpy(result.config.responses[result.config.nresponses], optarg, 255);
587 result.config.nresponses++; 722 result.config.nresponses++;
588 break; 723 break;
589 case 'c': /* critical time threshold */ 724 case 'c': /* critical time threshold */ {
590 if (!is_nonnegative(optarg)) { 725 mp_range_parsed tmp = mp_parse_range_string(optarg);
591 usage4(_("Critical time must be a positive")); 726 if (tmp.error != MP_PARSING_SUCCES) {
592 } else { 727 die(STATE_UNKNOWN, "failed to parse critical time threshold");
593 result.config.critical_time = strtod(optarg, NULL);
594 result.config.check_critical_time = true;
595 } 728 }
596 break; 729 result.config.connection_time =
597 case 'w': /* warning time threshold */ 730 mp_thresholds_set_warn(result.config.connection_time, tmp.range);
598 if (!is_nonnegative(optarg)) { 731 } break;
599 usage4(_("Warning time must be a positive")); 732 case 'w': /* warning time threshold */ {
600 } else { 733 mp_range_parsed tmp = mp_parse_range_string(optarg);
601 result.config.warning_time = strtod(optarg, NULL); 734 if (tmp.error != MP_PARSING_SUCCES) {
602 result.config.check_warning_time = true; 735 die(STATE_UNKNOWN, "failed to parse warning time threshold");
603 } 736 }
604 break; 737 result.config.connection_time =
738 mp_thresholds_set_crit(result.config.connection_time, tmp.range);
739 } break;
605 case 'v': /* verbose */ 740 case 'v': /* verbose */
606 verbose++; 741 verbose++;
607 break; 742 break;
@@ -638,7 +773,6 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) {
638 } 773 }
639 result.config.days_till_exp_warn = atoi(optarg); 774 result.config.days_till_exp_warn = atoi(optarg);
640 } 775 }
641 result.config.check_cert = true;
642 result.config.ignore_send_quit_failure = true; 776 result.config.ignore_send_quit_failure = true;
643#else 777#else
644 usage(_("SSL support not available - install OpenSSL and recompile")); 778 usage(_("SSL support not available - install OpenSSL and recompile"));
@@ -687,6 +821,21 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) {
687 exit(STATE_UNKNOWN); 821 exit(STATE_UNKNOWN);
688 case '?': /* help */ 822 case '?': /* help */
689 usage5(); 823 usage5();
824 case output_format_index: {
825 parsed_output_format parser = mp_parse_output_format(optarg);
826 if (!parser.parsing_success) {
827 // TODO List all available formats here, maybe add anothoer usage function
828 printf("Invalid output format: %s\n", optarg);
829 exit(STATE_UNKNOWN);
830 }
831
832 result.config.output_format_is_set = true;
833 result.config.output_format = parser.output_format;
834 break;
835 }
836 case ignore_certificate_expiration_index: {
837 result.config.ignore_certificate_expiration = true;
838 }
690 } 839 }
691 } 840 }
692 841
@@ -715,11 +864,26 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) {
715 result.config.server_port = server_port_option; 864 result.config.server_port = server_port_option;
716 } 865 }
717 866
867 if (result.config.authtype) {
868 if (strcmp(result.config.authtype, "LOGIN") == 0) {
869 if (result.config.authuser == NULL) {
870 usage4("no authuser specified");
871 }
872 if (result.config.authpass == NULL) {
873 usage4("no authpass specified");
874 }
875 } else {
876 usage4("only authtype LOGIN is supported");
877 }
878 }
879
718 return result; 880 return result;
719} 881}
720 882
721char *smtp_quit(check_smtp_config config, char buffer[MAX_INPUT_BUFFER], int socket_descriptor, bool ssl_established) { 883char *smtp_quit(check_smtp_config config, char buffer[MAX_INPUT_BUFFER], int socket_descriptor,
722 int sent_bytes = my_send(config, SMTP_QUIT, strlen(SMTP_QUIT), socket_descriptor, ssl_established); 884 bool ssl_established) {
885 int sent_bytes =
886 my_send(config, SMTP_QUIT, strlen(SMTP_QUIT), socket_descriptor, ssl_established);
723 if (sent_bytes < 0) { 887 if (sent_bytes < 0) {
724 if (config.ignore_send_quit_failure) { 888 if (config.ignore_send_quit_failure) {
725 if (verbose) { 889 if (verbose) {
@@ -759,9 +923,10 @@ char *smtp_quit(check_smtp_config config, char buffer[MAX_INPUT_BUFFER], int soc
759 * function which buffers the data, move that to netutils.c and change 923 * function which buffers the data, move that to netutils.c and change
760 * check_smtp and other plugins to use that. Also, remove (\r)\n. 924 * check_smtp and other plugins to use that. Also, remove (\r)\n.
761 */ 925 */
762int recvline(char *buf, size_t bufsize, check_smtp_config config, int socket_descriptor, bool ssl_established) { 926int recvline(char *buf, size_t bufsize, check_smtp_config config, int socket_descriptor,
927 bool ssl_established) {
763 int result; 928 int result;
764 int counter; 929 size_t counter;
765 930
766 for (counter = result = 0; counter < bufsize - 1; counter++) { 931 for (counter = result = 0; counter < bufsize - 1; counter++) {
767 if ((result = my_recv(config, &buf[counter], 1, socket_descriptor, ssl_established)) != 1) { 932 if ((result = my_recv(config, &buf[counter], 1, socket_descriptor, ssl_established)) != 1) {
@@ -769,7 +934,7 @@ int recvline(char *buf, size_t bufsize, check_smtp_config config, int socket_des
769 } 934 }
770 if (buf[counter] == '\n') { 935 if (buf[counter] == '\n') {
771 buf[++counter] = '\0'; 936 buf[++counter] = '\0';
772 return counter; 937 return (int)counter;
773 } 938 }
774 } 939 }
775 return (result == 1 || counter == 0) ? -2 : result; /* -2 if out of space */ 940 return (result == 1 || counter == 0) ? -2 : result; /* -2 if out of space */
@@ -789,13 +954,16 @@ int recvline(char *buf, size_t bufsize, check_smtp_config config, int socket_des
789 * 954 *
790 * TODO: Move this to netutils.c. Also, remove \r and possibly the final \n. 955 * TODO: Move this to netutils.c. Also, remove \r and possibly the final \n.
791 */ 956 */
792int recvlines(check_smtp_config config, char *buf, size_t bufsize, int socket_descriptor, bool ssl_established) { 957int recvlines(check_smtp_config config, char *buf, size_t bufsize, int socket_descriptor,
958 bool ssl_established) {
793 int result; 959 int result;
794 int counter; 960 int counter;
795 961
796 for (counter = 0; /* forever */; counter += result) { 962 for (counter = 0; /* forever */; counter += result) {
797 if (!((result = recvline(buf + counter, bufsize - counter, config, socket_descriptor, ssl_established)) > 3 && 963 if (!((result = recvline(buf + counter, bufsize - counter, config, socket_descriptor,
798 isdigit((int)buf[counter]) && isdigit((int)buf[counter + 1]) && isdigit((int)buf[counter + 2]) && buf[counter + 3] == '-')) { 964 ssl_established)) > 3 &&
965 isdigit((int)buf[counter]) && isdigit((int)buf[counter + 1]) &&
966 isdigit((int)buf[counter + 2]) && buf[counter + 3] == '-')) {
799 break; 967 break;
800 } 968 }
801 } 969 }
@@ -835,13 +1003,15 @@ void print_help(void) {
835 printf(UT_IPv46); 1003 printf(UT_IPv46);
836 1004
837 printf(" %s\n", "-e, --expect=STRING"); 1005 printf(" %s\n", "-e, --expect=STRING");
838 printf(_(" String to expect in first line of server response (default: '%s')\n"), SMTP_EXPECT); 1006 printf(_(" String to expect in first line of server response (default: '%s')\n"),
1007 SMTP_EXPECT);
839 printf(" %s\n", "-C, --command=STRING"); 1008 printf(" %s\n", "-C, --command=STRING");
840 printf(" %s\n", _("SMTP command (may be used repeatedly)")); 1009 printf(" %s\n", _("SMTP command (may be used repeatedly)"));
841 printf(" %s\n", "-R, --response=STRING"); 1010 printf(" %s\n", "-R, --response=STRING");
842 printf(" %s\n", _("Expected response to command (may be used repeatedly)")); 1011 printf(" %s\n", _("Expected response to command (may be used repeatedly)"));
843 printf(" %s\n", "-f, --from=STRING"); 1012 printf(" %s\n", "-f, --from=STRING");
844 printf(" %s\n", _("FROM-address to include in MAIL command, required by Exchange 2000")), printf(" %s\n", "-F, --fqdn=STRING"); 1013 printf(" %s\n", _("FROM-address to include in MAIL command, required by Exchange 2000")),
1014 printf(" %s\n", "-F, --fqdn=STRING");
845 printf(" %s\n", _("FQDN used for HELO")); 1015 printf(" %s\n", _("FQDN used for HELO"));
846 printf(" %s\n", "-r, --proxy"); 1016 printf(" %s\n", "-r, --proxy");
847 printf(" %s\n", _("Use PROXY protocol prefix for the connection.")); 1017 printf(" %s\n", _("Use PROXY protocol prefix for the connection."));
@@ -867,11 +1037,15 @@ void print_help(void) {
867 printf(" %s\n", _("Send LHLO instead of HELO/EHLO")); 1037 printf(" %s\n", _("Send LHLO instead of HELO/EHLO"));
868 printf(" %s\n", "-q, --ignore-quit-failure"); 1038 printf(" %s\n", "-q, --ignore-quit-failure");
869 printf(" %s\n", _("Ignore failure when sending QUIT command to server")); 1039 printf(" %s\n", _("Ignore failure when sending QUIT command to server"));
1040 printf(" %s\n", "--ignore-certificate-expiration");
1041 printf(" %s\n", _("Ignore certificate expiration"));
870 1042
871 printf(UT_WARN_CRIT); 1043 printf(UT_WARN_CRIT);
872 1044
873 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 1045 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
874 1046
1047 printf(UT_OUTPUT_FORMAT);
1048
875 printf(UT_VERBOSE); 1049 printf(UT_VERBOSE);
876 1050
877 printf("\n"); 1051 printf("\n");
@@ -885,7 +1059,9 @@ void print_help(void) {
885 1059
886void print_usage(void) { 1060void print_usage(void) {
887 printf("%s\n", _("Usage:")); 1061 printf("%s\n", _("Usage:"));
888 printf("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-R response] [-f from addr]\n", progname); 1062 printf("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-R response] [-f from addr]\n",
1063 progname);
889 printf("[-A authtype -U authuser -P authpass] [-w warn] [-c crit] [-t timeout] [-q]\n"); 1064 printf("[-A authtype -U authuser -P authpass] [-w warn] [-c crit] [-t timeout] [-q]\n");
890 printf("[-F fqdn] [-S] [-L] [-D warn days cert expire[,crit days cert expire]] [-r] [--sni] [-v] \n"); 1065 printf("[-F fqdn] [-S] [-L] [-D warn days cert expire[,crit days cert expire]] [-r] [--sni] "
1066 "[-v] \n");
891} 1067}
diff --git a/plugins/check_smtp.d/config.h b/plugins/check_smtp.d/config.h
index 0a6511ef..b0d42ed1 100644
--- a/plugins/check_smtp.d/config.h
+++ b/plugins/check_smtp.d/config.h
@@ -1,6 +1,8 @@
1#pragma once 1#pragma once
2 2
3#include "../../config.h" 3#include "../../config.h"
4#include "output.h"
5#include "thresholds.h"
4#include <stddef.h> 6#include <stddef.h>
5#include <string.h> 7#include <string.h>
6 8
@@ -18,20 +20,18 @@ typedef struct {
18 char *server_expect; 20 char *server_expect;
19 bool ignore_send_quit_failure; 21 bool ignore_send_quit_failure;
20 22
21 double warning_time; 23 mp_thresholds connection_time;
22 bool check_warning_time; 24
23 double critical_time;
24 bool check_critical_time;
25 bool use_ehlo; 25 bool use_ehlo;
26 bool use_lhlo; 26 bool use_lhlo;
27 27
28 char *from_arg; 28 char *from_arg;
29 bool send_mail_from; 29 bool send_mail_from;
30 30
31 int ncommands; 31 unsigned long ncommands;
32 char **commands; 32 char **commands;
33 33
34 int nresponses; 34 unsigned long nresponses;
35 char **responses; 35 char **responses;
36 36
37 char *authtype; 37 char *authtype;
@@ -40,13 +40,17 @@ typedef struct {
40 40
41 bool use_proxy_prefix; 41 bool use_proxy_prefix;
42#ifdef HAVE_SSL 42#ifdef HAVE_SSL
43 bool check_cert;
44 int days_till_exp_warn; 43 int days_till_exp_warn;
45 int days_till_exp_crit; 44 int days_till_exp_crit;
46 bool use_ssl; 45 bool use_ssl;
47 bool use_starttls; 46 bool use_starttls;
48 bool use_sni; 47 bool use_sni;
48
49 bool ignore_certificate_expiration;
49#endif 50#endif
51
52 bool output_format_is_set;
53 mp_output_format output_format;
50} check_smtp_config; 54} check_smtp_config;
51 55
52check_smtp_config check_smtp_config_init() { 56check_smtp_config check_smtp_config_init() {
@@ -58,10 +62,7 @@ check_smtp_config check_smtp_config_init() {
58 .server_expect = SMTP_EXPECT, 62 .server_expect = SMTP_EXPECT,
59 .ignore_send_quit_failure = false, 63 .ignore_send_quit_failure = false,
60 64
61 .warning_time = 0, 65 .connection_time = mp_thresholds_init(),
62 .check_warning_time = false,
63 .critical_time = 0,
64 .check_critical_time = false,
65 .use_ehlo = false, 66 .use_ehlo = false,
66 .use_lhlo = false, 67 .use_lhlo = false,
67 68
@@ -80,13 +81,16 @@ check_smtp_config check_smtp_config_init() {
80 81
81 .use_proxy_prefix = false, 82 .use_proxy_prefix = false,
82#ifdef HAVE_SSL 83#ifdef HAVE_SSL
83 .check_cert = false,
84 .days_till_exp_warn = 0, 84 .days_till_exp_warn = 0,
85 .days_till_exp_crit = 0, 85 .days_till_exp_crit = 0,
86 .use_ssl = false, 86 .use_ssl = false,
87 .use_starttls = false, 87 .use_starttls = false,
88 .use_sni = false, 88 .use_sni = false,
89
90 .ignore_certificate_expiration = false,
89#endif 91#endif
92
93 .output_format_is_set = false,
90 }; 94 };
91 return tmp; 95 return tmp;
92} 96}
diff --git a/plugins/check_snmp.c b/plugins/check_snmp.c
index c1d8e2dd..f470d222 100644
--- a/plugins/check_snmp.c
+++ b/plugins/check_snmp.c
@@ -32,716 +32,492 @@ const char *progname = "check_snmp";
32const char *copyright = "1999-2024"; 32const char *copyright = "1999-2024";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "common.h" 35#include "./common.h"
36#include "runcmd.h" 36#include "./runcmd.h"
37#include "utils.h" 37#include "./utils.h"
38#include "utils_cmd.h" 38#include "../lib/states.h"
39 39
40#define DEFAULT_COMMUNITY "public" 40#include "../lib/utils_base.h"
41#define DEFAULT_PORT "161" 41#include "../lib/output.h"
42#define DEFAULT_MIBLIST "ALL" 42#include "check_snmp.d/check_snmp_helpers.h"
43#define DEFAULT_PROTOCOL "1" 43
44#define DEFAULT_RETRIES 5 44#include <strings.h>
45#define DEFAULT_AUTH_PROTOCOL "MD5" 45#include <stdint.h>
46#define DEFAULT_PRIV_PROTOCOL "DES" 46
47#define DEFAULT_DELIMITER "=" 47#include "check_snmp.d/config.h"
48#define DEFAULT_OUTPUT_DELIMITER " " 48#include <stdlib.h>
49#define DEFAULT_BUFFER_SIZE 100 49#include <arpa/inet.h>
50 50#include <net-snmp/library/parse.h>
51#define mark(a) ((a) != 0 ? "*" : "") 51#include <net-snmp/net-snmp-config.h>
52 52#include <net-snmp/net-snmp-includes.h>
53#define CHECK_UNDEF 0 53#include <net-snmp/library/snmp.h>
54#define CRIT_PRESENT 1 54#include <net-snmp/library/keytools.h>
55#define CRIT_STRING 2 55#include <net-snmp/library/snmp_api.h>
56#define CRIT_REGEX 4 56#include <net-snmp/session_api.h>
57#define WARN_PRESENT 8 57#include <net-snmp/definitions.h>
58 58#include <net-snmp/library/asn1.h>
59#define OID_COUNT_STEP 8 59#include <net-snmp/mib_api.h>
60 60#include <net-snmp/library/snmp_impl.h>
61/* Longopts only arguments */ 61#include <string.h>
62#define L_CALCULATE_RATE CHAR_MAX + 1 62#include "../gl/regex.h"
63#define L_RATE_MULTIPLIER CHAR_MAX + 2 63#include "../gl/base64.h"
64#define L_INVERT_SEARCH CHAR_MAX + 3 64#include <assert.h>
65#define L_OFFSET CHAR_MAX + 4 65
66#define L_IGNORE_MIB_PARSING_ERRORS CHAR_MAX + 5 66const char DEFAULT_COMMUNITY[] = "public";
67 67const char DEFAULT_MIBLIST[] = "ALL";
68/* Gobble to string - stop incrementing c when c[0] match one of the 68#define DEFAULT_AUTH_PROTOCOL "MD5"
69 * characters in s */ 69
70#define GOBBLE_TOS(c, s) \ 70#ifdef HAVE_USM_DES_PRIV_PROTOCOL
71 while (c[0] != '\0' && strchr(s, c[0]) == NULL) { \ 71# define DEFAULT_PRIV_PROTOCOL "DES"
72 c++; \ 72#else
73# define DEFAULT_PRIV_PROTOCOL "AES"
74#endif
75
76typedef struct proces_arguments_wrapper {
77 int errorcode;
78 check_snmp_config config;
79} process_arguments_wrapper;
80
81static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
82static char *trim_whitespaces_and_check_quoting(char *str);
83static char *get_next_argument(char *str);
84void print_usage(void);
85void print_help(void);
86
87int verbose = 0;
88
89typedef struct {
90 int errorcode;
91 char *state_string;
92} gen_state_string_type;
93gen_state_string_type gen_state_string(check_snmp_state_entry *entries, size_t num_of_entries) {
94 char *encoded_string = NULL;
95 gen_state_string_type result = {.errorcode = OK, .state_string = NULL};
96
97 if (verbose > 1) {
98 printf("%s:\n", __FUNCTION__);
99 for (size_t i = 0; i < num_of_entries; i++) {
100 printf("Entry timestamp %lu: %s", entries[i].timestamp, ctime(&entries[i].timestamp));
101 switch (entries[i].type) {
102 case ASN_GAUGE:
103 printf("Type GAUGE\n");
104 break;
105 case ASN_TIMETICKS:
106 printf("Type TIMETICKS\n");
107 break;
108 case ASN_COUNTER:
109 printf("Type COUNTER\n");
110 break;
111 case ASN_UINTEGER:
112 printf("Type UINTEGER\n");
113 break;
114 case ASN_COUNTER64:
115 printf("Type COUNTER64\n");
116 break;
117 case ASN_FLOAT:
118 printf("Type FLOAT\n");
119 case ASN_DOUBLE:
120 printf("Type DOUBLE\n");
121 break;
122 case ASN_INTEGER:
123 printf("Type INTEGER\n");
124 break;
125 }
126
127 switch (entries[i].type) {
128 case ASN_GAUGE:
129 case ASN_TIMETICKS:
130 case ASN_COUNTER:
131 case ASN_UINTEGER:
132 case ASN_COUNTER64:
133 printf("Value %llu\n", entries[i].value.uIntVal);
134 break;
135 case ASN_FLOAT:
136 case ASN_DOUBLE:
137 printf("Value %f\n", entries[i].value.doubleVal);
138 break;
139 case ASN_INTEGER:
140 printf("Value %lld\n", entries[i].value.intVal);
141 break;
142 }
143 }
144 }
145
146 idx_t encoded = base64_encode_alloc((const char *)entries,
147 (idx_t)(num_of_entries * sizeof(check_snmp_state_entry)),
148 &encoded_string);
149
150 if (encoded > 0 && encoded_string != NULL) {
151 // success
152 if (verbose > 1) {
153 printf("encoded string: %s\n", encoded_string);
154 printf("encoded string length: %lu\n", strlen(encoded_string));
155 }
156 result.state_string = encoded_string;
157 return result;
73 } 158 }
74/* Given c, keep track of backslashes (bk) and double-quotes (dq) 159 result.errorcode = ERROR;
75 * from c[0] */ 160 return result;
76#define COUNT_SEQ(c, bk, dq) \ 161}
77 switch (c[0]) { \ 162
78 case '\\': \ 163typedef struct {
79 if (bk) \ 164 int errorcode;
80 bk--; \ 165 check_snmp_state_entry *state;
81 else \ 166} recover_state_data_type;
82 bk++; \ 167recover_state_data_type recover_state_data(char *state_string, idx_t state_string_length) {
83 break; \ 168 recover_state_data_type result = {.errorcode = OK, .state = NULL};
84 case '"': \ 169
85 if (!dq) { \ 170 if (verbose > 1) {
86 dq++; \ 171 printf("%s:\n", __FUNCTION__);
87 } else if (!bk) { \ 172 printf("State string: %s\n", state_string);
88 dq--; \ 173 printf("State string length: %lu\n", state_string_length);
89 } else { \
90 bk--; \
91 } \
92 break; \
93 } 174 }
94 175
95static int process_arguments(int, char **); 176 idx_t outlen = 0;
96static int validate_arguments(void); 177 bool decoded =
97static char *thisarg(char *str); 178 base64_decode_alloc(state_string, state_string_length, (char **)&result.state, &outlen);
98static char *nextarg(char *str); 179
99void print_usage(void); 180 if (!decoded) {
100static void print_help(void); 181 if (verbose) {
101static char *multiply(char *str); 182 printf("Failed to decode state string\n");
102 183 }
103#include "regex.h" 184 // failure to decode
104static char regex_expect[MAX_INPUT_BUFFER] = ""; 185 result.errorcode = ERROR;
105static regex_t preg; 186 return result;
106static regmatch_t pmatch[10]; 187 }
107static char errbuf[MAX_INPUT_BUFFER] = ""; 188
108static char perfstr[MAX_INPUT_BUFFER] = "| "; 189 if (result.state == NULL) {
109static int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 190 // Memory Error?
110static int eflags = 0; 191 result.errorcode = ERROR;
111static int errcode, excode; 192 return result;
112 193 }
113static char *server_address = NULL; 194
114static char *community = NULL; 195 if (verbose > 1) {
115static char **contextargs = NULL; 196 printf("Recovered %lu entries of size %lu\n",
116static char *context = NULL; 197 (size_t)outlen / sizeof(check_snmp_state_entry), outlen);
117static char **authpriv = NULL; 198
118static char *proto = NULL; 199 for (size_t i = 0; i < (size_t)outlen / sizeof(check_snmp_state_entry); i++) {
119static char *seclevel = NULL; 200 printf("Entry timestamp %lu: %s", result.state[i].timestamp,
120static char *secname = NULL; 201 ctime(&result.state[i].timestamp));
121static char *authproto = NULL; 202 switch (result.state[i].type) {
122static char *privproto = NULL; 203 case ASN_GAUGE:
123static char *authpasswd = NULL; 204 printf("Type GAUGE\n");
124static char *privpasswd = NULL; 205 break;
125static int nulloid = STATE_UNKNOWN; 206 case ASN_TIMETICKS:
126static char **oids = NULL; 207 printf("Type TIMETICKS\n");
127static size_t oids_size = 0; 208 break;
128static char *label; 209 case ASN_COUNTER:
129static char *units; 210 printf("Type COUNTER\n");
130static char *port; 211 break;
131static char *snmpcmd; 212 case ASN_UINTEGER:
132static char string_value[MAX_INPUT_BUFFER] = ""; 213 printf("Type UINTEGER\n");
133static int invert_search = 0; 214 break;
134static char **labels = NULL; 215 case ASN_COUNTER64:
135static char **unitv = NULL; 216 printf("Type COUNTER64\n");
136static size_t nlabels = 0; 217 break;
137static size_t labels_size = OID_COUNT_STEP; 218 case ASN_FLOAT:
138static size_t nunits = 0; 219 printf("Type FLOAT\n");
139static size_t unitv_size = OID_COUNT_STEP; 220 case ASN_DOUBLE:
140static size_t numoids = 0; 221 printf("Type DOUBLE\n");
141static int numauthpriv = 0; 222 break;
142static int numcontext = 0; 223 case ASN_INTEGER:
143static int verbose = 0; 224 printf("Type INTEGER\n");
144static bool usesnmpgetnext = false; 225 break;
145static char *warning_thresholds = NULL; 226 }
146static char *critical_thresholds = NULL; 227
147static thresholds **thlds; 228 switch (result.state[i].type) {
148static size_t thlds_size = OID_COUNT_STEP; 229 case ASN_GAUGE:
149static double *response_value; 230 case ASN_TIMETICKS:
150static size_t response_size = OID_COUNT_STEP; 231 case ASN_COUNTER:
151static int retries = 0; 232 case ASN_UINTEGER:
152static int *eval_method; 233 case ASN_COUNTER64:
153static size_t eval_size = OID_COUNT_STEP; 234 printf("Value %llu\n", result.state[i].value.uIntVal);
154static char *delimiter; 235 break;
155static char *output_delim; 236 case ASN_FLOAT:
156static char *miblist = NULL; 237 case ASN_DOUBLE:
157static bool needmibs = false; 238 printf("Value %f\n", result.state[i].value.doubleVal);
158static int calculate_rate = 0; 239 break;
159static double offset = 0.0; 240 case ASN_INTEGER:
160static int rate_multiplier = 1; 241 printf("Value %lld\n", result.state[i].value.intVal);
161static state_data *previous_state; 242 break;
162static double *previous_value; 243 }
163static size_t previous_size = OID_COUNT_STEP; 244 }
164static int perf_labels = 1; 245 }
165static char *ip_version = ""; 246
166static double multiplier = 1.0; 247 return result;
167static char *fmtstr = "";
168static bool fmtstr_set = false;
169static char buffer[DEFAULT_BUFFER_SIZE];
170static bool ignore_mib_parsing_errors = false;
171
172static char *fix_snmp_range(char *th) {
173 double left;
174 double right;
175 char *colon;
176 char *ret;
177
178 if ((colon = strchr(th, ':')) == NULL || *(colon + 1) == '\0')
179 return th;
180
181 left = strtod(th, NULL);
182 right = strtod(colon + 1, NULL);
183 if (right >= left)
184 return th;
185
186 if ((ret = malloc(strlen(th) + 2)) == NULL)
187 die(STATE_UNKNOWN, _("Cannot malloc"));
188 *colon = '\0';
189 sprintf(ret, "@%s:%s", colon + 1, th);
190 free(th);
191 return ret;
192} 248}
193 249
194int main(int argc, char **argv) { 250int main(int argc, char **argv) {
195 int len;
196 int total_oids;
197 size_t line;
198 unsigned int bk_count = 0;
199 unsigned int dq_count = 0;
200 int iresult = STATE_UNKNOWN;
201 int result = STATE_UNKNOWN;
202 int return_code = 0;
203 int external_error = 0;
204 char **command_line = NULL;
205 char *cl_hidden_auth = NULL;
206 char *oidname = NULL;
207 char *response = NULL;
208 char *mult_resp = NULL;
209 char *outbuff;
210 char *ptr = NULL;
211 char *show = NULL;
212 char *th_warn = NULL;
213 char *th_crit = NULL;
214 char type[8] = "";
215 output chld_out;
216 output chld_err;
217 char *previous_string = NULL;
218 char *ap = NULL;
219 char *state_string = NULL;
220 size_t response_length;
221 size_t current_length;
222 size_t string_length;
223 char *temp_string = NULL;
224 char *quote_string = NULL;
225 time_t current_time;
226 double temp_double;
227 time_t duration;
228 char *conv = "12345678";
229 int is_counter = 0;
230
231 setlocale(LC_ALL, ""); 251 setlocale(LC_ALL, "");
232 bindtextdomain(PACKAGE, LOCALEDIR); 252 bindtextdomain(PACKAGE, LOCALEDIR);
233 textdomain(PACKAGE); 253 textdomain(PACKAGE);
234 254
235 labels = malloc(labels_size * sizeof(*labels));
236 unitv = malloc(unitv_size * sizeof(*unitv));
237 thlds = malloc(thlds_size * sizeof(*thlds));
238 response_value = malloc(response_size * sizeof(*response_value));
239 previous_value = malloc(previous_size * sizeof(*previous_value));
240 eval_method = calloc(eval_size, sizeof(*eval_method));
241 oids = calloc(oids_size, sizeof(char *));
242
243 label = strdup("SNMP");
244 units = strdup("");
245 port = strdup(DEFAULT_PORT);
246 outbuff = strdup("");
247 delimiter = strdup(" = ");
248 output_delim = strdup(DEFAULT_OUTPUT_DELIMITER);
249 timeout_interval = DEFAULT_SOCKET_TIMEOUT; 255 timeout_interval = DEFAULT_SOCKET_TIMEOUT;
250 retries = DEFAULT_RETRIES;
251 256
252 np_init((char *)progname, argc, argv); 257 np_init((char *)progname, argc, argv);
253 258
259 state_key stateKey = np_enable_state(NULL, 1, progname, argc, argv);
260
254 /* Parse extra opts if any */ 261 /* Parse extra opts if any */
255 argv = np_extra_opts(&argc, argv, progname); 262 argv = np_extra_opts(&argc, argv, progname);
256 263
257 np_set_args(argc, argv); 264 np_set_args(argc, argv);
258 265
259 time(&current_time); 266 // Initialize net-snmp before touching the session we are going to use
267 init_snmp("check_snmp");
260 268
261 if (process_arguments(argc, argv) == ERROR) 269 process_arguments_wrapper paw_tmp = process_arguments(argc, argv);
270 if (paw_tmp.errorcode == ERROR) {
262 usage4(_("Could not parse arguments")); 271 usage4(_("Could not parse arguments"));
263
264 if (calculate_rate) {
265 if (!strcmp(label, "SNMP"))
266 label = strdup("SNMP RATE");
267
268 size_t i = 0;
269
270 previous_state = np_state_read();
271 if (previous_state != NULL) {
272 /* Split colon separated values */
273 previous_string = strdup((char *)previous_state->data);
274 while ((ap = strsep(&previous_string, ":")) != NULL) {
275 if (verbose > 2)
276 printf("State for %zd=%s\n", i, ap);
277 while (i >= previous_size) {
278 previous_size += OID_COUNT_STEP;
279 previous_value = realloc(previous_value, previous_size * sizeof(*previous_value));
280 }
281 previous_value[i++] = strtod(ap, NULL);
282 }
283 }
284 } 272 }
285 273
286 /* Populate the thresholds */ 274 check_snmp_config config = paw_tmp.config;
287 th_warn = warning_thresholds;
288 th_crit = critical_thresholds;
289 for (size_t i = 0; i < numoids; i++) {
290 char *w = th_warn ? strndup(th_warn, strcspn(th_warn, ",")) : NULL;
291 char *c = th_crit ? strndup(th_crit, strcspn(th_crit, ",")) : NULL;
292 /* translate "2:1" to "@1:2" for backwards compatibility */
293 w = w ? fix_snmp_range(w) : NULL;
294 c = c ? fix_snmp_range(c) : NULL;
295
296 while (i >= thlds_size) {
297 thlds_size += OID_COUNT_STEP;
298 thlds = realloc(thlds, thlds_size * sizeof(*thlds));
299 }
300
301 /* Skip empty thresholds, while avoiding segfault */
302 set_thresholds(&thlds[i], w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL, c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL);
303 if (w) {
304 th_warn = strchr(th_warn, ',');
305 if (th_warn)
306 th_warn++;
307 free(w);
308 }
309 if (c) {
310 th_crit = strchr(th_crit, ',');
311 if (th_crit)
312 th_crit++;
313 free(c);
314 }
315 }
316 275
317 /* Create the command array to execute */ 276 if (config.output_format_is_set) {
318 if (usesnmpgetnext) { 277 mp_set_format(config.output_format);
319 snmpcmd = strdup(PATH_TO_SNMPGETNEXT);
320 } else {
321 snmpcmd = strdup(PATH_TO_SNMPGET);
322 } 278 }
323 279
324 /* 10 arguments to pass before context and authpriv options + 1 for host and numoids. Add one for terminating NULL */ 280 /* Set signal handling and alarm */
325 281 if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
326 unsigned index = 0; 282 usage4(_("Cannot catch SIGALRM"));
327 command_line = calloc(11 + numcontext + numauthpriv + 1 + numoids + 1, sizeof(char *));
328
329 command_line[index++] = snmpcmd;
330 command_line[index++] = strdup("-Le");
331 command_line[index++] = strdup("-t");
332 xasprintf(&command_line[index++], "%d", timeout_interval);
333 command_line[index++] = strdup("-r");
334 xasprintf(&command_line[index++], "%d", retries);
335 command_line[index++] = strdup("-m");
336 command_line[index++] = strdup(miblist);
337 command_line[index++] = "-v";
338 command_line[index++] = strdup(proto);
339
340 xasprintf(&cl_hidden_auth, "%s -Le -t %d -r %d -m %s -v %s", snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''",
341 proto);
342
343 if (ignore_mib_parsing_errors) {
344 command_line[index++] = "-Pe";
345 xasprintf(&cl_hidden_auth, "%s -Pe", cl_hidden_auth);
346 } 283 }
347 284
348 for (int i = 0; i < numcontext; i++) { 285 time_t current_time;
349 command_line[index++] = contextargs[i]; 286 time(&current_time);
350 }
351 287
352 for (int i = 0; i < numauthpriv; i++) { 288 if (verbose > 2) {
353 command_line[index++] = authpriv[i]; 289 printf("current time: %s (timestamp: %lu)\n", ctime(&current_time), current_time);
354 } 290 }
355 291
356 xasprintf(&command_line[index++], "%s:%s", server_address, port); 292 snmp_responces response = do_snmp_query(config.snmp_params);
357 293
358 xasprintf(&cl_hidden_auth, "%s [context] [authpriv] %s:%s", cl_hidden_auth, server_address, port); 294 mp_check overall = mp_check_init();
359 295
360 for (size_t i = 0; i < numoids; i++) { 296 if (response.errorcode == OK) {
361 command_line[index++] = oids[i]; 297 mp_subcheck sc_successfull_query = mp_subcheck_init();
362 xasprintf(&cl_hidden_auth, "%s %s", cl_hidden_auth, oids[i]); 298 xasprintf(&sc_successfull_query.output, "SNMP query was successful");
299 sc_successfull_query = mp_set_subcheck_state(sc_successfull_query, STATE_OK);
300 mp_add_subcheck_to_check(&overall, sc_successfull_query);
301 } else {
302 // Error treatment here, either partial or whole
303 mp_subcheck sc_failed_query = mp_subcheck_init();
304 xasprintf(&sc_failed_query.output, "SNMP query failed");
305 sc_failed_query = mp_set_subcheck_state(sc_failed_query, STATE_OK);
306 mp_add_subcheck_to_check(&overall, sc_failed_query);
307 mp_exit(overall);
363 } 308 }
364 309
365 command_line[index++] = NULL; 310 check_snmp_state_entry *prev_state = NULL;
311 bool have_previous_state = false;
366 312
367 if (verbose) { 313 if (config.evaluation_params.calculate_rate) {
368 printf("%s\n", cl_hidden_auth); 314 state_data *previous_state = np_state_read(stateKey);
369 } 315 if (previous_state == NULL) {
316 // failed to recover state
317 // or no previous state
318 have_previous_state = false;
319 } else {
320 // sanity check
321 recover_state_data_type prev_state_wrapper =
322 recover_state_data(previous_state->data, (idx_t)previous_state->length);
370 323
371 /* Set signal handling and alarm */ 324 if (prev_state_wrapper.errorcode == OK) {
372 if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) { 325 have_previous_state = true;
373 usage4(_("Cannot catch SIGALRM")); 326 prev_state = prev_state_wrapper.state;
374 } 327 } else {
375 alarm(timeout_interval * retries + 5); 328 have_previous_state = false;
376 329 prev_state = NULL;
377 /* Run the command */
378 return_code = cmd_run_array(command_line, &chld_out, &chld_err, 0);
379
380 /* disable alarm again */
381 alarm(0);
382
383 /* Due to net-snmp sometimes showing stderr messages with poorly formed MIBs,
384 only return state unknown if return code is non zero or there is no stdout.
385 Do this way so that if there is stderr, will get added to output, which helps problem diagnosis
386 */
387 if (return_code != 0)
388 external_error = 1;
389 if (chld_out.lines == 0)
390 external_error = 1;
391 if (external_error) {
392 if (chld_err.lines > 0) {
393 printf(_("External command error: %s\n"), chld_err.line[0]);
394 for (size_t i = 1; i < chld_err.lines; i++) {
395 printf("%s\n", chld_err.line[i]);
396 } 330 }
397 } else {
398 printf(_("External command error with no output (return code: %d)\n"), return_code);
399 } 331 }
400 exit(STATE_UNKNOWN);
401 } 332 }
402 333
403 if (verbose) { 334 check_snmp_state_entry *new_state = NULL;
404 for (size_t i = 0; i < chld_out.lines; i++) { 335 if (config.evaluation_params.calculate_rate) {
405 printf("%s\n", chld_out.line[i]); 336 new_state = calloc(config.snmp_params.num_of_test_units, sizeof(check_snmp_state_entry));
337 if (new_state == NULL) {
338 die(STATE_UNKNOWN, "memory allocation failed");
406 } 339 }
407 } 340 }
408 341
409 line = 0; 342 // We got the the query results, now process them
410 total_oids = 0; 343 for (size_t loop_index = 0; loop_index < config.snmp_params.num_of_test_units; loop_index++) {
411 for (size_t i = 0; line < chld_out.lines && i < numoids; line++, i++, total_oids++) { 344 if (verbose > 0) {
412 if (calculate_rate) 345 printf("loop_index: %zu\n", loop_index);
413 conv = "%.10g";
414 else
415 conv = "%.0f";
416
417 ptr = chld_out.line[line];
418 oidname = strpcpy(oidname, ptr, delimiter);
419 response = strstr(ptr, delimiter);
420 if (response == NULL)
421 break;
422
423 if (verbose > 2) {
424 printf("Processing oid %zi (line %zi)\n oidname: %s\n response: %s\n", i + 1, line + 1, oidname, response);
425 } 346 }
426 347
427 /* Clean up type array - Sol10 does not necessarily zero it out */ 348 check_snmp_state_entry previous_unit_state = {};
428 bzero(type, sizeof(type)); 349 if (config.evaluation_params.calculate_rate && have_previous_state) {
429 350 previous_unit_state = prev_state[loop_index];
430 is_counter = 0; 351 }
431 /* We strip out the datatype indicator for PHBs */
432 if (strstr(response, "Gauge: ")) {
433 show = multiply(strstr(response, "Gauge: ") + 7);
434 } else if (strstr(response, "Gauge32: ")) {
435 show = multiply(strstr(response, "Gauge32: ") + 9);
436 } else if (strstr(response, "Counter32: ")) {
437 show = strstr(response, "Counter32: ") + 11;
438 is_counter = 1;
439 if (!calculate_rate)
440 strcpy(type, "c");
441 } else if (strstr(response, "Counter64: ")) {
442 show = strstr(response, "Counter64: ") + 11;
443 is_counter = 1;
444 if (!calculate_rate)
445 strcpy(type, "c");
446 } else if (strstr(response, "INTEGER: ")) {
447 show = multiply(strstr(response, "INTEGER: ") + 9);
448
449 if (fmtstr_set) {
450 conv = fmtstr;
451 }
452 } else if (strstr(response, "OID: ")) {
453 show = strstr(response, "OID: ") + 5;
454 } else if (strstr(response, "STRING: ")) {
455 show = strstr(response, "STRING: ") + 8;
456 conv = "%.10g";
457
458 /* Get the rest of the string on multi-line strings */
459 ptr = show;
460 COUNT_SEQ(ptr, bk_count, dq_count)
461 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
462 ptr++;
463 GOBBLE_TOS(ptr, "\n\"\\")
464 COUNT_SEQ(ptr, bk_count, dq_count)
465 }
466
467 if (dq_count) { /* unfinished line */
468 /* copy show verbatim first */
469 if (!mult_resp)
470 mult_resp = strdup("");
471 xasprintf(&mult_resp, "%s%s:\n%s\n", mult_resp, oids[i], show);
472 /* then strip out unmatched double-quote from single-line output */
473 if (show[0] == '"')
474 show++;
475
476 /* Keep reading until we match end of double-quoted string */
477 for (line++; line < chld_out.lines; line++) {
478 ptr = chld_out.line[line];
479 xasprintf(&mult_resp, "%s%s\n", mult_resp, ptr);
480
481 COUNT_SEQ(ptr, bk_count, dq_count)
482 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
483 ptr++;
484 GOBBLE_TOS(ptr, "\n\"\\")
485 COUNT_SEQ(ptr, bk_count, dq_count)
486 }
487 /* Break for loop before next line increment when done */
488 if (!dq_count)
489 break;
490 }
491 }
492
493 } else if (strstr(response, "Timeticks: ")) {
494 show = strstr(response, "Timeticks: ");
495 } else
496 show = response + 3;
497 352
498 iresult = STATE_DEPENDENT; 353 check_snmp_evaluation single_eval =
354 evaluate_single_unit(response.response_values[loop_index], config.evaluation_params,
355 config.snmp_params.test_units[loop_index], current_time,
356 previous_unit_state, have_previous_state);
499 357
500 /* Process this block for numeric comparisons */ 358 if (config.evaluation_params.calculate_rate &&
501 /* Make some special values,like Timeticks numeric only if a threshold is defined */ 359 mp_compute_subcheck_state(single_eval.sc) != STATE_UNKNOWN) {
502 if (thlds[i]->warning || thlds[i]->critical || calculate_rate) { 360 new_state[loop_index] = single_eval.state;
503 if (verbose > 2) {
504 print_thresholds(" thresholds", thlds[i]);
505 }
506 ptr = strpbrk(show, "-0123456789");
507 if (ptr == NULL) {
508 if (nulloid == 3)
509 die(STATE_UNKNOWN, _("No valid data returned (%s)\n"), show);
510 else if (nulloid == 0)
511 die(STATE_OK, _("No valid data returned (%s)\n"), show);
512 else if (nulloid == 1)
513 die(STATE_WARNING, _("No valid data returned (%s)\n"), show);
514 else if (nulloid == 2)
515 die(STATE_CRITICAL, _("No valid data returned (%s)\n"), show);
516 }
517 while (i >= response_size) {
518 response_size += OID_COUNT_STEP;
519 response_value = realloc(response_value, response_size * sizeof(*response_value));
520 }
521 response_value[i] = strtod(ptr, NULL) + offset;
522
523 if (calculate_rate) {
524 if (previous_state != NULL) {
525 duration = current_time - previous_state->time;
526 if (duration <= 0)
527 die(STATE_UNKNOWN, _("Time duration between plugin calls is invalid"));
528 temp_double = response_value[i] - previous_value[i];
529 /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */
530 if (is_counter) {
531 if (temp_double < (double)0.0)
532 temp_double += (double)4294967296.0; /* 2^32 */
533 if (temp_double < (double)0.0)
534 temp_double += (double)18446744069414584320.0; /* 2^64-2^32 */
535 ;
536 }
537 /* Convert to per second, then use multiplier */
538 temp_double = temp_double / duration * rate_multiplier;
539 iresult = get_status(temp_double, thlds[i]);
540 xasprintf(&show, conv, temp_double);
541 }
542 } else {
543 iresult = get_status(response_value[i], thlds[i]);
544 xasprintf(&show, conv, response_value[i]);
545 }
546 } 361 }
547 362
548 /* Process this block for string matching */ 363 mp_add_subcheck_to_check(&overall, single_eval.sc);
549 else if (eval_size > i && eval_method[i] & CRIT_STRING) { 364 }
550 if (strcmp(show, string_value))
551 iresult = (invert_search == 0) ? STATE_CRITICAL : STATE_OK;
552 else
553 iresult = (invert_search == 0) ? STATE_OK : STATE_CRITICAL;
554 }
555 365
556 /* Process this block for regex matching */ 366 if (config.evaluation_params.calculate_rate) {
557 else if (eval_size > i && eval_method[i] & CRIT_REGEX) { 367 // store state
558 excode = regexec(&preg, response, 10, pmatch, eflags); 368 gen_state_string_type current_state_wrapper =
559 if (excode == 0) { 369 gen_state_string(new_state, config.snmp_params.num_of_test_units);
560 iresult = (invert_search == 0) ? STATE_OK : STATE_CRITICAL;
561 } else if (excode != REG_NOMATCH) {
562 regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER);
563 printf(_("Execute Error: %s\n"), errbuf);
564 exit(STATE_CRITICAL);
565 } else {
566 iresult = (invert_search == 0) ? STATE_CRITICAL : STATE_OK;
567 }
568 }
569 370
570 /* Process this block for existence-nonexistence checks */ 371 if (current_state_wrapper.errorcode == OK) {
571 /* TV: Should this be outside of this else block? */ 372 np_state_write_string(stateKey, current_time, current_state_wrapper.state_string);
572 else { 373 } else {
573 if (eval_size > i && eval_method[i] & CRIT_PRESENT) 374 die(STATE_UNKNOWN, "failed to create state string");
574 iresult = STATE_CRITICAL;
575 else if (eval_size > i && eval_method[i] & WARN_PRESENT)
576 iresult = STATE_WARNING;
577 else if (response && iresult == STATE_DEPENDENT)
578 iresult = STATE_OK;
579 } 375 }
376 }
377 mp_exit(overall);
378}
580 379
581 /* Result is the worst outcome of all the OIDs tested */ 380/* process command-line arguments */
582 result = max_state(result, iresult); 381static process_arguments_wrapper process_arguments(int argc, char **argv) {
583 382 enum {
584 /* Prepend a label for this OID if there is one */ 383 /* Longopts only arguments */
585 if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL) 384 invert_search_index = CHAR_MAX + 1,
586 xasprintf(&outbuff, "%s%s%s %s%s%s", outbuff, (i == 0) ? " " : output_delim, labels[i], mark(iresult), show, mark(iresult)); 385 offset_index,
587 else 386 ignore_mib_parsing_errors_index,
588 xasprintf(&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim, mark(iresult), show, mark(iresult)); 387 connection_prefix_index,
589 388 output_format_index,
590 /* Append a unit string for this OID if there is one */ 389 calculate_rate,
591 if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL) 390 rate_multiplier
592 xasprintf(&outbuff, "%s %s", outbuff, unitv[i]); 391 };
593 392
594 /* Write perfdata with whatever can be parsed by strtod, if possible */ 393 static struct option longopts[] = {
595 ptr = NULL; 394 STD_LONG_OPTS,
596 strtod(show, &ptr); 395 {"community", required_argument, 0, 'C'},
597 if (ptr > show) { 396 {"oid", required_argument, 0, 'o'},
598 if (perf_labels && nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL) 397 {"object", required_argument, 0, 'o'},
599 temp_string = labels[i]; 398 {"delimiter", required_argument, 0, 'd'},
600 else 399 {"nulloid", required_argument, 0, 'z'},
601 temp_string = oidname; 400 {"output-delimiter", required_argument, 0, 'D'},
602 if (strpbrk(temp_string, " ='\"") == NULL) { 401 {"string", required_argument, 0, 's'},
603 strncat(perfstr, temp_string, sizeof(perfstr) - strlen(perfstr) - 1); 402 {"timeout", required_argument, 0, 't'},
604 } else { 403 {"regex", required_argument, 0, 'r'},
605 if (strpbrk(temp_string, "'") == NULL) { 404 {"ereg", required_argument, 0, 'r'},
606 quote_string = "'"; 405 {"eregi", required_argument, 0, 'R'},
607 } else { 406 {"label", required_argument, 0, 'l'},
608 quote_string = "\""; 407 {"units", required_argument, 0, 'u'},
609 } 408 {"port", required_argument, 0, 'p'},
610 strncat(perfstr, quote_string, sizeof(perfstr) - strlen(perfstr) - 1); 409 {"retries", required_argument, 0, 'e'},
611 strncat(perfstr, temp_string, sizeof(perfstr) - strlen(perfstr) - 1); 410 {"miblist", required_argument, 0, 'm'},
612 strncat(perfstr, quote_string, sizeof(perfstr) - strlen(perfstr) - 1); 411 {"protocol", required_argument, 0, 'P'},
613 } 412 {"context", required_argument, 0, 'N'},
614 strncat(perfstr, "=", sizeof(perfstr) - strlen(perfstr) - 1); 413 {"seclevel", required_argument, 0, 'L'},
615 len = sizeof(perfstr) - strlen(perfstr) - 1; 414 {"secname", required_argument, 0, 'U'},
616 strncat(perfstr, show, len > ptr - show ? ptr - show : len); 415 {"authproto", required_argument, 0, 'a'},
416 {"privproto", required_argument, 0, 'x'},
417 {"authpasswd", required_argument, 0, 'A'},
418 {"privpasswd", required_argument, 0, 'X'},
419 {"next", no_argument, 0, 'n'},
420 {"offset", required_argument, 0, offset_index},
421 {"invert-search", no_argument, 0, invert_search_index},
422 {"perf-oids", no_argument, 0, 'O'},
423 {"ipv4", no_argument, 0, '4'},
424 {"ipv6", no_argument, 0, '6'},
425 {"multiplier", required_argument, 0, 'M'},
426 {"ignore-mib-parsing-errors", no_argument, 0, ignore_mib_parsing_errors_index},
427 {"connection-prefix", required_argument, 0, connection_prefix_index},
428 {"output-format", required_argument, 0, output_format_index},
429 {"rate", no_argument, 0, calculate_rate},
430 {"rate-multiplier", required_argument, 0, rate_multiplier},
431 {0, 0, 0, 0}};
432
433 if (argc < 2) {
434 process_arguments_wrapper result = {
435 .errorcode = ERROR,
436 };
437 return result;
438 }
617 439
618 if (strcmp(type, "") != 0) { 440 // Count number of OIDs here first
619 strncat(perfstr, type, sizeof(perfstr) - strlen(perfstr) - 1); 441 int option = 0;
620 } 442 size_t oid_counter = 0;
443 while (true) {
444 int option_char = getopt_long(
445 argc, argv,
446 "nhvVO46t:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:N:L:U:a:x:A:X:M:f:z:", longopts, &option);
621 447
622 if (warning_thresholds) { 448 if (option_char == -1 || option_char == EOF) {
623 strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1); 449 break;
624 if (thlds[i]->warning && thlds[i]->warning->text) 450 }
625 strncat(perfstr, thlds[i]->warning->text, sizeof(perfstr) - strlen(perfstr) - 1);
626 }
627 451
628 if (critical_thresholds) { 452 switch (option_char) {
629 if (!warning_thresholds) 453 case 'o': {
630 strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1); 454 // we are going to parse this again, so we work on a copy of that string
631 strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1); 455 char *tmp_oids = strdup(optarg);
632 if (thlds[i]->critical && thlds[i]->critical->text) 456 if (tmp_oids == NULL) {
633 strncat(perfstr, thlds[i]->critical->text, sizeof(perfstr) - strlen(perfstr) - 1); 457 die(STATE_UNKNOWN, "strdup failed");
634 } 458 }
635 459
636 strncat(perfstr, " ", sizeof(perfstr) - strlen(perfstr) - 1); 460 for (char *ptr = strtok(tmp_oids, ", "); ptr != NULL;
637 } 461 ptr = strtok(NULL, ", "), oid_counter++) {
638 }
639
640 /* Save state data, as all data collected now */
641 if (calculate_rate) {
642 string_length = 1024;
643 state_string = malloc(string_length);
644 if (state_string == NULL)
645 die(STATE_UNKNOWN, _("Cannot malloc"));
646
647 current_length = 0;
648 for (int i = 0; i < total_oids; i++) {
649 xasprintf(&temp_string, "%.0f", response_value[i]);
650 if (temp_string == NULL)
651 die(STATE_UNKNOWN, _("Cannot asprintf()"));
652 response_length = strlen(temp_string);
653 if (current_length + response_length > string_length) {
654 string_length = current_length + 1024;
655 state_string = realloc(state_string, string_length);
656 if (state_string == NULL)
657 die(STATE_UNKNOWN, _("Cannot realloc()"));
658 } 462 }
659 strcpy(&state_string[current_length], temp_string); 463 break;
660 current_length = current_length + response_length;
661 state_string[current_length] = ':';
662 current_length++;
663 free(temp_string);
664 } 464 }
665 state_string[--current_length] = '\0'; 465 case '?': /* usage */
666 if (verbose > 2) 466 usage5();
667 printf("State string=%s\n", state_string); 467 // fallthrough
468 case 'h': /* help */
469 print_help();
470 exit(STATE_UNKNOWN);
471 case 'V': /* version */
472 print_revision(progname, NP_VERSION);
473 exit(STATE_UNKNOWN);
668 474
669 /* This is not strictly the same as time now, but any subtle variations will cancel out */ 475 default:
670 np_state_write_string(current_time, state_string); 476 continue;
671 if (previous_state == NULL) {
672 /* Or should this be highest state? */
673 die(STATE_OK, _("No previous data to calculate rate - assume okay"));
674 } 477 }
675 } 478 }
676 479
677 printf("%s %s -%s %s\n", label, state_text(result), outbuff, perfstr); 480 /* Check whether at least one OID was given */
678 if (mult_resp) 481 if (oid_counter == 0) {
679 printf("%s", mult_resp); 482 die(STATE_UNKNOWN, _("No OIDs specified\n"));
483 }
680 484
681 return result; 485 // Allocate space for test units
682} 486 check_snmp_test_unit *tmp = calloc(oid_counter, sizeof(check_snmp_test_unit));
487 if (tmp == NULL) {
488 die(STATE_UNKNOWN, "Failed to calloc");
489 }
683 490
684/* process command-line arguments */ 491 for (size_t i = 0; i < oid_counter; i++) {
685int process_arguments(int argc, char **argv) { 492 tmp[i] = check_snmp_test_unit_init();
686 static struct option longopts[] = {STD_LONG_OPTS,
687 {"community", required_argument, 0, 'C'},
688 {"oid", required_argument, 0, 'o'},
689 {"object", required_argument, 0, 'o'},
690 {"delimiter", required_argument, 0, 'd'},
691 {"nulloid", required_argument, 0, 'z'},
692 {"output-delimiter", required_argument, 0, 'D'},
693 {"string", required_argument, 0, 's'},
694 {"timeout", required_argument, 0, 't'},
695 {"regex", required_argument, 0, 'r'},
696 {"ereg", required_argument, 0, 'r'},
697 {"eregi", required_argument, 0, 'R'},
698 {"label", required_argument, 0, 'l'},
699 {"units", required_argument, 0, 'u'},
700 {"port", required_argument, 0, 'p'},
701 {"retries", required_argument, 0, 'e'},
702 {"miblist", required_argument, 0, 'm'},
703 {"protocol", required_argument, 0, 'P'},
704 {"context", required_argument, 0, 'N'},
705 {"seclevel", required_argument, 0, 'L'},
706 {"secname", required_argument, 0, 'U'},
707 {"authproto", required_argument, 0, 'a'},
708 {"privproto", required_argument, 0, 'x'},
709 {"authpasswd", required_argument, 0, 'A'},
710 {"privpasswd", required_argument, 0, 'X'},
711 {"next", no_argument, 0, 'n'},
712 {"rate", no_argument, 0, L_CALCULATE_RATE},
713 {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER},
714 {"offset", required_argument, 0, L_OFFSET},
715 {"invert-search", no_argument, 0, L_INVERT_SEARCH},
716 {"perf-oids", no_argument, 0, 'O'},
717 {"ipv4", no_argument, 0, '4'},
718 {"ipv6", no_argument, 0, '6'},
719 {"multiplier", required_argument, 0, 'M'},
720 {"fmtstr", required_argument, 0, 'f'},
721 {"ignore-mib-parsing-errors", no_argument, false, L_IGNORE_MIB_PARSING_ERRORS},
722 {0, 0, 0, 0}};
723
724 if (argc < 2)
725 return ERROR;
726
727 /* reverse compatibility for very old non-POSIX usage forms */
728 for (int c = 1; c < argc; c++) {
729 if (strcmp("-to", argv[c]) == 0)
730 strcpy(argv[c], "-t");
731 if (strcmp("-wv", argv[c]) == 0)
732 strcpy(argv[c], "-w");
733 if (strcmp("-cv", argv[c]) == 0)
734 strcpy(argv[c], "-c");
735 } 493 }
736 494
737 size_t j = 0; 495 check_snmp_config config = check_snmp_config_init();
738 size_t jj = 0; 496 config.snmp_params.test_units = tmp;
497 config.snmp_params.num_of_test_units = oid_counter;
498
499 option = 0;
500 optind = 1; // Reset argument scanner
501 size_t tmp_oid_counter = 0;
502 size_t eval_counter = 0;
503 size_t unitv_counter = 0;
504 size_t labels_counter = 0;
505 unsigned char *authpasswd = NULL;
506 unsigned char *privpasswd = NULL;
507 int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
508 char *port = NULL;
509 char *miblist = NULL;
510 char *connection_prefix = NULL;
511 bool snmp_version_set_explicitely = false;
512 // TODO error checking
739 while (true) { 513 while (true) {
740 int option = 0; 514 int option_char = getopt_long(
741 int option_char = getopt_long(argc, argv, "nhvVO46t:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:N:L:U:a:x:A:X:M:f:z:", longopts, &option); 515 argc, argv,
516 "nhvVO46t:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:N:L:U:a:x:A:X:M:f:z:", longopts, &option);
742 517
743 if (option_char == -1 || option_char == EOF) 518 if (option_char == -1 || option_char == EOF) {
744 break; 519 break;
520 }
745 521
746 switch (option_char) { 522 switch (option_char) {
747 case '?': /* usage */ 523 case '?': /* usage */
@@ -758,64 +534,155 @@ int process_arguments(int argc, char **argv) {
758 534
759 /* Connection info */ 535 /* Connection info */
760 case 'C': /* group or community */ 536 case 'C': /* group or community */
761 community = optarg; 537 config.snmp_params.snmp_session.community = (unsigned char *)optarg;
538 config.snmp_params.snmp_session.community_len = strlen(optarg);
762 break; 539 break;
763 case 'H': /* Host or server */ 540 case 'H': /* Host or server */
764 server_address = optarg; 541 config.snmp_params.snmp_session.peername = optarg;
765 break; 542 break;
766 case 'p': /* TCP port number */ 543 case 'p': /*port number */
544 // Add port to "peername" below to not rely on argument order
767 port = optarg; 545 port = optarg;
768 break; 546 break;
769 case 'm': /* List of MIBS */ 547 case 'm': /* List of MIBS */
770 miblist = optarg; 548 miblist = optarg;
771 break; 549 break;
772 case 'n': /* usesnmpgetnext */ 550 case 'n': /* use_getnext instead of get */
773 usesnmpgetnext = true; 551 config.snmp_params.use_getnext = true;
774 break; 552 break;
775 case 'P': /* SNMP protocol version */ 553 case 'P': /* SNMP protocol version */
776 proto = optarg; 554 if (strcasecmp("1", optarg) == 0) {
555 config.snmp_params.snmp_session.version = SNMP_VERSION_1;
556 } else if (strcasecmp("2c", optarg) == 0) {
557 config.snmp_params.snmp_session.version = SNMP_VERSION_2c;
558 } else if (strcasecmp("3", optarg) == 0) {
559 config.snmp_params.snmp_session.version = SNMP_VERSION_3;
560 } else {
561 die(STATE_UNKNOWN, "invalid SNMP version/protocol: %s", optarg);
562 }
563 snmp_version_set_explicitely = true;
564
777 break; 565 break;
778 case 'N': /* SNMPv3 context */ 566 case 'N': /* SNMPv3 context name */
779 context = optarg; 567 config.snmp_params.snmp_session.contextName = optarg;
568 config.snmp_params.snmp_session.contextNameLen = strlen(optarg);
780 break; 569 break;
781 case 'L': /* security level */ 570 case 'L': /* security level */
782 seclevel = optarg; 571 if (strcasecmp("noAuthNoPriv", optarg) == 0) {
572 config.snmp_params.snmp_session.securityLevel = SNMP_SEC_LEVEL_NOAUTH;
573 } else if (strcasecmp("authNoPriv", optarg) == 0) {
574 config.snmp_params.snmp_session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
575 } else if (strcasecmp("authPriv", optarg) == 0) {
576 config.snmp_params.snmp_session.securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
577 } else {
578 die(STATE_UNKNOWN, "invalid security level: %s", optarg);
579 }
783 break; 580 break;
784 case 'U': /* security username */ 581 case 'U': /* security username */
785 secname = optarg; 582 config.snmp_params.snmp_session.securityName = optarg;
583 config.snmp_params.snmp_session.securityNameLen = strlen(optarg);
786 break; 584 break;
787 case 'a': /* auth protocol */ 585 case 'a': /* auth protocol */
788 authproto = optarg; 586 // SNMPv3: SHA or MD5
587 // TODO Test for availability of individual protocols
588 if (strcasecmp("MD5", optarg) == 0) {
589 config.snmp_params.snmp_session.securityAuthProto = usmHMACMD5AuthProtocol;
590 config.snmp_params.snmp_session.securityAuthProtoLen =
591 OID_LENGTH(usmHMACMD5AuthProtocol);
592 } else if (strcasecmp("SHA", optarg) == 0) {
593 config.snmp_params.snmp_session.securityAuthProto = usmHMACSHA1AuthProtocol;
594 config.snmp_params.snmp_session.securityAuthProtoLen =
595 OID_LENGTH(usmHMACSHA1AuthProtocol);
596 } else if (strcasecmp("SHA224", optarg) == 0) {
597 config.snmp_params.snmp_session.securityAuthProto = usmHMAC128SHA224AuthProtocol;
598 config.snmp_params.snmp_session.securityAuthProtoLen =
599 OID_LENGTH(usmHMAC128SHA224AuthProtocol);
600 } else if (strcasecmp("SHA256", optarg) == 0) {
601 config.snmp_params.snmp_session.securityAuthProto = usmHMAC192SHA256AuthProtocol;
602 config.snmp_params.snmp_session.securityAuthProtoLen =
603 OID_LENGTH(usmHMAC192SHA256AuthProtocol);
604 } else if (strcasecmp("SHA384", optarg) == 0) {
605 config.snmp_params.snmp_session.securityAuthProto = usmHMAC256SHA384AuthProtocol;
606 config.snmp_params.snmp_session.securityAuthProtoLen =
607 OID_LENGTH(usmHMAC256SHA384AuthProtocol);
608 } else if (strcasecmp("SHA512", optarg) == 0) {
609 config.snmp_params.snmp_session.securityAuthProto = usmHMAC384SHA512AuthProtocol;
610 config.snmp_params.snmp_session.securityAuthProtoLen =
611 OID_LENGTH(usmHMAC384SHA512AuthProtocol);
612 } else {
613 die(STATE_UNKNOWN, "Unknown authentication protocol");
614 }
789 break; 615 break;
790 case 'x': /* priv protocol */ 616 case 'x': /* priv protocol */
791 privproto = optarg; 617 if (strcasecmp("DES", optarg) == 0) {
618#ifdef HAVE_USM_DES_PRIV_PROTOCOL
619 config.snmp_params.snmp_session.securityAuthProto = usmDESPrivProtocol;
620 config.snmp_params.snmp_session.securityAuthProtoLen =
621 OID_LENGTH(usmDESPrivProtocol);
622#else
623 die(STATE_UNKNOWN, "DES Privacy Protocol not available on this platform");
624#endif
625 } else if (strcasecmp("AES", optarg) == 0) {
626 config.snmp_params.snmp_session.securityAuthProto = usmAESPrivProtocol;
627 config.snmp_params.snmp_session.securityAuthProtoLen =
628 OID_LENGTH(usmAESPrivProtocol);
629 // } else if (strcasecmp("AES128", optarg)) {
630 // config.snmp_session.securityAuthProto = usmAES128PrivProtocol;
631 // config.snmp_session.securityAuthProtoLen = OID_LENGTH(usmAES128PrivProtocol)
632 // / OID_LENGTH(oid);
633 } else if (strcasecmp("AES192", optarg) == 0) {
634 config.snmp_params.snmp_session.securityAuthProto = usmAES192PrivProtocol;
635 config.snmp_params.snmp_session.securityAuthProtoLen =
636 OID_LENGTH(usmAES192PrivProtocol);
637 } else if (strcasecmp("AES256", optarg) == 0) {
638 config.snmp_params.snmp_session.securityAuthProto = usmAES256PrivProtocol;
639 config.snmp_params.snmp_session.securityAuthProtoLen =
640 OID_LENGTH(usmAES256PrivProtocol);
641 // } else if (strcasecmp("AES192Cisco", optarg)) {
642 // config.snmp_session.securityAuthProto = usmAES192CiscoPrivProtocol;
643 // config.snmp_session.securityAuthProtoLen =
644 // sizeof(usmAES192CiscoPrivProtocol) / sizeof(oid); } else if
645 // (strcasecmp("AES256Cisco", optarg)) { config.snmp_session.securityAuthProto =
646 // usmAES256CiscoPrivProtocol; config.snmp_session.securityAuthProtoLen =
647 // sizeof(usmAES256CiscoPrivProtocol) / sizeof(oid); } else if
648 // (strcasecmp("AES192Cisco2", optarg)) { config.snmp_session.securityAuthProto
649 // = usmAES192Cisco2PrivProtocol; config.snmp_session.securityAuthProtoLen =
650 // sizeof(usmAES192Cisco2PrivProtocol) / sizeof(oid); } else if
651 // (strcasecmp("AES256Cisco2", optarg)) { config.snmp_session.securityAuthProto
652 // = usmAES256Cisco2PrivProtocol; config.snmp_session.securityAuthProtoLen =
653 // sizeof(usmAES256Cisco2PrivProtocol) / sizeof(oid);
654 } else {
655 die(STATE_UNKNOWN, "Unknown privacy protocol");
656 }
792 break; 657 break;
793 case 'A': /* auth passwd */ 658 case 'A': /* auth passwd */
794 authpasswd = optarg; 659 authpasswd = (unsigned char *)optarg;
795 break; 660 break;
796 case 'X': /* priv passwd */ 661 case 'X': /* priv passwd */
797 privpasswd = optarg; 662 privpasswd = (unsigned char *)optarg;
663 break;
664 case 'e':
665 case 'E':
666 if (!is_integer(optarg)) {
667 usage2(_("Retries interval must be a positive integer"), optarg);
668 } else {
669 config.snmp_params.snmp_session.retries = atoi(optarg);
670 }
798 break; 671 break;
799 case 't': /* timeout period */ 672 case 't': /* timeout period */
800 if (!is_integer(optarg)) 673 if (!is_integer(optarg)) {
801 usage2(_("Timeout interval must be a positive integer"), optarg); 674 usage2(_("Timeout interval must be a positive integer"), optarg);
802 else 675 } else {
803 timeout_interval = atoi(optarg); 676 timeout_interval = (unsigned int)atoi(optarg);
677 }
804 break; 678 break;
805 679
806 /* Test parameters */ 680 /* Test parameters */
807 case 'c': /* critical threshold */ 681 case 'c': /* critical threshold */
808 critical_thresholds = optarg; 682 check_snmp_set_thresholds(optarg, config.snmp_params.test_units, oid_counter, true);
809 break; 683 break;
810 case 'w': /* warning threshold */ 684 case 'w': /* warning threshold */
811 warning_thresholds = optarg; 685 check_snmp_set_thresholds(optarg, config.snmp_params.test_units, oid_counter, false);
812 break;
813 case 'e': /* PRELIMINARY - may change */
814 case 'E': /* PRELIMINARY - may change */
815 if (!is_integer(optarg))
816 usage2(_("Retries interval must be a positive integer"), optarg);
817 else
818 retries = atoi(optarg);
819 break; 686 break;
820 case 'o': /* object identifier */ 687 case 'o': /* object identifier */
821 if (strspn(optarg, "0123456789.,") != strlen(optarg)) { 688 if (strspn(optarg, "0123456789.,") != strlen(optarg)) {
@@ -824,306 +691,292 @@ int process_arguments(int argc, char **argv) {
824 * so we have a mib variable, rather than just an SNMP OID, 691 * so we have a mib variable, rather than just an SNMP OID,
825 * so we have to actually read the mib files 692 * so we have to actually read the mib files
826 */ 693 */
827 needmibs = true; 694 config.snmp_params.need_mibs = true;
828 }
829 for (char *ptr = strtok(optarg, ", "); ptr != NULL; ptr = strtok(NULL, ", "), j++) {
830 while (j >= oids_size) {
831 oids_size += OID_COUNT_STEP;
832 oids = realloc(oids, oids_size * sizeof(*oids));
833 }
834 oids[j] = strdup(ptr);
835 } 695 }
836 numoids = j; 696
837 if (option_char == 'E' || option_char == 'e') { 697 for (char *ptr = strtok(optarg, ", "); ptr != NULL;
838 jj++; 698 ptr = strtok(NULL, ", "), tmp_oid_counter++) {
839 while (j + 1 >= eval_size) { 699 config.snmp_params.test_units[tmp_oid_counter].oid = strdup(ptr);
840 eval_size += OID_COUNT_STEP;
841 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
842 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8);
843 }
844 if (option_char == 'E')
845 eval_method[j + 1] |= WARN_PRESENT;
846 else if (option_char == 'e')
847 eval_method[j + 1] |= CRIT_PRESENT;
848 } 700 }
849 break; 701 break;
850 case 'z': /* Null OID Return Check */ 702 case 'z': /* Null OID Return Check */
851 if (!is_integer(optarg)) 703 if (!is_integer(optarg)) {
852 usage2(_("Exit status must be a positive integer"), optarg); 704 usage2(_("Exit status must be a positive integer"), optarg);
853 else 705 } else {
854 nulloid = atoi(optarg); 706 config.evaluation_params.nulloid_result = atoi(optarg);
707 }
855 break; 708 break;
856 case 's': /* string or substring */ 709 case 's': /* string or substring */
857 strncpy(string_value, optarg, sizeof(string_value) - 1); 710 strncpy(config.evaluation_params.string_cmp_value, optarg,
858 string_value[sizeof(string_value) - 1] = 0; 711 sizeof(config.evaluation_params.string_cmp_value) - 1);
859 while (jj >= eval_size) { 712 config.evaluation_params
860 eval_size += OID_COUNT_STEP; 713 .string_cmp_value[sizeof(config.evaluation_params.string_cmp_value) - 1] = 0;
861 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method)); 714 config.snmp_params.test_units[eval_counter++].eval_mthd.crit_string = true;
862 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8);
863 }
864 eval_method[jj++] = CRIT_STRING;
865 break; 715 break;
866 case 'R': /* regex */ 716 case 'R': /* regex */
867 cflags = REG_ICASE; 717 cflags = REG_ICASE;
868 // fall through 718 // fall through
869 case 'r': /* regex */ 719 case 'r': /* regex */
720 {
721 char regex_expect[MAX_INPUT_BUFFER] = "";
870 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 722 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
871 strncpy(regex_expect, optarg, sizeof(regex_expect) - 1); 723 strncpy(regex_expect, optarg, sizeof(regex_expect) - 1);
872 regex_expect[sizeof(regex_expect) - 1] = 0; 724 regex_expect[sizeof(regex_expect) - 1] = 0;
873 errcode = regcomp(&preg, regex_expect, cflags); 725 int errcode = regcomp(&config.evaluation_params.regex_cmp_value, regex_expect, cflags);
874 if (errcode != 0) { 726 if (errcode != 0) {
875 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER); 727 char errbuf[MAX_INPUT_BUFFER] = "";
876 printf(_("Could Not Compile Regular Expression")); 728 regerror(errcode, &config.evaluation_params.regex_cmp_value, errbuf,
877 return ERROR; 729 MAX_INPUT_BUFFER);
878 } 730 printf("Could Not Compile Regular Expression: %s", errbuf);
879 while (jj >= eval_size) { 731 process_arguments_wrapper result = {
880 eval_size += OID_COUNT_STEP; 732 .errorcode = ERROR,
881 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method)); 733 };
882 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8); 734 return result;
883 } 735 }
884 eval_method[jj++] = CRIT_REGEX; 736 config.snmp_params.test_units[eval_counter++].eval_mthd.crit_regex = true;
885 break; 737 } break;
886
887 /* Format */
888 case 'd': /* delimiter */
889 delimiter = strscpy(delimiter, optarg);
890 break;
891 case 'D': /* output-delimiter */
892 output_delim = strscpy(output_delim, optarg);
893 break;
894 case 'l': /* label */ 738 case 'l': /* label */
895 nlabels++; 739 {
896 if (nlabels > labels_size) { 740 if (labels_counter >= config.snmp_params.num_of_test_units) {
897 labels_size += 8; 741 break;
898 labels = realloc(labels, labels_size * sizeof(*labels)); 742 }
899 if (labels == NULL) 743 char *ptr = trim_whitespaces_and_check_quoting(optarg);
900 die(STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels); 744 if (ptr[0] == '\'') {
745 config.snmp_params.test_units[labels_counter].label = ptr + 1;
746 } else {
747 config.snmp_params.test_units[labels_counter].label = ptr;
901 } 748 }
902 labels[nlabels - 1] = optarg; 749
903 char *ptr = thisarg(optarg); 750 while (ptr && (ptr = get_next_argument(ptr))) {
904 labels[nlabels - 1] = ptr; 751 labels_counter++;
905 if (ptr[0] == '\'') 752 ptr = trim_whitespaces_and_check_quoting(ptr);
906 labels[nlabels - 1] = ptr + 1; 753 if (ptr[0] == '\'') {
907 while (ptr && (ptr = nextarg(ptr))) { 754 config.snmp_params.test_units[labels_counter].label = ptr + 1;
908 nlabels++; 755 } else {
909 if (nlabels > labels_size) { 756 config.snmp_params.test_units[labels_counter].label = ptr;
910 labels_size += 8;
911 labels = realloc(labels, labels_size * sizeof(*labels));
912 if (labels == NULL)
913 die(STATE_UNKNOWN, _("Could not reallocate labels\n"));
914 } 757 }
915 ptr = thisarg(ptr);
916 if (ptr[0] == '\'')
917 labels[nlabels - 1] = ptr + 1;
918 else
919 labels[nlabels - 1] = ptr;
920 } 758 }
921 break; 759 labels_counter++;
760 } break;
922 case 'u': /* units */ 761 case 'u': /* units */
923 units = optarg; 762 {
924 nunits++; 763 if (unitv_counter >= config.snmp_params.num_of_test_units) {
925 if (nunits > unitv_size) { 764 break;
926 unitv_size += 8;
927 unitv = realloc(unitv, unitv_size * sizeof(*unitv));
928 if (unitv == NULL)
929 die(STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits);
930 } 765 }
931 unitv[nunits - 1] = optarg; 766 char *ptr = trim_whitespaces_and_check_quoting(optarg);
932 ptr = thisarg(optarg); 767 if (ptr[0] == '\'') {
933 unitv[nunits - 1] = ptr; 768 config.snmp_params.test_units[unitv_counter].unit_value = ptr + 1;
934 if (ptr[0] == '\'') 769 } else {
935 unitv[nunits - 1] = ptr + 1; 770 config.snmp_params.test_units[unitv_counter].unit_value = ptr;
936 while (ptr && (ptr = nextarg(ptr))) { 771 }
937 if (nunits > unitv_size) { 772 while (ptr && (ptr = get_next_argument(ptr))) {
938 unitv_size += 8; 773 unitv_counter++;
939 unitv = realloc(unitv, unitv_size * sizeof(*unitv)); 774 ptr = trim_whitespaces_and_check_quoting(ptr);
940 if (units == NULL) 775 if (ptr[0] == '\'') {
941 die(STATE_UNKNOWN, _("Could not realloc() units\n")); 776 config.snmp_params.test_units[unitv_counter].unit_value = ptr + 1;
777 } else {
778 config.snmp_params.test_units[unitv_counter].unit_value = ptr;
942 } 779 }
943 nunits++;
944 ptr = thisarg(ptr);
945 if (ptr[0] == '\'')
946 unitv[nunits - 1] = ptr + 1;
947 else
948 unitv[nunits - 1] = ptr;
949 } 780 }
781 unitv_counter++;
782 } break;
783 case offset_index:
784 config.evaluation_params.offset = strtod(optarg, NULL);
785 config.evaluation_params.offset_set = true;
950 break; 786 break;
951 case L_CALCULATE_RATE: 787 case invert_search_index:
952 if (calculate_rate == 0) 788 config.evaluation_params.invert_search = false;
953 np_enable_state(NULL, 1);
954 calculate_rate = 1;
955 break;
956 case L_RATE_MULTIPLIER:
957 if (!is_integer(optarg) || ((rate_multiplier = atoi(optarg)) <= 0))
958 usage2(_("Rate multiplier must be a positive integer"), optarg);
959 break;
960 case L_OFFSET:
961 offset = strtod(optarg, NULL);
962 break;
963 case L_INVERT_SEARCH:
964 invert_search = 1;
965 break; 789 break;
966 case 'O': 790 case 'O':
967 perf_labels = 0; 791 config.evaluation_params.use_oid_as_perf_data_label = true;
968 break; 792 break;
969 case '4': 793 case '4':
794 // The default, do something here to be exclusive to -6 instead of doing nothing?
795 connection_prefix = "udp";
970 break; 796 break;
971 case '6': 797 case '6':
972 xasprintf(&ip_version, "udp6:"); 798 connection_prefix = "udp6";
973 if (verbose > 2) 799 break;
974 printf("IPv6 detected! Will pass \"udp6:\" to snmpget.\n"); 800 case connection_prefix_index:
801 connection_prefix = optarg;
975 break; 802 break;
976 case 'M': 803 case 'M':
977 if (strspn(optarg, "0123456789.,") == strlen(optarg)) { 804 if (strspn(optarg, "0123456789.,") == strlen(optarg)) {
978 multiplier = strtod(optarg, NULL); 805 config.evaluation_params.multiplier = strtod(optarg, NULL);
806 config.evaluation_params.multiplier_set = true;
979 } 807 }
980 break; 808 break;
981 case 'f': 809 case ignore_mib_parsing_errors_index:
982 if (multiplier != 1.0) { 810 config.snmp_params.ignore_mib_parsing_errors = true;
983 fmtstr = optarg; 811 break;
984 fmtstr_set = true; 812 case 'f': // Deprecated format option for floating point values
813 break;
814 case output_format_index: {
815 parsed_output_format parser = mp_parse_output_format(optarg);
816 if (!parser.parsing_success) {
817 // TODO List all available formats here, maybe add anothoer usage function
818 printf("Invalid output format: %s\n", optarg);
819 exit(STATE_UNKNOWN);
820 }
821
822 config.output_format_is_set = true;
823 config.output_format = parser.output_format;
824 break;
825 }
826 case calculate_rate:
827 config.evaluation_params.calculate_rate = true;
828 break;
829 case rate_multiplier:
830 if (!is_integer(optarg) ||
831 ((config.evaluation_params.rate_multiplier = (unsigned int)atoi(optarg)) <= 0)) {
832 usage2(_("Rate multiplier must be a positive integer"), optarg);
985 } 833 }
986 break; 834 break;
987 case L_IGNORE_MIB_PARSING_ERRORS: 835 default:
988 ignore_mib_parsing_errors = true; 836 die(STATE_UNKNOWN, "Unknown option");
989 } 837 }
990 } 838 }
991 839
992 if (server_address == NULL) 840 if (config.snmp_params.snmp_session.peername == NULL) {
993 server_address = argv[optind]; 841 config.snmp_params.snmp_session.peername = argv[optind];
994 842 }
995 if (community == NULL)
996 community = strdup(DEFAULT_COMMUNITY);
997
998 return validate_arguments();
999}
1000
1001/******************************************************************************
1002
1003@@-
1004<sect3>
1005<title>validate_arguments</title>
1006
1007<para>&PROTO_validate_arguments;</para>
1008
1009<para>Checks to see if the default miblist needs to be loaded. Also verifies
1010the authentication and authorization combinations based on protocol version
1011selected.</para>
1012
1013<para></para>
1014
1015</sect3>
1016-@@
1017******************************************************************************/
1018 843
1019static int validate_arguments() { 844 // Build true peername here if necessary
1020 /* check whether to load locally installed MIBS (CPU/disk intensive) */ 845 if (connection_prefix != NULL) {
1021 if (miblist == NULL) { 846 // We got something in the connection prefix
1022 if (needmibs) { 847 if (strcasecmp(connection_prefix, "udp") == 0) {
1023 miblist = strdup(DEFAULT_MIBLIST); 848 // The default, do nothing
849 } else if (strcasecmp(connection_prefix, "tcp") == 0) {
850 // use tcp/ipv4
851 xasprintf(&config.snmp_params.snmp_session.peername, "tcp:%s",
852 config.snmp_params.snmp_session.peername);
853 } else if (strcasecmp(connection_prefix, "tcp6") == 0 ||
854 strcasecmp(connection_prefix, "tcpv6") == 0 ||
855 strcasecmp(connection_prefix, "tcpipv6") == 0 ||
856 strcasecmp(connection_prefix, "udp6") == 0 ||
857 strcasecmp(connection_prefix, "udpipv6") == 0 ||
858 strcasecmp(connection_prefix, "udpv6") == 0) {
859 // Man page (or net-snmp) code says IPv6 addresses should be wrapped in [], but it
860 // works anyway therefore do nothing here
861 xasprintf(&config.snmp_params.snmp_session.peername, "%s:%s", connection_prefix,
862 config.snmp_params.snmp_session.peername);
863 } else if (strcmp(connection_prefix, "tls") == 0) {
864 // TODO: Anything else to do here?
865 xasprintf(&config.snmp_params.snmp_session.peername, "tls:%s",
866 config.snmp_params.snmp_session.peername);
867 } else if (strcmp(connection_prefix, "dtls") == 0) {
868 // TODO: Anything else to do here?
869 xasprintf(&config.snmp_params.snmp_session.peername, "dtls:%s",
870 config.snmp_params.snmp_session.peername);
871 } else if (strcmp(connection_prefix, "unix") == 0) {
872 // TODO: Check whether this is a valid path?
873 xasprintf(&config.snmp_params.snmp_session.peername, "unix:%s",
874 config.snmp_params.snmp_session.peername);
875 } else if (strcmp(connection_prefix, "ipx") == 0) {
876 xasprintf(&config.snmp_params.snmp_session.peername, "ipx:%s",
877 config.snmp_params.snmp_session.peername);
1024 } else { 878 } else {
1025 miblist = ""; /* don't read any mib files for numeric oids */ 879 // Don't know that prefix, die here
880 die(STATE_UNKNOWN, "Unknown connection prefix");
1026 } 881 }
1027 } 882 }
1028 883
1029 /* Check server_address is given */ 884 /* Check server_address is given */
1030 if (server_address == NULL) 885 if (config.snmp_params.snmp_session.peername == NULL) {
1031 die(STATE_UNKNOWN, _("No host specified\n")); 886 die(STATE_UNKNOWN, _("No host specified\n"));
887 }
1032 888
1033 /* Check oid is given */ 889 if (port != NULL) {
1034 if (numoids == 0) 890 xasprintf(&config.snmp_params.snmp_session.peername, "%s:%s",
1035 die(STATE_UNKNOWN, _("No OIDs specified\n")); 891 config.snmp_params.snmp_session.peername, port);
892 }
1036 893
1037 if (proto == NULL) 894 /* check whether to load locally installed MIBS (CPU/disk intensive) */
1038 xasprintf(&proto, DEFAULT_PROTOCOL); 895 if (miblist == NULL) {
1039 896 if (config.snmp_params.need_mibs) {
1040 if ((strcmp(proto, "1") == 0) || (strcmp(proto, "2c") == 0)) { /* snmpv1 or snmpv2c */ 897 setenv("MIBLS", DEFAULT_MIBLIST, 1);
1041 numauthpriv = 2; 898 } else {
1042 authpriv = calloc(numauthpriv, sizeof(char *)); 899 setenv("MIBLS", "NONE", 1);
1043 authpriv[0] = strdup("-c"); 900 miblist = ""; /* don't read any mib files for numeric oids */
1044 authpriv[1] = strdup(community);
1045 } else if (strcmp(proto, "3") == 0) { /* snmpv3 args */
1046 if (!(context == NULL)) {
1047 numcontext = 2;
1048 contextargs = calloc(numcontext, sizeof(char *));
1049 contextargs[0] = strdup("-n");
1050 contextargs[1] = strdup(context);
1051 } 901 }
902 } else {
903 // Blatantly stolen from snmplib/snmp_parse_args
904 setenv("MIBS", miblist, 1);
905 }
1052 906
1053 if (seclevel == NULL) 907 // Historical default is SNMP v2c
1054 xasprintf(&seclevel, "noAuthNoPriv"); 908 if (!snmp_version_set_explicitely && config.snmp_params.snmp_session.community != NULL) {
909 config.snmp_params.snmp_session.version = SNMP_VERSION_2c;
910 }
1055 911
1056 if (secname == NULL) 912 if ((config.snmp_params.snmp_session.version == SNMP_VERSION_1) ||
913 (config.snmp_params.snmp_session.version == SNMP_VERSION_2c)) { /* snmpv1 or snmpv2c */
914 /*
915 config.numauthpriv = 2;
916 config.authpriv = calloc(config.numauthpriv, sizeof(char *));
917 config.authpriv[0] = strdup("-c");
918 config.authpriv[1] = strdup(community);
919 */
920 } else if (config.snmp_params.snmp_session.version == SNMP_VERSION_3) { /* snmpv3 args */
921 // generate keys for priv and auth here (if demanded)
922
923 if (config.snmp_params.snmp_session.securityName == NULL) {
1057 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname"); 924 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname");
925 }
1058 926
1059 if (strcmp(seclevel, "noAuthNoPriv") == 0) { 927 switch (config.snmp_params.snmp_session.securityLevel) {
1060 numauthpriv = 4; 928 case SNMP_SEC_LEVEL_AUTHPRIV: {
1061 authpriv = calloc(numauthpriv, sizeof(char *)); 929 if (authpasswd == NULL) {
1062 authpriv[0] = strdup("-l"); 930 die(STATE_UNKNOWN,
1063 authpriv[1] = strdup("noAuthNoPriv"); 931 "No authentication passphrase was given, but authorization was requested");
1064 authpriv[2] = strdup("-u");
1065 authpriv[3] = strdup(secname);
1066 } else {
1067 if (!((strcmp(seclevel, "authNoPriv") == 0) || (strcmp(seclevel, "authPriv") == 0))) {
1068 usage2(_("Invalid seclevel"), seclevel);
1069 } 932 }
1070 933 // auth and priv
1071 if (authproto == NULL) 934 int priv_key_generated = generate_Ku(
1072 xasprintf(&authproto, DEFAULT_AUTH_PROTOCOL); 935 config.snmp_params.snmp_session.securityPrivProto,
1073 936 (unsigned int)config.snmp_params.snmp_session.securityPrivProtoLen, authpasswd,
1074 if (authpasswd == NULL) 937 strlen((const char *)authpasswd), config.snmp_params.snmp_session.securityPrivKey,
1075 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd"); 938 &config.snmp_params.snmp_session.securityPrivKeyLen);
1076 939
1077 if (strcmp(seclevel, "authNoPriv") == 0) { 940 if (priv_key_generated != SNMPERR_SUCCESS) {
1078 numauthpriv = 8; 941 die(STATE_UNKNOWN, "Failed to generate privacy key");
1079 authpriv = calloc(numauthpriv, sizeof(char *));
1080 authpriv[0] = strdup("-l");
1081 authpriv[1] = strdup("authNoPriv");
1082 authpriv[2] = strdup("-a");
1083 authpriv[3] = strdup(authproto);
1084 authpriv[4] = strdup("-u");
1085 authpriv[5] = strdup(secname);
1086 authpriv[6] = strdup("-A");
1087 authpriv[7] = strdup(authpasswd);
1088 } else if (strcmp(seclevel, "authPriv") == 0) {
1089 if (privproto == NULL)
1090 xasprintf(&privproto, DEFAULT_PRIV_PROTOCOL);
1091
1092 if (privpasswd == NULL)
1093 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd");
1094
1095 numauthpriv = 12;
1096 authpriv = calloc(numauthpriv, sizeof(char *));
1097 authpriv[0] = strdup("-l");
1098 authpriv[1] = strdup("authPriv");
1099 authpriv[2] = strdup("-a");
1100 authpriv[3] = strdup(authproto);
1101 authpriv[4] = strdup("-u");
1102 authpriv[5] = strdup(secname);
1103 authpriv[6] = strdup("-A");
1104 authpriv[7] = strdup(authpasswd);
1105 authpriv[8] = strdup("-x");
1106 authpriv[9] = strdup(privproto);
1107 authpriv[10] = strdup("-X");
1108 authpriv[11] = strdup(privpasswd);
1109 } 942 }
1110 } 943 }
1111 944 // fall through
1112 } else { 945 case SNMP_SEC_LEVEL_AUTHNOPRIV: {
1113 usage2(_("Invalid SNMP version"), proto); 946 if (privpasswd == NULL) {
947 die(STATE_UNKNOWN, "No privacy passphrase was given, but privacy was requested");
948 }
949 int auth_key_generated = generate_Ku(
950 config.snmp_params.snmp_session.securityAuthProto,
951 (unsigned int)config.snmp_params.snmp_session.securityAuthProtoLen, privpasswd,
952 strlen((const char *)privpasswd), config.snmp_params.snmp_session.securityAuthKey,
953 &config.snmp_params.snmp_session.securityAuthKeyLen);
954
955 if (auth_key_generated != SNMPERR_SUCCESS) {
956 die(STATE_UNKNOWN, "Failed to generate privacy key");
957 }
958 } break;
959 case SNMP_SEC_LEVEL_NOAUTH:
960 // No auth, no priv, not much todo
961 break;
962 }
1114 } 963 }
1115 964
1116 return OK; 965 process_arguments_wrapper result = {
966 .config = config,
967 .errorcode = OK,
968 };
969 return result;
1117} 970}
1118 971
1119/* trim leading whitespace 972/* trim leading whitespace
1120 if there is a leading quote, make sure it balances */ 973 if there is a leading quote, make sure it balances */
1121 974char *trim_whitespaces_and_check_quoting(char *str) {
1122static char *thisarg(char *str) {
1123 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */ 975 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
1124 if (str[0] == '\'') { /* handle SIMPLE quoted strings */ 976 if (str[0] == '\'') { /* handle SIMPLE quoted strings */
1125 if (strlen(str) == 1 || !strstr(str + 1, "'")) 977 if (strlen(str) == 1 || !strstr(str + 1, "'")) {
1126 die(STATE_UNKNOWN, _("Unbalanced quotes\n")); 978 die(STATE_UNKNOWN, _("Unbalanced quotes\n"));
979 }
1127 } 980 }
1128 return str; 981 return str;
1129} 982}
@@ -1132,23 +985,21 @@ static char *thisarg(char *str) {
1132 set the trailing quote to '\x0' 985 set the trailing quote to '\x0'
1133 if the string continues, advance beyond the comma */ 986 if the string continues, advance beyond the comma */
1134 987
1135static char *nextarg(char *str) { 988char *get_next_argument(char *str) {
1136 if (str[0] == '\'') { 989 if (str[0] == '\'') {
1137 str[0] = 0; 990 str[0] = 0;
1138 if (strlen(str) > 1) { 991 if (strlen(str) > 1) {
1139 str = strstr(str + 1, "'"); 992 str = strstr(str + 1, "'");
1140 return (++str); 993 return (++str);
1141 } else {
1142 return NULL;
1143 } 994 }
995 return NULL;
1144 } 996 }
1145 if (str[0] == ',') { 997 if (str[0] == ',') {
1146 str[0] = 0; 998 str[0] = 0;
1147 if (strlen(str) > 1) { 999 if (strlen(str) > 1) {
1148 return (++str); 1000 return (++str);
1149 } else {
1150 return NULL;
1151 } 1001 }
1002 return NULL;
1152 } 1003 }
1153 if ((str = strstr(str, ",")) && strlen(str) > 1) { 1004 if ((str = strstr(str, ",")) && strlen(str) > 1) {
1154 str[0] = 0; 1005 str[0] = 0;
@@ -1157,41 +1008,7 @@ static char *nextarg(char *str) {
1157 return NULL; 1008 return NULL;
1158} 1009}
1159 1010
1160/* multiply result (values 0 < n < 1 work as divider) */ 1011void print_help(void) {
1161static char *multiply(char *str) {
1162 if (multiplier == 1)
1163 return (str);
1164
1165 if (verbose > 2)
1166 printf(" multiply input: %s\n", str);
1167
1168 char *endptr;
1169 double val = strtod(str, &endptr);
1170 if ((val == 0.0) && (endptr == str)) {
1171 die(STATE_UNKNOWN, _("multiplier set (%.1f), but input is not a number: %s"), multiplier, str);
1172 }
1173
1174 if (verbose > 2)
1175 printf(" multiply extracted double: %f\n", val);
1176
1177 val *= multiplier;
1178 char *conv = "%f";
1179 if (fmtstr_set) {
1180 conv = fmtstr;
1181 }
1182 if (val == (int)val) {
1183 snprintf(buffer, DEFAULT_BUFFER_SIZE, "%.0f", val);
1184 } else {
1185 if (verbose > 2)
1186 printf(" multiply using format: %s\n", conv);
1187 snprintf(buffer, DEFAULT_BUFFER_SIZE, conv, val);
1188 }
1189 if (verbose > 2)
1190 printf(" multiply result: %s\n", buffer);
1191 return buffer;
1192}
1193
1194static void print_help(void) {
1195 print_revision(progname, NP_VERSION); 1012 print_revision(progname, NP_VERSION);
1196 1013
1197 printf(COPYRIGHT, copyright, email); 1014 printf(COPYRIGHT, copyright, email);
@@ -1204,8 +1021,6 @@ static void print_help(void) {
1204 1021
1205 printf(UT_HELP_VRSN); 1022 printf(UT_HELP_VRSN);
1206 printf(UT_EXTRA_OPTS); 1023 printf(UT_EXTRA_OPTS);
1207 printf(UT_IPv46);
1208
1209 printf(UT_HOST_PORT, 'p', DEFAULT_PORT); 1024 printf(UT_HOST_PORT, 'p', DEFAULT_PORT);
1210 1025
1211 /* SNMP and Authentication Protocol */ 1026 /* SNMP and Authentication Protocol */
@@ -1217,13 +1032,15 @@ static void print_help(void) {
1217 printf(" %s\n", _("SNMPv3 context")); 1032 printf(" %s\n", _("SNMPv3 context"));
1218 printf(" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]"); 1033 printf(" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
1219 printf(" %s\n", _("SNMPv3 securityLevel")); 1034 printf(" %s\n", _("SNMPv3 securityLevel"));
1220 printf(" %s\n", "-a, --authproto=AUTHENTICATION_PROTOCOL"); 1035 printf(" %s\n", "-a, --authproto=[MD5|SHA]");
1221 printf(" %s\n", 1036 printf(" %s\n", _("SNMPv3 auth proto"));
1222 _("SNMPv3 authentication protocol (default MD5), available options depend on the specific version of the net-snmp tools")); 1037#ifdef HAVE_USM_DES_PRIV_PROTOCOL
1223 printf(" %s\n", _("if < 5.8 SHA (1) and MD5 should be available, if >= 5.8 additionally SHA-224, SHA-256, SHA-384 and SHA-512")); 1038 printf(" %s\n", "-x, --privproto=[DES|AES]");
1224 printf(" %s\n", "-x, --privproto=PRIVACY_PROTOCOL"); 1039 printf(" %s\n", _("SNMPv3 priv proto (default DES)"));
1225 printf(" %s\n", _("SNMPv3 privacy protocol (default DES), available options depend on the specific version of the net-snmp tools")); 1040#else
1226 printf(" %s\n", _("if < 5.8 DES and AES should be available, if >= 5.8 additionally AES-192 and AES-256")); 1041 printf(" %s\n", "-x, --privproto=[AES]");
1042 printf(" %s\n", _("SNMPv3 priv proto (default AES)"));
1043#endif
1227 1044
1228 /* Authentication Tokens*/ 1045 /* Authentication Tokens*/
1229 printf(" %s\n", "-C, --community=STRING"); 1046 printf(" %s\n", "-C, --community=STRING");
@@ -1235,15 +1052,18 @@ static void print_help(void) {
1235 printf(" %s\n", _("SNMPv3 authentication password")); 1052 printf(" %s\n", _("SNMPv3 authentication password"));
1236 printf(" %s\n", "-X, --privpasswd=PASSWORD"); 1053 printf(" %s\n", "-X, --privpasswd=PASSWORD");
1237 printf(" %s\n", _("SNMPv3 privacy password")); 1054 printf(" %s\n", _("SNMPv3 privacy password"));
1055 printf(" %s\n", "--connection-prefix");
1056 printf(" Connection prefix, may be one of udp, udp6, tcp, unix, ipx, udp6, udpv6, udpipv6, "
1057 "tcp6, tcpv6, tcpipv6, tls, dtls - "
1058 "default is \"udp\"\n");
1238 1059
1239 /* OID Stuff */ 1060 /* OID Stuff */
1240 printf(" %s\n", "-o, --oid=OID(s)"); 1061 printf(" %s\n", "-o, --oid=OID(s)");
1241 printf(" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query")); 1062 printf(" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
1242 printf(" %s\n", "-m, --miblist=STRING"); 1063 printf(" %s\n", "-m, --miblist=STRING");
1243 printf(" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'")); 1064 printf(" %s\n",
1065 _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
1244 printf(" %s\n", _("for symbolic OIDs.)")); 1066 printf(" %s\n", _("for symbolic OIDs.)"));
1245 printf(" %s\n", "-d, --delimiter=STRING");
1246 printf(" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER);
1247 printf(" %s\n", _("Any data on the right hand side of the delimiter is considered")); 1067 printf(" %s\n", _("Any data on the right hand side of the delimiter is considered"));
1248 printf(" %s\n", _("to be the data that should be used in the evaluation.")); 1068 printf(" %s\n", _("to be the data that should be used in the evaluation."));
1249 printf(" %s\n", "-z, --nulloid=#"); 1069 printf(" %s\n", "-z, --nulloid=#");
@@ -1260,10 +1080,6 @@ static void print_help(void) {
1260 printf(" %s\n", _("Warning threshold range(s)")); 1080 printf(" %s\n", _("Warning threshold range(s)"));
1261 printf(" %s\n", "-c, --critical=THRESHOLD(s)"); 1081 printf(" %s\n", "-c, --critical=THRESHOLD(s)");
1262 printf(" %s\n", _("Critical threshold range(s)")); 1082 printf(" %s\n", _("Critical threshold range(s)"));
1263 printf(" %s\n", "--rate");
1264 printf(" %s\n", _("Enable rate calculation. See 'Rate Calculation' below"));
1265 printf(" %s\n", "--rate-multiplier");
1266 printf(" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute"));
1267 printf(" %s\n", "--offset=OFFSET"); 1083 printf(" %s\n", "--offset=OFFSET");
1268 printf(" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data")); 1084 printf(" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data"));
1269 1085
@@ -1271,9 +1087,11 @@ static void print_help(void) {
1271 printf(" %s\n", "-s, --string=STRING"); 1087 printf(" %s\n", "-s, --string=STRING");
1272 printf(" %s\n", _("Return OK state (for that OID) if STRING is an exact match")); 1088 printf(" %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
1273 printf(" %s\n", "-r, --ereg=REGEX"); 1089 printf(" %s\n", "-r, --ereg=REGEX");
1274 printf(" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches")); 1090 printf(" %s\n",
1091 _("Return OK state (for that OID) if extended regular expression REGEX matches"));
1275 printf(" %s\n", "-R, --eregi=REGEX"); 1092 printf(" %s\n", "-R, --eregi=REGEX");
1276 printf(" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches")); 1093 printf(" %s\n",
1094 _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
1277 printf(" %s\n", "--invert-search"); 1095 printf(" %s\n", "--invert-search");
1278 printf(" %s\n", _("Invert search result (CRITICAL if found)")); 1096 printf(" %s\n", _("Invert search result (CRITICAL if found)"));
1279 1097
@@ -1282,53 +1100,46 @@ static void print_help(void) {
1282 printf(" %s\n", _("Prefix label for output from plugin")); 1100 printf(" %s\n", _("Prefix label for output from plugin"));
1283 printf(" %s\n", "-u, --units=STRING"); 1101 printf(" %s\n", "-u, --units=STRING");
1284 printf(" %s\n", _("Units label(s) for output data (e.g., 'sec.').")); 1102 printf(" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
1285 printf(" %s\n", "-D, --output-delimiter=STRING");
1286 printf(" %s\n", _("Separates output on multiple OID requests"));
1287 printf(" %s\n", "-M, --multiplier=FLOAT"); 1103 printf(" %s\n", "-M, --multiplier=FLOAT");
1288 printf(" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1")); 1104 printf(" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1"));
1289 printf(" %s\n", "-f, --fmtstr=STRING"); 1105 printf(UT_OUTPUT_FORMAT);
1290 printf(" %s\n", _("C-style format string for float values (see option -M)"));
1291 1106
1292 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 1107 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1293 printf(" %s\n", _("NOTE the final timeout value is calculated using this formula: timeout_interval * retries + 5")); 1108 printf(" %s\n", _("NOTE the final timeout value is calculated using this formula: "
1109 "timeout_interval * retries + 5"));
1294 printf(" %s\n", "-e, --retries=INTEGER"); 1110 printf(" %s\n", "-e, --retries=INTEGER");
1295 printf(" %s%i\n", _("Number of retries to be used in the requests, default: "), DEFAULT_RETRIES); 1111 printf(" %s%i\n", _("Number of retries to be used in the requests, default: "),
1112 DEFAULT_RETRIES);
1296 1113
1297 printf(" %s\n", "-O, --perf-oids"); 1114 printf(" %s\n", "-O, --perf-oids");
1298 printf(" %s\n", _("Label performance data with OIDs instead of --label's")); 1115 printf(" %s\n", _("Label performance data with OIDs instead of --label's"));
1299 1116
1300 printf(" %s\n", "--ignore-mib-parsing-errors"); 1117 printf(" %s\n", "--ignore-mib-parsing-errors");
1301 printf(" %s\n", _("Tell snmpget to not print errors encountered when parsing MIB files")); 1118 printf(" %s\n", _("Do to not print errors encountered when parsing MIB files"));
1302 1119
1303 printf(UT_VERBOSE); 1120 printf(UT_VERBOSE);
1304 1121
1305 printf("\n"); 1122 printf("\n");
1306 printf("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package.")); 1123 printf("%s\n", _("This plugin relies (links against) on the NET-SNMP libraries."));
1307 printf("%s\n", _("if you don't have the package installed, you will need to download it from")); 1124 printf("%s\n",
1125 _("if you don't have the libraries installed, you will need to download them from"));
1308 printf("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin.")); 1126 printf("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
1309 1127
1310 printf("\n"); 1128 printf("\n");
1311 printf("%s\n", _("Notes:")); 1129 printf("%s\n", _("Notes:"));
1312 printf(" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited ")); 1130 printf(" %s\n",
1131 _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited "));
1313 printf(" %s\n", _("list (lists with internal spaces must be quoted).")); 1132 printf(" %s\n", _("list (lists with internal spaces must be quoted)."));
1314 1133
1315 printf(" -%s", UT_THRESHOLDS_NOTES); 1134 printf(" -%s", UT_THRESHOLDS_NOTES);
1316 1135
1317 printf(" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'")); 1136 printf(" %s\n",
1137 _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
1318 printf(" %s\n", _("- Note that only one string and one regex may be checked at present")); 1138 printf(" %s\n", _("- Note that only one string and one regex may be checked at present"));
1319 printf(" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value")); 1139 printf(" %s\n",
1140 _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
1320 printf(" %s\n", _("returned from the SNMP query is an unsigned integer.")); 1141 printf(" %s\n", _("returned from the SNMP query is an unsigned integer."));
1321 1142
1322 printf("\n");
1323 printf("%s\n", _("Rate Calculation:"));
1324 printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when"));
1325 printf(" %s\n", _("calculating the counter difference since the last check. check_snmp"));
1326 printf(" %s\n", _("saves the last state information in a file so that the rate per second"));
1327 printf(" %s\n", _("can be calculated. Use the --rate option to save state information."));
1328 printf(" %s\n", _("On the first run, there will be no prior state - this will return with OK."));
1329 printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so"));
1330 printf(" %s\n", _("changing the arguments will create a new state file."));
1331
1332 printf(UT_SUPPORT); 1143 printf(UT_SUPPORT);
1333} 1144}
1334 1145
@@ -1339,5 +1150,5 @@ void print_usage(void) {
1339 printf("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n"); 1150 printf("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1340 printf("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n"); 1151 printf("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n");
1341 printf("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n"); 1152 printf("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n");
1342 printf("[-M multiplier [-f format]]\n"); 1153 printf("[-M multiplier]\n");
1343} 1154}
diff --git a/plugins/check_snmp.d/check_snmp_helpers.c b/plugins/check_snmp.d/check_snmp_helpers.c
new file mode 100644
index 00000000..f506537a
--- /dev/null
+++ b/plugins/check_snmp.d/check_snmp_helpers.c
@@ -0,0 +1,936 @@
1#include "./check_snmp_helpers.h"
2#include <string.h>
3#include "../../lib/utils_base.h"
4#include "config.h"
5#include <assert.h>
6#include "../utils.h"
7#include "output.h"
8#include "states.h"
9#include <sys/stat.h>
10#include <ctype.h>
11
12extern int verbose;
13
14check_snmp_test_unit check_snmp_test_unit_init() {
15 check_snmp_test_unit tmp = {
16 .threshold = mp_thresholds_init(),
17 };
18 return tmp;
19}
20
21int check_snmp_set_thresholds(const char *threshold_string, check_snmp_test_unit test_units[],
22 size_t max_test_units, bool is_critical) {
23
24 if (threshold_string == NULL || strlen(threshold_string) == 0) {
25 // No input, do nothing
26 return 0;
27 }
28
29 if (strchr(threshold_string, ',') != NULL) {
30 // Got a comma in the string, should be multiple values
31 size_t tu_index = 0;
32
33 while (threshold_string[0] == ',') {
34 // got commas at the beginning, so skip some values
35 tu_index++;
36 threshold_string++;
37 }
38
39 for (char *ptr = strtok(threshold_string, ", "); ptr != NULL;
40 ptr = strtok(NULL, ", "), tu_index++) {
41
42 if (tu_index > max_test_units) {
43 // More thresholds then values, just ignore them
44 return 0;
45 }
46
47 // edge case: maybe we got `,,` to skip a value
48 if (strlen(ptr) == 0) {
49 // no threshold given, do not set it then
50 continue;
51 }
52
53 mp_range_parsed tmp = mp_parse_range_string(ptr);
54 if (tmp.error != MP_PARSING_SUCCES) {
55 die(STATE_UNKNOWN, "Unable to parse critical threshold range: %s", ptr);
56 }
57
58 if (is_critical) {
59 test_units[tu_index].threshold.critical = tmp.range;
60 test_units[tu_index].threshold.critical_is_set = true;
61 } else {
62 test_units[tu_index].threshold.warning = tmp.range;
63 test_units[tu_index].threshold.warning_is_set = true;
64 }
65 }
66
67 } else {
68 // Single value
69 // only valid for the first test unit
70 mp_range_parsed tmp = mp_parse_range_string(threshold_string);
71 if (tmp.error != MP_PARSING_SUCCES) {
72 die(STATE_UNKNOWN, "Unable to parse critical threshold range: %s", threshold_string);
73 }
74
75 if (is_critical) {
76 test_units[0].threshold.critical = tmp.range;
77 test_units[0].threshold.critical_is_set = true;
78 } else {
79 test_units[0].threshold.warning = tmp.range;
80 test_units[0].threshold.warning_is_set = true;
81 }
82 }
83
84 return 0;
85}
86
87const int DEFAULT_PROTOCOL = SNMP_VERSION_1;
88const char DEFAULT_OUTPUT_DELIMITER[] = " ";
89
90const int RANDOM_STATE_DATA_LENGTH_PREDICTION = 8192;
91
92check_snmp_config check_snmp_config_init() {
93 check_snmp_config tmp = {
94 .snmp_params =
95 {
96 .use_getnext = false,
97
98 .ignore_mib_parsing_errors = false,
99 .need_mibs = false,
100
101 .test_units = NULL,
102 .num_of_test_units = 0,
103 },
104
105 .evaluation_params =
106 {
107 .nulloid_result = STATE_UNKNOWN, // state to return if no result for query
108
109 .invert_search = true,
110 .regex_cmp_value = {},
111 .string_cmp_value = "",
112
113 .multiplier = 1.0,
114 .multiplier_set = false,
115 .offset = 0,
116 .offset_set = false,
117
118 .use_oid_as_perf_data_label = false,
119
120 .calculate_rate = false,
121 .rate_multiplier = 1,
122 },
123 };
124
125 snmp_sess_init(&tmp.snmp_params.snmp_session);
126
127 tmp.snmp_params.snmp_session.retries = DEFAULT_RETRIES;
128 tmp.snmp_params.snmp_session.version = DEFAULT_SNMP_VERSION;
129 tmp.snmp_params.snmp_session.securityLevel = SNMP_SEC_LEVEL_NOAUTH;
130 tmp.snmp_params.snmp_session.community = (unsigned char *)"public";
131 tmp.snmp_params.snmp_session.community_len = strlen("public");
132 return tmp;
133}
134
135snmp_responces do_snmp_query(check_snmp_config_snmp_parameters parameters) {
136 if (parameters.ignore_mib_parsing_errors) {
137 char *opt_toggle_res = snmp_mib_toggle_options("e");
138 if (opt_toggle_res != NULL) {
139 die(STATE_UNKNOWN, "Unable to disable MIB parsing errors");
140 }
141 }
142
143 struct snmp_pdu *pdu = NULL;
144 if (parameters.use_getnext) {
145 pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
146 } else {
147 pdu = snmp_pdu_create(SNMP_MSG_GET);
148 }
149
150 for (size_t i = 0; i < parameters.num_of_test_units; i++) {
151 assert(parameters.test_units[i].oid != NULL);
152 if (verbose > 0) {
153 printf("OID %zu to parse: %s\n", i, parameters.test_units[i].oid);
154 }
155
156 oid tmp_OID[MAX_OID_LEN];
157 size_t tmp_OID_len = MAX_OID_LEN;
158 if (snmp_parse_oid(parameters.test_units[i].oid, tmp_OID, &tmp_OID_len) != NULL) {
159 // success
160 snmp_add_null_var(pdu, tmp_OID, tmp_OID_len);
161 } else {
162 // failed
163 snmp_perror("Parsing failure");
164 die(STATE_UNKNOWN, "Failed to parse OID\n");
165 }
166 }
167
168 const int timeout_safety_tolerance = 5;
169 alarm((timeout_interval * (unsigned int)parameters.snmp_session.retries) +
170 timeout_safety_tolerance);
171
172 struct snmp_session *active_session = snmp_open(&parameters.snmp_session);
173 if (active_session == NULL) {
174 int pcliberr = 0;
175 int psnmperr = 0;
176 char *pperrstring = NULL;
177 snmp_error(&parameters.snmp_session, &pcliberr, &psnmperr, &pperrstring);
178 die(STATE_UNKNOWN, "Failed to open SNMP session: %s\n", pperrstring);
179 }
180
181 struct snmp_pdu *response = NULL;
182 int snmp_query_status = snmp_synch_response(active_session, pdu, &response);
183
184 if (!(snmp_query_status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR)) {
185 int pcliberr = 0;
186 int psnmperr = 0;
187 char *pperrstring = NULL;
188 snmp_error(active_session, &pcliberr, &psnmperr, &pperrstring);
189
190 if (psnmperr == SNMPERR_TIMEOUT) {
191 // We exit with critical here for some historical reason
192 die(STATE_CRITICAL, "SNMP query ran into a timeout\n");
193 }
194 die(STATE_UNKNOWN, "SNMP query failed: %s\n", pperrstring);
195 }
196
197 snmp_close(active_session);
198
199 /* disable alarm again */
200 alarm(0);
201
202 snmp_responces result = {
203 .errorcode = OK,
204 .response_values = calloc(parameters.num_of_test_units, sizeof(response_value)),
205 };
206
207 if (result.response_values == NULL) {
208 result.errorcode = ERROR;
209 return result;
210 }
211
212 // We got the the query results, now process them
213 size_t loop_index = 0;
214 for (netsnmp_variable_list *vars = response->variables; vars;
215 vars = vars->next_variable, loop_index++) {
216
217 for (size_t jdx = 0; jdx < vars->name_length; jdx++) {
218 result.response_values[loop_index].oid[jdx] = vars->name[jdx];
219 }
220 result.response_values[loop_index].oid_length = vars->name_length;
221
222 switch (vars->type) {
223 case ASN_OCTET_STR: {
224 result.response_values[loop_index].string_response = strdup((char *)vars->val.string);
225 result.response_values[loop_index].type = vars->type;
226 if (verbose) {
227 printf("Debug: Got a string as response: %s\n", vars->val.string);
228 }
229 }
230 continue;
231 case ASN_OPAQUE:
232 if (verbose) {
233 printf("Debug: Got OPAQUE\n");
234 }
235 break;
236 /* Numerical values */
237 case ASN_COUNTER64: {
238 if (verbose) {
239 printf("Debug: Got counter64\n");
240 }
241 struct counter64 tmp = *(vars->val.counter64);
242 uint64_t counter = (tmp.high << 32) + tmp.low;
243 result.response_values[loop_index].value.uIntVal = counter;
244 result.response_values[loop_index].type = vars->type;
245 } break;
246 case ASN_GAUGE: // same as ASN_UNSIGNED
247 case ASN_TIMETICKS:
248 case ASN_COUNTER:
249 case ASN_UINTEGER: {
250 if (verbose) {
251 printf("Debug: Got a Integer like\n");
252 }
253 result.response_values[loop_index].value.uIntVal = (unsigned long)*(vars->val.integer);
254 result.response_values[loop_index].type = vars->type;
255 } break;
256 case ASN_INTEGER: {
257 if (verbose) {
258 printf("Debug: Got a Integer\n");
259 }
260 result.response_values[loop_index].value.intVal = *(vars->val.integer);
261 result.response_values[loop_index].type = vars->type;
262 } break;
263 case ASN_FLOAT: {
264 if (verbose) {
265 printf("Debug: Got a float\n");
266 }
267 result.response_values[loop_index].value.doubleVal = *(vars->val.floatVal);
268 result.response_values[loop_index].type = vars->type;
269 } break;
270 case ASN_DOUBLE: {
271 if (verbose) {
272 printf("Debug: Got a double\n");
273 }
274 result.response_values[loop_index].value.doubleVal = *(vars->val.doubleVal);
275 result.response_values[loop_index].type = vars->type;
276 } break;
277 case ASN_IPADDRESS:
278 if (verbose) {
279 printf("Debug: Got an IP address\n");
280 }
281 result.response_values[loop_index].type = vars->type;
282
283 // TODO: print address here, state always ok? or regex match?
284 break;
285 default:
286 if (verbose) {
287 printf("Debug: Got a unmatched result type: %hhu\n", vars->type);
288 }
289 // TODO: Error here?
290 break;
291 }
292 }
293
294 return result;
295}
296
297check_snmp_evaluation evaluate_single_unit(response_value response,
298 check_snmp_evaluation_parameters eval_params,
299 check_snmp_test_unit test_unit, time_t query_timestamp,
300 check_snmp_state_entry prev_state,
301 bool have_previous_state) {
302 mp_subcheck sc_oid_test = mp_subcheck_init();
303
304 if ((test_unit.label != NULL) && (strcmp(test_unit.label, "") != 0)) {
305 xasprintf(&sc_oid_test.output, "%s - ", test_unit.label);
306 } else {
307 sc_oid_test.output = strdup("");
308 }
309
310 char oid_string[(MAX_OID_LEN * 2) + 1] = {};
311
312 int oid_string_result =
313 snprint_objid(oid_string, (MAX_OID_LEN * 2) + 1, response.oid, response.oid_length);
314 if (oid_string_result <= 0) {
315 // TODO error here
316 die(STATE_UNKNOWN, "snprint_objid failed\n");
317 }
318
319 xasprintf(&sc_oid_test.output, "%sOID: %s", sc_oid_test.output, oid_string);
320 sc_oid_test = mp_set_subcheck_default_state(sc_oid_test, STATE_OK);
321
322 if (verbose > 2) {
323 printf("Processing oid %s\n", oid_string);
324 }
325
326 bool got_a_numerical_value = false;
327 mp_perfdata_value pd_result_val = {0};
328
329 check_snmp_state_entry result_state = {
330 .timestamp = query_timestamp,
331 .oid_length = response.oid_length,
332 .type = response.type,
333 };
334
335 for (size_t i = 0; i < response.oid_length; i++) {
336 result_state.oid[i] = response.oid[i];
337 }
338
339 if (have_previous_state) {
340 if (query_timestamp == prev_state.timestamp) {
341 // somehow we have the same timestamp again, that can't be good
342 sc_oid_test = mp_set_subcheck_state(sc_oid_test, STATE_UNKNOWN);
343 xasprintf(&sc_oid_test.output, "Time duration between plugin calls is invalid");
344
345 check_snmp_evaluation result = {
346 .sc = sc_oid_test,
347 .state = result_state,
348 };
349
350 return result;
351 }
352 }
353 // compute rate time difference
354 double timeDiff = 0;
355 if (have_previous_state) {
356 if (verbose) {
357 printf("Previous timestamp: %s", ctime(&prev_state.timestamp));
358 printf("Current timestamp: %s", ctime(&query_timestamp));
359 }
360 timeDiff = difftime(query_timestamp, prev_state.timestamp) / eval_params.rate_multiplier;
361 }
362
363 mp_perfdata pd_num_val = {};
364
365 switch (response.type) {
366 case ASN_OCTET_STR: {
367 char *tmp = response.string_response;
368 if (strchr(tmp, '"') != NULL) {
369 // got double quote in the string
370 if (strchr(tmp, '\'') != NULL) {
371 // got single quote in the string too
372 // dont quote that at all to avoid even more confusion
373 xasprintf(&sc_oid_test.output, "%s - Value: %s", sc_oid_test.output, tmp);
374 } else {
375 // quote with single quotes
376 xasprintf(&sc_oid_test.output, "%s - Value: '%s'", sc_oid_test.output, tmp);
377 }
378 } else {
379 // quote with double quotes
380 xasprintf(&sc_oid_test.output, "%s - Value: \"%s\"", sc_oid_test.output, tmp);
381 }
382
383 if (strlen(tmp) == 0) {
384 sc_oid_test = mp_set_subcheck_state(sc_oid_test, eval_params.nulloid_result);
385 }
386
387 // String matching test
388 if ((test_unit.eval_mthd.crit_string)) {
389 if (strcmp(tmp, eval_params.string_cmp_value)) {
390 sc_oid_test = mp_set_subcheck_state(
391 sc_oid_test, (eval_params.invert_search) ? STATE_CRITICAL : STATE_OK);
392 } else {
393 sc_oid_test = mp_set_subcheck_state(
394 sc_oid_test, (eval_params.invert_search) ? STATE_OK : STATE_CRITICAL);
395 }
396 } else if (test_unit.eval_mthd.crit_regex) {
397 const size_t nmatch = eval_params.regex_cmp_value.re_nsub + 1;
398 regmatch_t pmatch[nmatch];
399 memset(pmatch, '\0', sizeof(regmatch_t) * nmatch);
400
401 int excode = regexec(&eval_params.regex_cmp_value, tmp, nmatch, pmatch, 0);
402 if (excode == 0) {
403 sc_oid_test = mp_set_subcheck_state(
404 sc_oid_test, (eval_params.invert_search) ? STATE_OK : STATE_CRITICAL);
405 } else if (excode != REG_NOMATCH) {
406 char errbuf[MAX_INPUT_BUFFER] = "";
407 regerror(excode, &eval_params.regex_cmp_value, errbuf, MAX_INPUT_BUFFER);
408 printf(_("Execute Error: %s\n"), errbuf);
409 exit(STATE_CRITICAL);
410 } else { // REG_NOMATCH
411 sc_oid_test = mp_set_subcheck_state(
412 sc_oid_test, eval_params.invert_search ? STATE_CRITICAL : STATE_OK);
413 }
414 }
415 } break;
416 case ASN_COUNTER64:
417 got_a_numerical_value = true;
418
419 result_state.value.uIntVal = response.value.uIntVal;
420 result_state.type = response.type;
421
422 // TODO: perfdata unit counter
423 if (eval_params.calculate_rate && have_previous_state) {
424 if (prev_state.value.uIntVal > response.value.uIntVal) {
425 // overflow
426 unsigned long long tmp =
427 (UINT64_MAX - prev_state.value.uIntVal) + response.value.uIntVal;
428
429 tmp /= timeDiff;
430 pd_result_val = mp_create_pd_value(tmp);
431 } else {
432 pd_result_val = mp_create_pd_value(
433 (response.value.uIntVal - prev_state.value.uIntVal) / timeDiff);
434 }
435 } else {
436 // It's only a counter if we cont compute rate
437 pd_num_val.uom = "c";
438 pd_result_val = mp_create_pd_value(response.value.uIntVal);
439 }
440 break;
441 case ASN_GAUGE: // same as ASN_UNSIGNED
442 case ASN_TIMETICKS:
443 case ASN_COUNTER:
444 case ASN_UINTEGER: {
445 got_a_numerical_value = true;
446 long long treated_value = (long long)response.value.uIntVal;
447
448 if (eval_params.multiplier_set || eval_params.offset_set) {
449 double processed = (double)response.value.uIntVal;
450
451 if (eval_params.offset_set) {
452 processed += eval_params.offset;
453 }
454
455 if (eval_params.multiplier_set) {
456 processed = processed * eval_params.multiplier;
457 }
458
459 treated_value = lround(processed);
460 }
461
462 result_state.value.intVal = treated_value;
463
464 if (eval_params.calculate_rate && have_previous_state) {
465 if (verbose > 2) {
466 printf("%s: Rate calculation (int/counter/gauge): prev: %lli\n", __FUNCTION__,
467 prev_state.value.intVal);
468 printf("%s: Rate calculation (int/counter/gauge): current: %lli\n", __FUNCTION__,
469 treated_value);
470 }
471 double rate = (treated_value - prev_state.value.intVal) / timeDiff;
472 pd_result_val = mp_create_pd_value(rate);
473 } else {
474 pd_result_val = mp_create_pd_value(treated_value);
475
476 if (response.type == ASN_COUNTER) {
477 pd_num_val.uom = "c";
478 }
479 }
480
481 } break;
482 case ASN_INTEGER: {
483 if (eval_params.multiplier_set || eval_params.offset_set) {
484 double processed = (double)response.value.intVal;
485
486 if (eval_params.offset_set) {
487 processed += eval_params.offset;
488 }
489
490 if (eval_params.multiplier_set) {
491 processed *= eval_params.multiplier;
492 }
493
494 result_state.value.doubleVal = processed;
495
496 if (eval_params.calculate_rate && have_previous_state) {
497 pd_result_val =
498 mp_create_pd_value((processed - prev_state.value.doubleVal) / timeDiff);
499 } else {
500 pd_result_val = mp_create_pd_value(processed);
501 }
502 } else {
503 result_state.value.intVal = response.value.intVal;
504
505 if (eval_params.calculate_rate && have_previous_state) {
506 pd_result_val = mp_create_pd_value(
507 (response.value.intVal - prev_state.value.intVal) / timeDiff);
508 } else {
509 pd_result_val = mp_create_pd_value(response.value.intVal);
510 }
511 }
512
513 got_a_numerical_value = true;
514 } break;
515 case ASN_FLOAT: // fallthrough
516 case ASN_DOUBLE: {
517 got_a_numerical_value = true;
518 double tmp = response.value.doubleVal;
519 if (eval_params.offset_set) {
520 tmp += eval_params.offset;
521 }
522
523 if (eval_params.multiplier_set) {
524 tmp *= eval_params.multiplier;
525 }
526
527 if (eval_params.calculate_rate && have_previous_state) {
528 pd_result_val = mp_create_pd_value((tmp - prev_state.value.doubleVal) / timeDiff);
529 } else {
530 pd_result_val = mp_create_pd_value(tmp);
531 }
532 got_a_numerical_value = true;
533
534 result_state.value.doubleVal = tmp;
535 } break;
536 case ASN_IPADDRESS:
537 // TODO
538 break;
539 }
540
541 if (got_a_numerical_value) {
542 if (eval_params.use_oid_as_perf_data_label) {
543 // Use oid for perdata label
544 pd_num_val.label = strdup(oid_string);
545 // TODO strdup error checking
546 } else if (test_unit.label != NULL && strcmp(test_unit.label, "") != 0) {
547 pd_num_val.label = strdup(test_unit.label);
548 } else {
549 pd_num_val.label = strdup(test_unit.oid);
550 }
551
552 if (!(eval_params.calculate_rate && !have_previous_state)) {
553 // some kind of numerical value
554 if (test_unit.unit_value != NULL && strcmp(test_unit.unit_value, "") != 0) {
555 pd_num_val.uom = test_unit.unit_value;
556 }
557
558 pd_num_val.value = pd_result_val;
559
560 xasprintf(&sc_oid_test.output, "%s Value: %s", sc_oid_test.output,
561 pd_value_to_string(pd_result_val));
562
563 if (test_unit.unit_value != NULL && strcmp(test_unit.unit_value, "") != 0) {
564 xasprintf(&sc_oid_test.output, "%s%s", sc_oid_test.output, test_unit.unit_value);
565 }
566
567 if (test_unit.threshold.warning_is_set || test_unit.threshold.critical_is_set) {
568 pd_num_val = mp_pd_set_thresholds(pd_num_val, test_unit.threshold);
569 mp_state_enum tmp_state = mp_get_pd_status(pd_num_val);
570
571 if (tmp_state == STATE_WARNING) {
572 sc_oid_test = mp_set_subcheck_state(sc_oid_test, STATE_WARNING);
573 xasprintf(&sc_oid_test.output, "%s - number violates warning threshold",
574 sc_oid_test.output);
575 } else if (tmp_state == STATE_CRITICAL) {
576 sc_oid_test = mp_set_subcheck_state(sc_oid_test, STATE_CRITICAL);
577 xasprintf(&sc_oid_test.output, "%s - number violates critical threshold",
578 sc_oid_test.output);
579 }
580 }
581
582 mp_add_perfdata_to_subcheck(&sc_oid_test, pd_num_val);
583 } else {
584 // should calculate rate, but there is no previous state, so first run
585 // exit with ok now
586 sc_oid_test = mp_set_subcheck_state(sc_oid_test, STATE_OK);
587 xasprintf(&sc_oid_test.output, "%s - No previous data to calculate rate - assume okay",
588 sc_oid_test.output);
589 }
590 }
591
592 check_snmp_evaluation result = {
593 .sc = sc_oid_test,
594 .state = result_state,
595 };
596
597 return result;
598}
599
600char *_np_state_generate_key(int argc, char **argv);
601
602/*
603 * If time=NULL, use current time. Create state file, with state format
604 * version, default text. Writes version, time, and data. Avoid locking
605 * problems - use mv to write and then swap. Possible loss of state data if
606 * two things writing to same key at same time.
607 * Will die with UNKNOWN if errors
608 */
609void np_state_write_string(state_key stateKey, time_t timestamp, char *stringToStore) {
610 time_t current_time;
611 if (timestamp == 0) {
612 time(&current_time);
613 } else {
614 current_time = timestamp;
615 }
616
617 int result = 0;
618
619 /* If file doesn't currently exist, create directories */
620 if (access(stateKey._filename, F_OK) != 0) {
621 char *directories = NULL;
622 result = asprintf(&directories, "%s", stateKey._filename);
623 if (result < 0) {
624 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
625 }
626
627 for (char *p = directories + 1; *p; p++) {
628 if (*p == '/') {
629 *p = '\0';
630 if ((access(directories, F_OK) != 0) && (mkdir(directories, S_IRWXU) != 0)) {
631 /* Can't free this! Otherwise error message is wrong! */
632 /* np_free(directories); */
633 die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories);
634 }
635 *p = '/';
636 }
637 }
638
639 if (directories) {
640 free(directories);
641 }
642 }
643
644 char *temp_file = NULL;
645 result = asprintf(&temp_file, "%s.XXXXXX", stateKey._filename);
646 if (result < 0) {
647 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
648 }
649
650 int temp_file_desc = 0;
651 if ((temp_file_desc = mkstemp(temp_file)) == -1) {
652 if (temp_file) {
653 free(temp_file);
654 }
655 die(STATE_UNKNOWN, _("Cannot create temporary filename"));
656 }
657
658 FILE *temp_file_pointer = fdopen(temp_file_desc, "w");
659 if (temp_file_pointer == NULL) {
660 close(temp_file_desc);
661 unlink(temp_file);
662 if (temp_file) {
663 free(temp_file);
664 }
665 die(STATE_UNKNOWN, _("Unable to open temporary state file"));
666 }
667
668 fprintf(temp_file_pointer, "# NP State file\n");
669 fprintf(temp_file_pointer, "%d\n", NP_STATE_FORMAT_VERSION);
670 fprintf(temp_file_pointer, "%d\n", stateKey.data_version);
671 fprintf(temp_file_pointer, "%lu\n", current_time);
672 fprintf(temp_file_pointer, "%s\n", stringToStore);
673
674 fchmod(temp_file_desc, S_IRUSR | S_IWUSR | S_IRGRP);
675
676 fflush(temp_file_pointer);
677
678 result = fclose(temp_file_pointer);
679
680 fsync(temp_file_desc);
681
682 if (result != 0) {
683 unlink(temp_file);
684 if (temp_file) {
685 free(temp_file);
686 }
687 die(STATE_UNKNOWN, _("Error writing temp file"));
688 }
689
690 if (rename(temp_file, stateKey._filename) != 0) {
691 unlink(temp_file);
692 if (temp_file) {
693 free(temp_file);
694 }
695 die(STATE_UNKNOWN, _("Cannot rename state temp file"));
696 }
697
698 if (temp_file) {
699 free(temp_file);
700 }
701}
702
703/*
704 * Read the state file
705 */
706bool _np_state_read_file(FILE *state_file, state_key stateKey) {
707 time_t current_time;
708 time(&current_time);
709
710 /* Note: This introduces a limit of 8192 bytes in the string data */
711 char *line = (char *)calloc(1, 8192);
712 if (line == NULL) {
713 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
714 }
715
716 bool status = false;
717 enum {
718 STATE_FILE_VERSION,
719 STATE_DATA_VERSION,
720 STATE_DATA_TIME,
721 STATE_DATA_TEXT,
722 STATE_DATA_END
723 } expected = STATE_FILE_VERSION;
724
725 int failure = 0;
726 while (!failure && (fgets(line, 8192, state_file)) != NULL) {
727 size_t pos = strlen(line);
728 if (line[pos - 1] == '\n') {
729 line[pos - 1] = '\0';
730 }
731
732 if (line[0] == '#') {
733 continue;
734 }
735
736 switch (expected) {
737 case STATE_FILE_VERSION: {
738 int i = atoi(line);
739 if (i != NP_STATE_FORMAT_VERSION) {
740 failure++;
741 } else {
742 expected = STATE_DATA_VERSION;
743 }
744 } break;
745 case STATE_DATA_VERSION: {
746 int i = atoi(line);
747 if (i != stateKey.data_version) {
748 failure++;
749 } else {
750 expected = STATE_DATA_TIME;
751 }
752 } break;
753 case STATE_DATA_TIME: {
754 /* If time > now, error */
755 time_t data_time = strtoul(line, NULL, 10);
756 if (data_time > current_time) {
757 failure++;
758 } else {
759 stateKey.state_data->time = data_time;
760 expected = STATE_DATA_TEXT;
761 }
762 } break;
763 case STATE_DATA_TEXT:
764 stateKey.state_data->data = strdup(line);
765 if (stateKey.state_data->data == NULL) {
766 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
767 }
768 stateKey.state_data->length = strlen(line);
769 expected = STATE_DATA_END;
770 status = true;
771 break;
772 case STATE_DATA_END:;
773 }
774 }
775
776 if (line) {
777 free(line);
778 }
779 return status;
780}
781/*
782 * Will return NULL if no data is available (first run). If key currently
783 * exists, read data. If state file format version is not expected, return
784 * as if no data. Get state data version number and compares to expected.
785 * If numerically lower, then return as no previous state. die with UNKNOWN
786 * if exceptional error.
787 */
788state_data *np_state_read(state_key stateKey) {
789 /* Open file. If this fails, no previous state found */
790 FILE *statefile = fopen(stateKey._filename, "r");
791 state_data *this_state_data = (state_data *)calloc(1, sizeof(state_data));
792 if (statefile != NULL) {
793
794 if (this_state_data == NULL) {
795 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
796 }
797
798 this_state_data->data = NULL;
799 stateKey.state_data = this_state_data;
800
801 if (_np_state_read_file(statefile, stateKey)) {
802 this_state_data->errorcode = OK;
803 } else {
804 this_state_data->errorcode = ERROR;
805 }
806
807 fclose(statefile);
808 } else {
809 // Failed to open state file
810 this_state_data->errorcode = ERROR;
811 }
812
813 return stateKey.state_data;
814}
815
816/*
817 * Internal function. Returns either:
818 * envvar NAGIOS_PLUGIN_STATE_DIRECTORY
819 * statically compiled shared state directory
820 */
821char *_np_state_calculate_location_prefix(void) {
822 char *env_dir;
823
824 /* Do not allow passing MP_STATE_PATH in setuid plugins
825 * for security reasons */
826 if (!mp_suid()) {
827 env_dir = getenv("MP_STATE_PATH");
828 if (env_dir && env_dir[0] != '\0') {
829 return env_dir;
830 }
831 /* This is the former ENV, for backward-compatibility */
832 env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY");
833 if (env_dir && env_dir[0] != '\0') {
834 return env_dir;
835 }
836 }
837
838 return NP_STATE_DIR_PREFIX;
839}
840
841/*
842 * Initiatializer for state routines.
843 * Sets variables. Generates filename. Returns np_state_key. die with
844 * UNKNOWN if exception
845 */
846state_key np_enable_state(char *keyname, int expected_data_version, char *plugin_name, int argc,
847 char **argv) {
848 state_key *this_state = (state_key *)calloc(1, sizeof(state_key));
849 if (this_state == NULL) {
850 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
851 }
852
853 char *temp_keyname = NULL;
854 if (keyname == NULL) {
855 temp_keyname = _np_state_generate_key(argc, argv);
856 } else {
857 temp_keyname = strdup(keyname);
858 if (temp_keyname == NULL) {
859 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
860 }
861 }
862
863 /* Die if invalid characters used for keyname */
864 char *tmp_char = temp_keyname;
865 while (*tmp_char != '\0') {
866 if (!(isalnum(*tmp_char) || *tmp_char == '_')) {
867 die(STATE_UNKNOWN, _("Invalid character for keyname - only alphanumerics or '_'"));
868 }
869 tmp_char++;
870 }
871 this_state->name = temp_keyname;
872 this_state->plugin_name = plugin_name;
873 this_state->data_version = expected_data_version;
874 this_state->state_data = NULL;
875
876 /* Calculate filename */
877 char *temp_filename = NULL;
878 int error = asprintf(&temp_filename, "%s/%lu/%s/%s", _np_state_calculate_location_prefix(),
879 (unsigned long)geteuid(), plugin_name, this_state->name);
880 if (error < 0) {
881 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
882 }
883
884 this_state->_filename = temp_filename;
885
886 return *this_state;
887}
888
889/*
890 * Returns a string to use as a keyname, based on an md5 hash of argv, thus
891 * hopefully a unique key per service/plugin invocation. Use the extra-opts
892 * parse of argv, so that uniqueness in parameters are reflected there.
893 */
894char *_np_state_generate_key(int argc, char **argv) {
895 unsigned char result[256];
896
897#ifdef USE_OPENSSL
898 /*
899 * This code path is chosen if openssl is available (which should be the most common
900 * scenario). Alternatively, the gnulib implementation/
901 *
902 */
903 EVP_MD_CTX *ctx = EVP_MD_CTX_new();
904
905 EVP_DigestInit(ctx, EVP_sha256());
906
907 for (int i = 0; i < argc; i++) {
908 EVP_DigestUpdate(ctx, argv[i], strlen(argv[i]));
909 }
910
911 EVP_DigestFinal(ctx, result, NULL);
912#else
913
914 struct sha256_ctx ctx;
915
916 for (int i = 0; i < this_monitoring_plugin->argc; i++) {
917 sha256_process_bytes(argv[i], strlen(argv[i]), &ctx);
918 }
919
920 sha256_finish_ctx(&ctx, result);
921#endif // FOUNDOPENSSL
922
923 char keyname[41];
924 for (int i = 0; i < 20; ++i) {
925 sprintf(&keyname[2 * i], "%02x", result[i]);
926 }
927
928 keyname[40] = '\0';
929
930 char *keyname_copy = strdup(keyname);
931 if (keyname_copy == NULL) {
932 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
933 }
934
935 return keyname_copy;
936}
diff --git a/plugins/check_snmp.d/check_snmp_helpers.h b/plugins/check_snmp.d/check_snmp_helpers.h
new file mode 100644
index 00000000..0f7780b1
--- /dev/null
+++ b/plugins/check_snmp.d/check_snmp_helpers.h
@@ -0,0 +1,71 @@
1#pragma once
2
3#include "./config.h"
4#include <net-snmp/library/asn1.h>
5
6check_snmp_test_unit check_snmp_test_unit_init();
7int check_snmp_set_thresholds(const char *, check_snmp_test_unit[], size_t, bool);
8check_snmp_config check_snmp_config_init();
9
10typedef struct {
11 oid oid[MAX_OID_LEN];
12 size_t oid_length;
13 unsigned char type;
14 union {
15 uint64_t uIntVal;
16 int64_t intVal;
17 double doubleVal;
18 } value;
19 char *string_response;
20} response_value;
21
22typedef struct {
23 int errorcode;
24 response_value *response_values;
25} snmp_responces;
26snmp_responces do_snmp_query(check_snmp_config_snmp_parameters parameters);
27
28// state is similar to response, but only numerics and a timestamp
29typedef struct {
30 time_t timestamp;
31 oid oid[MAX_OID_LEN];
32 size_t oid_length;
33 unsigned char type;
34 union {
35 unsigned long long uIntVal;
36 long long intVal;
37 double doubleVal;
38 } value;
39} check_snmp_state_entry;
40
41typedef struct {
42 check_snmp_state_entry state;
43 mp_subcheck sc;
44} check_snmp_evaluation;
45check_snmp_evaluation evaluate_single_unit(response_value response,
46 check_snmp_evaluation_parameters eval_params,
47 check_snmp_test_unit test_unit, time_t query_timestamp,
48 check_snmp_state_entry prev_state,
49 bool have_previous_state);
50
51#define NP_STATE_FORMAT_VERSION 1
52
53typedef struct state_data_struct {
54 time_t time;
55 void *data;
56 size_t length; /* Of binary data */
57 int errorcode;
58} state_data;
59
60typedef struct state_key_struct {
61 char *name;
62 char *plugin_name;
63 int data_version;
64 char *_filename;
65 state_data *state_data;
66} state_key;
67
68state_data *np_state_read(state_key stateKey);
69state_key np_enable_state(char *keyname, int expected_data_version, char *plugin_name, int argc,
70 char **argv);
71void np_state_write_string(state_key stateKey, time_t timestamp, char *stringToStore);
diff --git a/plugins/check_snmp.d/config.h b/plugins/check_snmp.d/config.h
new file mode 100644
index 00000000..e7b6d1b3
--- /dev/null
+++ b/plugins/check_snmp.d/config.h
@@ -0,0 +1,81 @@
1#pragma once
2
3#include "../../lib/thresholds.h"
4#include "../../lib/states.h"
5#include <stdlib.h>
6#include <stdbool.h>
7#include <regex.h>
8#include "../common.h"
9
10// defines for snmp libs
11#define u_char unsigned char
12#define u_long unsigned long
13#define u_short unsigned short
14#define u_int unsigned int
15
16#include <net-snmp/net-snmp-config.h>
17#include <net-snmp/net-snmp-includes.h>
18#include <net-snmp/library/snmp.h>
19#include <net-snmp/session_api.h>
20
21#define DEFAULT_PORT "161"
22#define DEFAULT_RETRIES 5
23
24typedef struct eval_method {
25 bool crit_string;
26 bool crit_regex;
27} eval_method;
28
29typedef struct check_snmp_test_unit {
30 char *oid;
31 char *label;
32 char *unit_value;
33 eval_method eval_mthd;
34 mp_thresholds threshold;
35} check_snmp_test_unit;
36
37typedef struct {
38 struct snmp_session snmp_session;
39 // use getnet instead of get
40 bool use_getnext;
41
42 // TODO actually make these useful
43 bool ignore_mib_parsing_errors;
44 bool need_mibs;
45
46 check_snmp_test_unit *test_units;
47 size_t num_of_test_units;
48} check_snmp_config_snmp_parameters;
49
50typedef struct {
51 // State if an empty value is encountered
52 mp_state_enum nulloid_result;
53
54 // String evaluation stuff
55 bool invert_search;
56 regex_t regex_cmp_value; // regex to match query results against
57 char string_cmp_value[MAX_INPUT_BUFFER];
58
59 // Modify data
60 double multiplier;
61 bool multiplier_set;
62 double offset;
63 bool offset_set;
64
65 // Modify output
66 bool use_oid_as_perf_data_label;
67
68 // activate rate calculation
69 bool calculate_rate;
70 unsigned int rate_multiplier;
71} check_snmp_evaluation_parameters;
72
73typedef struct check_snmp_config {
74 // SNMP session to use
75 check_snmp_config_snmp_parameters snmp_params;
76
77 check_snmp_evaluation_parameters evaluation_params;
78
79 mp_output_format output_format;
80 bool output_format_is_set;
81} check_snmp_config;
diff --git a/plugins/check_ssh.c b/plugins/check_ssh.c
index 9d0d7cde..f6c8d551 100644
--- a/plugins/check_ssh.c
+++ b/plugins/check_ssh.c
@@ -57,7 +57,8 @@ static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*
57static void print_help(void); 57static void print_help(void);
58void print_usage(void); 58void print_usage(void);
59 59
60static int ssh_connect(mp_check *overall, char *haddr, int hport, char *remote_version, char *remote_protocol); 60static int ssh_connect(mp_check *overall, char *haddr, int hport, char *remote_version,
61 char *remote_protocol);
61 62
62int main(int argc, char **argv) { 63int main(int argc, char **argv) {
63 setlocale(LC_ALL, ""); 64 setlocale(LC_ALL, "");
@@ -85,7 +86,8 @@ int main(int argc, char **argv) {
85 alarm(socket_timeout); 86 alarm(socket_timeout);
86 87
87 /* ssh_connect exits if error is found */ 88 /* ssh_connect exits if error is found */
88 ssh_connect(&overall, config.server_name, config.port, config.remote_version, config.remote_protocol); 89 ssh_connect(&overall, config.server_name, config.port, config.remote_version,
90 config.remote_protocol);
89 91
90 alarm(0); 92 alarm(0);
91 93
@@ -96,19 +98,20 @@ int main(int argc, char **argv) {
96 98
97/* process command-line arguments */ 99/* process command-line arguments */
98process_arguments_wrapper process_arguments(int argc, char **argv) { 100process_arguments_wrapper process_arguments(int argc, char **argv) {
99 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, 101 static struct option longopts[] = {
100 {"version", no_argument, 0, 'V'}, 102 {"help", no_argument, 0, 'h'},
101 {"host", required_argument, 0, 'H'}, /* backward compatibility */ 103 {"version", no_argument, 0, 'V'},
102 {"hostname", required_argument, 0, 'H'}, 104 {"host", required_argument, 0, 'H'}, /* backward compatibility */
103 {"port", required_argument, 0, 'p'}, 105 {"hostname", required_argument, 0, 'H'},
104 {"use-ipv4", no_argument, 0, '4'}, 106 {"port", required_argument, 0, 'p'},
105 {"use-ipv6", no_argument, 0, '6'}, 107 {"use-ipv4", no_argument, 0, '4'},
106 {"timeout", required_argument, 0, 't'}, 108 {"use-ipv6", no_argument, 0, '6'},
107 {"verbose", no_argument, 0, 'v'}, 109 {"timeout", required_argument, 0, 't'},
108 {"remote-version", required_argument, 0, 'r'}, 110 {"verbose", no_argument, 0, 'v'},
109 {"remote-protocol", required_argument, 0, 'P'}, 111 {"remote-version", required_argument, 0, 'r'},
110 {"output-format", required_argument, 0, output_format_index}, 112 {"remote-protocol", required_argument, 0, 'P'},
111 {0, 0, 0, 0}}; 113 {"output-format", required_argument, 0, output_format_index},
114 {0, 0, 0, 0}};
112 115
113 process_arguments_wrapper result = { 116 process_arguments_wrapper result = {
114 .config = check_ssh_config_init(), 117 .config = check_ssh_config_init(),
@@ -228,7 +231,8 @@ process_arguments_wrapper process_arguments(int argc, char **argv) {
228 * 231 *
229 *-----------------------------------------------------------------------*/ 232 *-----------------------------------------------------------------------*/
230 233
231int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_version, char *desired_remote_protocol) { 234int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_version,
235 char *desired_remote_protocol) {
232 struct timeval tv; 236 struct timeval tv;
233 gettimeofday(&tv, NULL); 237 gettimeofday(&tv, NULL);
234 238
@@ -238,32 +242,34 @@ int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_
238 mp_subcheck connection_sc = mp_subcheck_init(); 242 mp_subcheck connection_sc = mp_subcheck_init();
239 if (result != STATE_OK) { 243 if (result != STATE_OK) {
240 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL); 244 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
241 xasprintf(&connection_sc.output, "Failed to establish TCP connection to Host %s and Port %d", haddr, hport); 245 xasprintf(&connection_sc.output,
246 "Failed to establish TCP connection to Host %s and Port %d", haddr, hport);
242 mp_add_subcheck_to_check(overall, connection_sc); 247 mp_add_subcheck_to_check(overall, connection_sc);
243 return result; 248 return result;
244 } 249 }
245 250
246 char *output = (char *)calloc(BUFF_SZ + 1, sizeof(char)); 251 char *output = (char *)calloc(BUFF_SZ + 1, sizeof(char));
247 char *buffer = NULL; 252 char *buffer = NULL;
248 size_t recv_ret = 0; 253 ssize_t recv_ret = 0;
249 char *version_control_string = NULL; 254 char *version_control_string = NULL;
250 size_t byte_offset = 0; 255 size_t byte_offset = 0;
251 while ((version_control_string == NULL) && 256 while ((version_control_string == NULL) &&
252 (recv_ret = recv(socket, output + byte_offset, (unsigned long)(BUFF_SZ - byte_offset), 0) > 0)) { 257 (recv_ret = recv(socket, output + byte_offset, (unsigned long)(BUFF_SZ - byte_offset),
258 0) > 0)) {
253 259
254 if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/ 260 if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/
255 byte_offset = 0; 261 byte_offset = 0;
256 262
257 char *index = NULL; 263 char *index = NULL;
258 unsigned long len = 0;
259 while ((index = strchr(output + byte_offset, '\n')) != NULL) { 264 while ((index = strchr(output + byte_offset, '\n')) != NULL) {
260 /*Partition the buffer so that this line is a separate string, 265 /*Partition the buffer so that this line is a separate string,
261 * by replacing the newline with NUL*/ 266 * by replacing the newline with NUL*/
262 output[(index - output)] = '\0'; 267 output[(index - output)] = '\0';
263 len = strlen(output + byte_offset); 268 size_t len = strlen(output + byte_offset);
264 269
265 if ((len >= 4) && (strncmp(output + byte_offset, "SSH-", 4) == 0)) { 270 if ((len >= 4) && (strncmp(output + byte_offset, "SSH-", 4) == 0)) {
266 /*if the string starts with SSH-, this _should_ be a valid version control string*/ 271 /*if the string starts with SSH-, this _should_ be a valid version control
272 * string*/
267 version_control_string = output + byte_offset; 273 version_control_string = output + byte_offset;
268 break; 274 break;
269 } 275 }
@@ -273,21 +279,23 @@ int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_
273 } 279 }
274 280
275 if (version_control_string == NULL) { 281 if (version_control_string == NULL) {
276 /* move unconsumed data to beginning of buffer, null rest */ 282 /* move unconsumed data to beginning of buffer */
277 memmove((void *)output, (void *)(output + byte_offset + 1), BUFF_SZ - len + 1); 283 memmove((void *)output, (void *)(output + byte_offset), BUFF_SZ - byte_offset);
278 memset(output + byte_offset + 1, 0, BUFF_SZ - byte_offset + 1);
279 284
280 /*start reading from end of current line chunk on next recv*/ 285 /*start reading from end of current line chunk on next recv*/
281 byte_offset = strlen(output); 286 byte_offset = strlen(output);
287
288 /* NUL the rest of the buffer */
289 memset(output + byte_offset, 0, BUFF_SZ - byte_offset);
282 } 290 }
283 } else { 291 } else {
284 byte_offset += recv_ret; 292 byte_offset += (size_t)recv_ret;
285 } 293 }
286 } 294 }
287 295
288 if (recv_ret < 0) { 296 if (recv_ret < 0) {
289 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL); 297 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
290 xasprintf(&connection_sc.output, "%s", "SSH CRITICAL - %s", strerror(errno)); 298 xasprintf(&connection_sc.output, "%s - %s", "SSH CRITICAL - ", strerror(errno));
291 mp_add_subcheck_to_check(overall, connection_sc); 299 mp_add_subcheck_to_check(overall, connection_sc);
292 return OK; 300 return OK;
293 } 301 }
@@ -333,7 +341,8 @@ int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_
333 * "1.x" (e.g., "1.5" or "1.3")." 341 * "1.x" (e.g., "1.5" or "1.3")."
334 * - RFC 4253:5 342 * - RFC 4253:5
335 */ 343 */
336 char *ssh_server = ssh_proto + strspn(ssh_proto, "0123456789.") + 1; /* (+1 for the '-' separating protoversion from softwareversion) */ 344 char *ssh_server = ssh_proto + strspn(ssh_proto, "0123456789.") +
345 1; /* (+1 for the '-' separating protoversion from softwareversion) */
337 346
338 /* If there's a space in the version string, whatever's after the space is a comment 347 /* If there's a space in the version string, whatever's after the space is a comment
339 * (which is NOT part of the server name/version)*/ 348 * (which is NOT part of the server name/version)*/
@@ -345,13 +354,15 @@ int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_
345 mp_subcheck protocol_validity_sc = mp_subcheck_init(); 354 mp_subcheck protocol_validity_sc = mp_subcheck_init();
346 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) { 355 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) {
347 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_CRITICAL); 356 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_CRITICAL);
348 xasprintf(&protocol_validity_sc.output, "Invalid protocol version control string %s", version_control_string); 357 xasprintf(&protocol_validity_sc.output, "Invalid protocol version control string %s",
358 version_control_string);
349 mp_add_subcheck_to_check(overall, protocol_validity_sc); 359 mp_add_subcheck_to_check(overall, protocol_validity_sc);
350 return OK; 360 return OK;
351 } 361 }
352 362
353 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_OK); 363 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_OK);
354 xasprintf(&protocol_validity_sc.output, "Valid protocol version control string %s", version_control_string); 364 xasprintf(&protocol_validity_sc.output, "Valid protocol version control string %s",
365 version_control_string);
355 mp_add_subcheck_to_check(overall, protocol_validity_sc); 366 mp_add_subcheck_to_check(overall, protocol_validity_sc);
356 367
357 ssh_proto[strspn(ssh_proto, "0123456789. ")] = 0; 368 ssh_proto[strspn(ssh_proto, "0123456789. ")] = 0;
@@ -366,8 +377,8 @@ int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_
366 if (desired_remote_version && strcmp(desired_remote_version, ssh_server)) { 377 if (desired_remote_version && strcmp(desired_remote_version, ssh_server)) {
367 mp_subcheck remote_version_sc = mp_subcheck_init(); 378 mp_subcheck remote_version_sc = mp_subcheck_init();
368 remote_version_sc = mp_set_subcheck_state(remote_version_sc, STATE_CRITICAL); 379 remote_version_sc = mp_set_subcheck_state(remote_version_sc, STATE_CRITICAL);
369 xasprintf(&remote_version_sc.output, _("%s (protocol %s) version mismatch, expected '%s'"), ssh_server, ssh_proto, 380 xasprintf(&remote_version_sc.output, _("%s (protocol %s) version mismatch, expected '%s'"),
370 desired_remote_version); 381 ssh_server, ssh_proto, desired_remote_version);
371 close(socket); 382 close(socket);
372 mp_add_subcheck_to_check(overall, remote_version_sc); 383 mp_add_subcheck_to_check(overall, remote_version_sc);
373 return OK; 384 return OK;
@@ -385,11 +396,13 @@ int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_
385 396
386 if (desired_remote_protocol && strcmp(desired_remote_protocol, ssh_proto)) { 397 if (desired_remote_protocol && strcmp(desired_remote_protocol, ssh_proto)) {
387 protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_CRITICAL); 398 protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_CRITICAL);
388 xasprintf(&protocol_version_sc.output, _("%s (protocol %s) protocol version mismatch, expected '%s'"), ssh_server, ssh_proto, 399 xasprintf(&protocol_version_sc.output,
389 desired_remote_protocol); 400 _("%s (protocol %s) protocol version mismatch, expected '%s'"), ssh_server,
401 ssh_proto, desired_remote_protocol);
390 } else { 402 } else {
391 protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_OK); 403 protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_OK);
392 xasprintf(&protocol_version_sc.output, "SSH server version: %s (protocol version: %s)", ssh_server, ssh_proto); 404 xasprintf(&protocol_version_sc.output, "SSH server version: %s (protocol version: %s)",
405 ssh_server, ssh_proto);
393 } 406 }
394 407
395 mp_add_subcheck_to_check(overall, protocol_version_sc); 408 mp_add_subcheck_to_check(overall, protocol_version_sc);
@@ -422,7 +435,8 @@ void print_help(void) {
422 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 435 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
423 436
424 printf(" %s\n", "-r, --remote-version=STRING"); 437 printf(" %s\n", "-r, --remote-version=STRING");
425 printf(" %s\n", _("Alert if string doesn't match expected server version (ex: OpenSSH_3.9p1)")); 438 printf(" %s\n",
439 _("Alert if string doesn't match expected server version (ex: OpenSSH_3.9p1)"));
426 440
427 printf(" %s\n", "-P, --remote-protocol=STRING"); 441 printf(" %s\n", "-P, --remote-protocol=STRING");
428 printf(" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)")); 442 printf(" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)"));
@@ -435,5 +449,6 @@ void print_help(void) {
435 449
436void print_usage(void) { 450void print_usage(void) {
437 printf("%s\n", _("Usage:")); 451 printf("%s\n", _("Usage:"));
438 printf("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] --hostname <host>\n", progname); 452 printf("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] --hostname <host>\n",
453 progname);
439} 454}
diff --git a/plugins/check_swap.c b/plugins/check_swap.c
index cb95949a..dbf53a00 100644
--- a/plugins/check_swap.c
+++ b/plugins/check_swap.c
@@ -90,6 +90,14 @@ int main(int argc, char **argv) {
90 exit(STATE_UNKNOWN); 90 exit(STATE_UNKNOWN);
91 } 91 }
92 92
93 if (verbose) {
94 printf("Swap retrieval result:\n"
95 "\tFree: %llu\n"
96 "\tUsed: %llu\n"
97 "\tTotal: %llu\n",
98 data.metrics.free, data.metrics.used, data.metrics.total);
99 }
100
93 double percent_used; 101 double percent_used;
94 mp_check overall = mp_check_init(); 102 mp_check overall = mp_check_init();
95 if (config.output_format_is_set) { 103 if (config.output_format_is_set) {
@@ -164,7 +172,8 @@ int main(int argc, char **argv) {
164 } 172 }
165 173
166 if (config.warn_is_set) { 174 if (config.warn_is_set) {
167 if ((config.warn.is_percentage && (percent_used >= (100 - (double)config.warn.value))) || config.warn.value >= data.metrics.free) { 175 if ((config.warn.is_percentage && (percent_used >= (100 - (double)config.warn.value))) ||
176 config.warn.value >= data.metrics.free) {
168 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING); 177 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
169 } 178 }
170 } 179 }
@@ -174,13 +183,14 @@ int main(int argc, char **argv) {
174 } 183 }
175 184
176 if (config.crit_is_set) { 185 if (config.crit_is_set) {
177 if ((config.crit.is_percentage && (percent_used >= (100 - (double)config.crit.value))) || config.crit.value >= data.metrics.free) { 186 if ((config.crit.is_percentage && (percent_used >= (100 - (double)config.crit.value))) ||
187 config.crit.value >= data.metrics.free) {
178 sc1 = mp_set_subcheck_state(sc1, STATE_CRITICAL); 188 sc1 = mp_set_subcheck_state(sc1, STATE_CRITICAL);
179 } 189 }
180 } 190 }
181 191
182 xasprintf(&sc1.output, _("%g%% free (%lluMiB out of %lluMiB)"), (100 - percent_used), data.metrics.free >> 20, 192 xasprintf(&sc1.output, _("%g%% free (%lluMiB out of %lluMiB)"), (100 - percent_used),
183 data.metrics.total >> 20); 193 data.metrics.free >> 20, data.metrics.total >> 20);
184 194
185 overall.summary = "Swap"; 195 overall.summary = "Swap";
186 mp_add_subcheck_to_check(&overall, sc1); 196 mp_add_subcheck_to_check(&overall, sc1);
@@ -193,7 +203,9 @@ int check_swap(float free_swap_mb, float total_swap_mb, swap_config config) {
193 return config.no_swap_state; 203 return config.no_swap_state;
194 } 204 }
195 205
196 uint64_t free_swap = (uint64_t)(free_swap_mb * (1024 * 1024)); /* Convert back to bytes as warn and crit specified in bytes */ 206 uint64_t free_swap =
207 (uint64_t)(free_swap_mb *
208 (1024 * 1024)); /* Convert back to bytes as warn and crit specified in bytes */
197 209
198 if (!config.crit.is_percentage && config.crit.value >= free_swap) { 210 if (!config.crit.is_percentage && config.crit.value >= free_swap) {
199 return STATE_CRITICAL; 211 return STATE_CRITICAL;
@@ -202,13 +214,16 @@ int check_swap(float free_swap_mb, float total_swap_mb, swap_config config) {
202 return STATE_WARNING; 214 return STATE_WARNING;
203 } 215 }
204 216
205 uint64_t usage_percentage = (uint64_t)((total_swap_mb - free_swap_mb) / total_swap_mb) * HUNDRED_PERCENT; 217 uint64_t usage_percentage =
218 (uint64_t)((total_swap_mb - free_swap_mb) / total_swap_mb) * HUNDRED_PERCENT;
206 219
207 if (config.crit.is_percentage && config.crit.value != 0 && usage_percentage >= (HUNDRED_PERCENT - config.crit.value)) { 220 if (config.crit.is_percentage && config.crit.value != 0 &&
221 usage_percentage >= (HUNDRED_PERCENT - config.crit.value)) {
208 return STATE_CRITICAL; 222 return STATE_CRITICAL;
209 } 223 }
210 224
211 if (config.warn.is_percentage && config.warn.value != 0 && usage_percentage >= (HUNDRED_PERCENT - config.warn.value)) { 225 if (config.warn.is_percentage && config.warn.value != 0 &&
226 usage_percentage >= (HUNDRED_PERCENT - config.warn.value)) {
212 return STATE_WARNING; 227 return STATE_WARNING;
213 } 228 }
214 229
diff --git a/plugins/check_swap.d/check_swap.h b/plugins/check_swap.d/check_swap.h
index 1000fc9e..8d3c7fcf 100644
--- a/plugins/check_swap.d/check_swap.h
+++ b/plugins/check_swap.d/check_swap.h
@@ -1,7 +1,8 @@
1#pragma once 1#pragma once
2 2
3#include "../common.h" 3#include "../common.h"
4#include "output.h" 4#include "../../lib/output.h"
5#include "../../lib/states.h"
5 6
6#ifndef SWAP_CONVERSION 7#ifndef SWAP_CONVERSION
7# define SWAP_CONVERSION 1 8# define SWAP_CONVERSION 1
@@ -26,7 +27,7 @@ typedef struct {
26 27
27typedef struct { 28typedef struct {
28 bool allswaps; 29 bool allswaps;
29 int no_swap_state; 30 mp_state_enum no_swap_state;
30 bool warn_is_set; 31 bool warn_is_set;
31 check_swap_threshold warn; 32 check_swap_threshold warn;
32 bool crit_is_set; 33 bool crit_is_set;
@@ -42,6 +43,7 @@ swap_config swap_config_init(void);
42 43
43swap_result get_swap_data(swap_config config); 44swap_result get_swap_data(swap_config config);
44swap_result getSwapFromProcMeminfo(char path_to_proc_meminfo[]); 45swap_result getSwapFromProcMeminfo(char path_to_proc_meminfo[]);
45swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[], const char swap_format[]); 46swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[],
47 const char swap_format[]);
46swap_result getSwapFromSwapctl_BSD(swap_config config); 48swap_result getSwapFromSwapctl_BSD(swap_config config);
47swap_result getSwapFromSwap_SRV4(swap_config config); 49swap_result getSwapFromSwap_SRV4(swap_config config);
diff --git a/plugins/check_swap.d/swap.c b/plugins/check_swap.d/swap.c
index 180d5037..58213a3c 100644
--- a/plugins/check_swap.d/swap.c
+++ b/plugins/check_swap.d/swap.c
@@ -52,10 +52,10 @@ swap_result get_swap_data(swap_config config) {
52 } 52 }
53# else // HAVE_SWAP 53# else // HAVE_SWAP
54# ifdef CHECK_SWAP_SWAPCTL_SVR4 54# ifdef CHECK_SWAP_SWAPCTL_SVR4
55 return getSwapFromSwapctl_SRV4(); 55 return getSwapFromSwapctl_SRV4(config);
56# else // CHECK_SWAP_SWAPCTL_SVR4 56# else // CHECK_SWAP_SWAPCTL_SVR4
57# ifdef CHECK_SWAP_SWAPCTL_BSD 57# ifdef CHECK_SWAP_SWAPCTL_BSD
58 return getSwapFromSwapctl_BSD(); 58 return getSwapFromSwapctl_BSD(config);
59# else // CHECK_SWAP_SWAPCTL_BSD 59# else // CHECK_SWAP_SWAPCTL_BSD
60# error No way found to retrieve swap 60# error No way found to retrieve swap
61# endif /* CHECK_SWAP_SWAPCTL_BSD */ 61# endif /* CHECK_SWAP_SWAPCTL_BSD */
@@ -68,7 +68,7 @@ swap_result getSwapFromProcMeminfo(char proc_meminfo[]) {
68 FILE *meminfo_file_ptr; 68 FILE *meminfo_file_ptr;
69 meminfo_file_ptr = fopen(proc_meminfo, "r"); 69 meminfo_file_ptr = fopen(proc_meminfo, "r");
70 70
71 swap_result result = {0}; 71 swap_result result = {};
72 result.errorcode = STATE_UNKNOWN; 72 result.errorcode = STATE_UNKNOWN;
73 73
74 if (meminfo_file_ptr == NULL) { 74 if (meminfo_file_ptr == NULL) {
@@ -78,90 +78,81 @@ swap_result getSwapFromProcMeminfo(char proc_meminfo[]) {
78 return result; 78 return result;
79 } 79 }
80 80
81 uint64_t swap_total = 0; 81 unsigned long swap_total = 0;
82 uint64_t swap_used = 0; 82 unsigned long swap_used = 0;
83 uint64_t swap_free = 0; 83 unsigned long swap_free = 0;
84 84
85 bool found_total = false; 85 bool found_total = false;
86 bool found_used = false;
87 bool found_free = false; 86 bool found_free = false;
88 87
89 char input_buffer[MAX_INPUT_BUFFER]; 88 char input_buffer[MAX_INPUT_BUFFER];
90 char str[32]; 89 char str[32];
91 90
92 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, meminfo_file_ptr)) { 91 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, meminfo_file_ptr)) {
93 uint64_t tmp_KB = 0;
94 92
95 /* 93 /*
96 * The following sscanf call looks for a line looking like: "Swap: 123 94 * The following sscanf call looks for a line looking like: "Swap: 123
97 * 123 123" On which kind of system this format exists, I can not say, 95 * 123 123" which exists on NetBSD (at least),
98 * but I wanted to document this for people who are not adapt with 96 * The unit should be Bytes
99 * sscanf anymore, like me
100 * Also the units used here are unclear and probably wrong
101 */ 97 */
102 if (sscanf(input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %lu %lu %lu", &swap_total, &swap_used, &swap_free) == 3) { 98 if (sscanf(input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %lu %lu %lu", &swap_total, &swap_used,
103 99 &swap_free) == 3) {
104 result.metrics.total += swap_total;
105 result.metrics.used += swap_used;
106 result.metrics.free += swap_free;
107
108 found_total = true; 100 found_total = true;
109 found_free = true; 101 found_free = true;
110 found_used = true;
111
112 // Set error 102 // Set error
113 result.errorcode = STATE_OK; 103 result.errorcode = STATE_OK;
104 // Break out of fgets here, since both scanf expressions might match (NetBSD for
105 // example)
106 break;
107 }
108
109 /*
110 * The following sscanf call looks for lines looking like:
111 * "SwapTotal: 123" and "SwapFree: 123" This format exists at least
112 * on Debian Linux with a 5.* kernel
113 */
114 unsigned long tmp_KB = 0;
115 int sscanf_result = sscanf(input_buffer,
116 "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu "
117 "%*[k]%*[B]",
118 str, &tmp_KB);
119
120 if (sscanf_result == 2) {
121
122 if (verbose >= 3) {
123 printf("Got %s with %lu\n", str, tmp_KB);
124 }
114 125
115 /* 126 /* I think this part is always in Kb, so convert to bytes */
116 * The following sscanf call looks for lines looking like: 127 if (strcmp("Total", str) == 0) {
117 * "SwapTotal: 123" and "SwapFree: 123" This format exists at least 128 swap_total = tmp_KB * 1000;
118 * on Debian Linux with a 5.* kernel 129 found_total = true;
119 */ 130 } else if (strcmp("Free", str) == 0) {
120 } else { 131 swap_free += tmp_KB * 1000;
121 int sscanf_result = sscanf(input_buffer, 132 found_free = true;
122 "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu " 133 } else if (strcmp("Cached", str) == 0) {
123 "%*[k]%*[B]", 134 swap_free += tmp_KB * 1000;
124 str, &tmp_KB);
125
126 if (sscanf_result == 2) {
127
128 if (verbose >= 3) {
129 printf("Got %s with %lu\n", str, tmp_KB);
130 }
131
132 /* I think this part is always in Kb, so convert to bytes */
133 if (strcmp("Total", str) == 0) {
134 swap_total = tmp_KB * 1000;
135 found_total = true;
136 } else if (strcmp("Free", str) == 0) {
137 swap_free = swap_free + tmp_KB * 1000;
138 found_free = true;
139 found_used = true; // No explicit used metric available
140 } else if (strcmp("Cached", str) == 0) {
141 swap_free = swap_free + tmp_KB * 1000;
142 found_free = true;
143 found_used = true; // No explicit used metric available
144 }
145
146 result.errorcode = STATE_OK;
147 } 135 }
136
137 result.errorcode = STATE_OK;
148 } 138 }
149 } 139 }
150 140
151 fclose(meminfo_file_ptr); 141 fclose(meminfo_file_ptr);
152 142
153 result.metrics.total = swap_total; 143 result.metrics.total = swap_total;
154 result.metrics.used = swap_total - swap_free;
155 result.metrics.free = swap_free; 144 result.metrics.free = swap_free;
145 result.metrics.used = swap_total - swap_free;
156 146
157 if (!found_free || !found_total || !found_used) { 147 if (!found_free || !found_total) {
158 result.errorcode = STATE_UNKNOWN; 148 result.errorcode = STATE_UNKNOWN;
159 } 149 }
160 150
161 return result; 151 return result;
162} 152}
163 153
164swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[], const char swap_format[]) { 154swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[],
155 const char swap_format[]) {
165 swap_result result = {0}; 156 swap_result result = {0};
166 157
167 char *temp_buffer; 158 char *temp_buffer;
@@ -224,7 +215,8 @@ swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[]
224 used_swap_mb = total_swap_mb - free_swap_mb; 215 used_swap_mb = total_swap_mb - free_swap_mb;
225 216
226 if (verbose >= 3) { 217 if (verbose >= 3) {
227 printf(_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb, free_swap_mb); 218 printf(_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb,
219 free_swap_mb);
228 } 220 }
229 } else { 221 } else {
230 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { 222 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
@@ -297,8 +289,14 @@ struct swapent {
297}; 289};
298 290
299#else 291#else
292
293// Includes for NetBSD
294# include <unistd.h>
295# include <sys/swap.h>
296
300# define bsd_swapctl swapctl 297# define bsd_swapctl swapctl
301#endif 298
299#endif // CHECK_SWAP_SWAPCTL_BSD
302 300
303swap_result getSwapFromSwapctl_BSD(swap_config config) { 301swap_result getSwapFromSwapctl_BSD(swap_config config) {
304 /* get the number of active swap devices */ 302 /* get the number of active swap devices */
@@ -322,8 +320,8 @@ swap_result getSwapFromSwapctl_BSD(swap_config config) {
322 unsigned long long used_swap_mb = 0; 320 unsigned long long used_swap_mb = 0;
323 321
324 for (int i = 0; i < nswaps; i++) { 322 for (int i = 0; i < nswaps; i++) {
325 dsktotal_mb = (float)ent[i].se_nblks / (float)config.conversion_factor; 323 dsktotal_mb = (double)ent[i].se_nblks / (double)config.conversion_factor;
326 dskused_mb = (float)ent[i].se_inuse / (float)config.conversion_factor; 324 dskused_mb = (double)ent[i].se_inuse / (double)config.conversion_factor;
327 dskfree_mb = (dsktotal_mb - dskused_mb); 325 dskfree_mb = (dsktotal_mb - dskused_mb);
328 326
329 if (config.allswaps && dsktotal_mb > 0) { 327 if (config.allswaps && dsktotal_mb > 0) {
@@ -404,7 +402,8 @@ swap_result getSwapFromSwap_SRV4(swap_config config) {
404 } 402 }
405 403
406 /* initialize swap table + entries */ 404 /* initialize swap table + entries */
407 swaptbl_t *tbl = (swaptbl_t *)malloc(sizeof(swaptbl_t) + (sizeof(swapent_t) * (unsigned long)nswaps)); 405 swaptbl_t *tbl =
406 (swaptbl_t *)malloc(sizeof(swaptbl_t) + (sizeof(swapent_t) * (unsigned long)nswaps));
408 407
409 if (tbl == NULL) { 408 if (tbl == NULL) {
410 die(STATE_UNKNOWN, _("malloc() failed!\n")); 409 die(STATE_UNKNOWN, _("malloc() failed!\n"));
@@ -439,7 +438,8 @@ swap_result getSwapFromSwap_SRV4(swap_config config) {
439 dskused_mb = (dsktotal_mb - dskfree_mb); 438 dskused_mb = (dsktotal_mb - dskfree_mb);
440 439
441 if (verbose >= 3) { 440 if (verbose >= 3) {
442 printf("dsktotal_mb=%.0f dskfree_mb=%.0f dskused_mb=%.0f\n", dsktotal_mb, dskfree_mb, dskused_mb); 441 printf("dsktotal_mb=%.0f dskfree_mb=%.0f dskused_mb=%.0f\n", dsktotal_mb, dskfree_mb,
442 dskused_mb);
443 } 443 }
444 444
445 if (config.allswaps && dsktotal_mb > 0) { 445 if (config.allswaps && dsktotal_mb > 0) {
diff --git a/plugins/check_tcp.c b/plugins/check_tcp.c
index 49ad096c..09806373 100644
--- a/plugins/check_tcp.c
+++ b/plugins/check_tcp.c
@@ -3,7 +3,7 @@
3 * Monitoring check_tcp plugin 3 * Monitoring check_tcp plugin
4 * 4 *
5 * License: GPL 5 * License: GPL
6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2025 Monitoring Plugins Development Team
7 * 7 *
8 * Description: 8 * Description:
9 * 9 *
@@ -29,74 +29,64 @@
29 29
30/* progname "check_tcp" changes depending on symlink called */ 30/* progname "check_tcp" changes depending on symlink called */
31char *progname; 31char *progname;
32const char *copyright = "1999-2024"; 32const char *copyright = "1999-2025";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "common.h" 35#include "./common.h"
36#include "netutils.h" 36#include "./netutils.h"
37#include "utils.h" 37#include "./utils.h"
38#include "utils_tcp.h" 38#include "./check_tcp.d/config.h"
39#include "output.h"
40#include "states.h"
39 41
42#include <sys/types.h>
40#include <ctype.h> 43#include <ctype.h>
41#include <sys/select.h> 44#include <sys/select.h>
42 45
46ssize_t my_recv(int socket_descriptor, char *buf, size_t len, bool use_tls) {
43#ifdef HAVE_SSL 47#ifdef HAVE_SSL
44static bool check_cert = false; 48 if (use_tls) {
45static int days_till_exp_warn, days_till_exp_crit; 49 return np_net_ssl_read(buf, (int)len);
46# define my_recv(buf, len) ((flags & FLAG_SSL) ? np_net_ssl_read(buf, len) : read(sd, buf, len)) 50 }
47# define my_send(buf, len) ((flags & FLAG_SSL) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0)) 51#endif
48#else 52 return read(socket_descriptor, buf, len);
49# define my_recv(buf, len) read(sd, buf, len) 53}
50# define my_send(buf, len) send(sd, buf, len, 0) 54
55ssize_t my_send(int socket_descriptor, char *buf, size_t len, bool use_tls) {
56#ifdef HAVE_SSL
57 if (use_tls) {
58 return np_net_ssl_write(buf, (int)len);
59 }
51#endif 60#endif
61 return write(socket_descriptor, buf, len);
62}
52 63
53/* int my_recv(char *, size_t); */ 64typedef struct {
54static int process_arguments(int /*argc*/, char ** /*argv*/); 65 int errorcode;
55static void print_help(void); 66 check_tcp_config config;
67} check_tcp_config_wrapper;
68static check_tcp_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/,
69 check_tcp_config /*config*/);
70void print_help(const char *service);
56void print_usage(void); 71void print_usage(void);
57 72
58#define EXPECT server_expect[0] 73int verbosity = 0;
59static char *SERVICE = "TCP";
60static char *SEND = NULL;
61static char *QUIT = NULL;
62static int PROTOCOL = IPPROTO_TCP; /* most common is default */
63static int PORT = 0;
64static int READ_TIMEOUT = 2;
65
66static int server_port = 0;
67static char *server_address = NULL;
68static bool host_specified = false;
69static char *server_send = NULL;
70static char *server_quit = NULL;
71static char **server_expect;
72static size_t server_expect_count = 0;
73static ssize_t maxbytes = 0;
74static char **warn_codes = NULL;
75static size_t warn_codes_count = 0;
76static char **crit_codes = NULL;
77static size_t crit_codes_count = 0;
78static unsigned int delay = 0;
79static double warning_time = 0;
80static double critical_time = 0;
81static double elapsed_time = 0;
82static long microsec;
83static int sd = 0;
84#define MAXBUF 1024
85static char buffer[MAXBUF];
86static int expect_mismatch_state = STATE_WARNING;
87static int match_flags = NP_MATCH_EXACT;
88 74
89#ifdef HAVE_SSL 75static const int READ_TIMEOUT = 2;
90static char *sni = NULL; 76
91static bool sni_specified = false; 77const int MAXBUF = 1024;
92#endif
93 78
94#define FLAG_SSL 0x01 79const int DEFAULT_FTP_PORT = 21;
95#define FLAG_VERBOSE 0x02 80const int DEFAULT_POP_PORT = 110;
96#define FLAG_TIME_WARN 0x04 81const int DEFAULT_SPOP_PORT = 995;
97#define FLAG_TIME_CRIT 0x08 82const int DEFAULT_SMTP_PORT = 25;
98#define FLAG_HIDE_OUTPUT 0x10 83const int DEFAULT_SSMTP_PORT = 465;
99static size_t flags; 84const int DEFAULT_IMAP_PORT = 143;
85const int DEFAULT_SIMAP_PORT = 993;
86const int DEFAULT_XMPP_C2S_PORT = 5222;
87const int DEFAULT_NNTP_PORT = 119;
88const int DEFAULT_NNTPS_PORT = 563;
89const int DEFAULT_CLAMD_PORT = 3310;
100 90
101int main(int argc, char **argv) { 91int main(int argc, char **argv) {
102 setlocale(LC_ALL, ""); 92 setlocale(LC_ALL, "");
@@ -105,353 +95,482 @@ int main(int argc, char **argv) {
105 95
106 /* determine program- and service-name quickly */ 96 /* determine program- and service-name quickly */
107 progname = strrchr(argv[0], '/'); 97 progname = strrchr(argv[0], '/');
108 if (progname != NULL) 98 if (progname != NULL) {
109 progname++; 99 progname++;
110 else 100 } else {
111 progname = argv[0]; 101 progname = argv[0];
102 }
103
104 // Initialize config here with values from above,
105 // might be changed by on disk config or cli commands
106 check_tcp_config config = check_tcp_config_init();
112 107
113 size_t prog_name_len = strlen(progname); 108 size_t prog_name_len = strlen(progname);
114 if (prog_name_len > 6 && !memcmp(progname, "check_", 6)) { 109 const size_t prefix_length = strlen("check_");
115 SERVICE = strdup(progname + 6); 110
116 for (size_t i = 0; i < prog_name_len - 6; i++) 111 if (prog_name_len <= prefix_length) {
117 SERVICE[i] = toupper(SERVICE[i]); 112 die(STATE_UNKNOWN, _("Weird progname"));
113 }
114
115 if (!memcmp(progname, "check_", prefix_length)) {
116 config.service = strdup(progname + prefix_length);
117 if (config.service == NULL) {
118 die(STATE_UNKNOWN, _("Allocation failed"));
119 }
120
121 for (size_t i = 0; i < prog_name_len - prefix_length; i++) {
122 config.service[i] = toupper(config.service[i]);
123 }
118 } 124 }
119 125
120 /* set up a reasonable buffer at first (will be realloc()'ed if 126 /* set up a reasonable buffer at first (will be realloc()'ed if
121 * user specifies other options) */ 127 * user specifies other options) */
122 server_expect = calloc(2, sizeof(char *)); 128 config.server_expect = calloc(2, sizeof(char *));
129
130 if (config.server_expect == NULL) {
131 die(STATE_UNKNOWN, _("Allocation failed"));
132 }
123 133
124 /* determine defaults for this service's protocol */ 134 /* determine defaults for this service's protocol */
125 if (!strncmp(SERVICE, "UDP", 3)) { 135 if (!strncmp(config.service, "UDP", strlen("UDP"))) {
126 PROTOCOL = IPPROTO_UDP; 136 config.protocol = IPPROTO_UDP;
127 } else if (!strncmp(SERVICE, "FTP", 3)) { 137 } else if (!strncmp(config.service, "FTP", strlen("FTP"))) {
128 EXPECT = "220"; 138 config.server_expect[0] = "220";
129 QUIT = "QUIT\r\n"; 139 config.quit = "QUIT\r\n";
130 PORT = 21; 140 config.server_port = DEFAULT_FTP_PORT;
131 } else if (!strncmp(SERVICE, "POP", 3) || !strncmp(SERVICE, "POP3", 4)) { 141 } else if (!strncmp(config.service, "POP", strlen("POP")) ||
132 EXPECT = "+OK"; 142 !strncmp(config.service, "POP3", strlen("POP3"))) {
133 QUIT = "QUIT\r\n"; 143 config.server_expect[0] = "+OK";
134 PORT = 110; 144 config.quit = "QUIT\r\n";
135 } else if (!strncmp(SERVICE, "SMTP", 4)) { 145 config.server_port = DEFAULT_POP_PORT;
136 EXPECT = "220"; 146 } else if (!strncmp(config.service, "SMTP", strlen("SMTP"))) {
137 QUIT = "QUIT\r\n"; 147 config.server_expect[0] = "220";
138 PORT = 25; 148 config.quit = "QUIT\r\n";
139 } else if (!strncmp(SERVICE, "IMAP", 4)) { 149 config.server_port = DEFAULT_SMTP_PORT;
140 EXPECT = "* OK"; 150 } else if (!strncmp(config.service, "IMAP", strlen("IMAP"))) {
141 QUIT = "a1 LOGOUT\r\n"; 151 config.server_expect[0] = "* OK";
142 PORT = 143; 152 config.quit = "a1 LOGOUT\r\n";
153 config.server_port = DEFAULT_IMAP_PORT;
143 } 154 }
144#ifdef HAVE_SSL 155#ifdef HAVE_SSL
145 else if (!strncmp(SERVICE, "SIMAP", 5)) { 156 else if (!strncmp(config.service, "SIMAP", strlen("SIMAP"))) {
146 EXPECT = "* OK"; 157 config.server_expect[0] = "* OK";
147 QUIT = "a1 LOGOUT\r\n"; 158 config.quit = "a1 LOGOUT\r\n";
148 flags |= FLAG_SSL; 159 config.use_tls = true;
149 PORT = 993; 160 config.server_port = DEFAULT_SIMAP_PORT;
150 } else if (!strncmp(SERVICE, "SPOP", 4)) { 161 } else if (!strncmp(config.service, "SPOP", strlen("SPOP"))) {
151 EXPECT = "+OK"; 162 config.server_expect[0] = "+OK";
152 QUIT = "QUIT\r\n"; 163 config.quit = "QUIT\r\n";
153 flags |= FLAG_SSL; 164 config.use_tls = true;
154 PORT = 995; 165 config.server_port = DEFAULT_SPOP_PORT;
155 } else if (!strncmp(SERVICE, "SSMTP", 5)) { 166 } else if (!strncmp(config.service, "SSMTP", strlen("SSMTP"))) {
156 EXPECT = "220"; 167 config.server_expect[0] = "220";
157 QUIT = "QUIT\r\n"; 168 config.quit = "QUIT\r\n";
158 flags |= FLAG_SSL; 169 config.use_tls = true;
159 PORT = 465; 170 config.server_port = DEFAULT_SSMTP_PORT;
160 } else if (!strncmp(SERVICE, "JABBER", 6)) { 171 } else if (!strncmp(config.service, "JABBER", strlen("JABBER"))) {
161 SEND = "<stream:stream to=\'host\' xmlns=\'jabber:client\' xmlns:stream=\'http://etherx.jabber.org/streams\'>\n"; 172 config.send = "<stream:stream to=\'host\' xmlns=\'jabber:client\' "
162 EXPECT = "<?xml version=\'1.0\'"; 173 "xmlns:stream=\'http://etherx.jabber.org/streams\'>\n";
163 QUIT = "</stream:stream>\n"; 174 config.server_expect[0] = "<?xml version=\'1.0\'";
164 flags |= FLAG_HIDE_OUTPUT; 175 config.quit = "</stream:stream>\n";
165 PORT = 5222; 176 config.hide_output = true;
166 } else if (!strncmp(SERVICE, "NNTPS", 5)) { 177 config.server_port = DEFAULT_XMPP_C2S_PORT;
167 server_expect_count = 2; 178 } else if (!strncmp(config.service, "NNTPS", strlen("NNTPS"))) {
168 server_expect[0] = "200"; 179 config.server_expect_count = 2;
169 server_expect[1] = "201"; 180 config.server_expect[0] = "200";
170 QUIT = "QUIT\r\n"; 181 config.server_expect[1] = "201";
171 flags |= FLAG_SSL; 182 config.quit = "QUIT\r\n";
172 PORT = 563; 183 config.use_tls = true;
184 config.server_port = DEFAULT_NNTPS_PORT;
173 } 185 }
174#endif 186#endif
175 else if (!strncmp(SERVICE, "NNTP", 4)) { 187 else if (!strncmp(config.service, "NNTP", strlen("NNTP"))) {
176 server_expect_count = 2; 188 config.server_expect_count = 2;
177 server_expect = malloc(sizeof(char *) * server_expect_count); 189 char **tmp = realloc(config.server_expect, config.server_expect_count * sizeof(char *));
178 server_expect[0] = strdup("200"); 190 if (tmp == NULL) {
179 server_expect[1] = strdup("201"); 191 free(config.server_expect);
180 QUIT = "QUIT\r\n"; 192 die(STATE_UNKNOWN, _("Allocation failed"));
181 PORT = 119; 193 }
182 } else if (!strncmp(SERVICE, "CLAMD", 5)) { 194 config.server_expect = tmp;
183 SEND = "PING"; 195
184 EXPECT = "PONG"; 196 config.server_expect[0] = strdup("200");
185 QUIT = NULL; 197 config.server_expect[1] = strdup("201");
186 PORT = 3310; 198 config.quit = "QUIT\r\n";
199 config.server_port = DEFAULT_NNTP_PORT;
200 } else if (!strncmp(config.service, "CLAMD", strlen("CLAMD"))) {
201 config.send = "PING";
202 config.server_expect[0] = "PONG";
203 config.quit = NULL;
204 config.server_port = DEFAULT_CLAMD_PORT;
187 } 205 }
188 /* fallthrough check, so it's supposed to use reverse matching */ 206 /* fallthrough check, so it's supposed to use reverse matching */
189 else if (strcmp(SERVICE, "TCP")) 207 else if (strcmp(config.service, "TCP")) {
190 usage(_("CRITICAL - Generic check_tcp called with unknown service\n")); 208 usage(_("CRITICAL - Generic check_tcp called with unknown service\n"));
191 209 }
192 server_address = "127.0.0.1";
193 server_port = PORT;
194 server_send = SEND;
195 server_quit = QUIT;
196 char *status = NULL;
197 210
198 /* Parse extra opts if any */ 211 /* Parse extra opts if any */
199 argv = np_extra_opts(&argc, argv, progname); 212 argv = np_extra_opts(&argc, argv, progname);
200 213
201 if (process_arguments(argc, argv) == ERROR) 214 check_tcp_config_wrapper paw = process_arguments(argc, argv, config);
215 if (paw.errorcode == ERROR) {
202 usage4(_("Could not parse arguments")); 216 usage4(_("Could not parse arguments"));
217 }
218
219 config = paw.config;
203 220
204 if (flags & FLAG_VERBOSE) { 221 if (verbosity > 0) {
205 printf("Using service %s\n", SERVICE); 222 printf("Using service %s\n", config.service);
206 printf("Port: %d\n", server_port); 223 printf("Port: %d\n", config.server_port);
207 printf("flags: 0x%x\n", (int)flags);
208 } 224 }
209 225
210 if (EXPECT && !server_expect_count) 226 if ((config.server_expect_count == 0) && config.server_expect[0]) {
211 server_expect_count++; 227 config.server_expect_count++;
228 }
212 229
213 if (PROTOCOL == IPPROTO_UDP && !(server_expect_count && server_send)) { 230 if (config.protocol == IPPROTO_UDP && !(config.server_expect_count && config.send)) {
214 usage(_("With UDP checks, a send/expect string must be specified.")); 231 usage(_("With UDP checks, a send/expect string must be specified."));
215 } 232 }
216 233
234 // Initialize check stuff before setting timers
235 mp_check overall = mp_check_init();
236 if (config.output_format_set) {
237 mp_set_format(config.output_format);
238 }
239
217 /* set up the timer */ 240 /* set up the timer */
218 signal(SIGALRM, socket_timeout_alarm_handler); 241 signal(SIGALRM, socket_timeout_alarm_handler);
219 alarm(socket_timeout); 242 alarm(socket_timeout);
220 243
221 /* try to connect to the host at the given port number */ 244 /* try to connect to the host at the given port number */
222 struct timeval tv; 245 struct timeval start_time;
223 gettimeofday(&tv, NULL); 246 gettimeofday(&start_time, NULL);
224 247
225 int result = STATE_UNKNOWN; 248 int socket_descriptor = 0;
226 result = np_net_connect(server_address, server_port, &sd, PROTOCOL); 249 mp_subcheck inital_connect_result = mp_subcheck_init();
227 if (result == STATE_CRITICAL) 250
228 return econn_refuse_state; 251 // Try initial connection
252 if (np_net_connect(config.server_address, config.server_port, &socket_descriptor,
253 config.protocol) == STATE_CRITICAL) {
254 // Early exit here, we got connection refused
255 inital_connect_result =
256 mp_set_subcheck_state(inital_connect_result, config.econn_refuse_state);
257 xasprintf(&inital_connect_result.output, "Connection to %s on port %i was REFUSED",
258 config.server_address, config.server_port);
259 mp_add_subcheck_to_check(&overall, inital_connect_result);
260 mp_exit(overall);
261 } else {
262 inital_connect_result = mp_set_subcheck_state(inital_connect_result, STATE_OK);
263 xasprintf(&inital_connect_result.output, "Connection to %s on port %i was a SUCCESS",
264 config.server_address, config.server_port);
265 mp_add_subcheck_to_check(&overall, inital_connect_result);
266 }
229 267
230#ifdef HAVE_SSL 268#ifdef HAVE_SSL
231 if (flags & FLAG_SSL) { 269 if (config.use_tls) {
232 result = np_net_ssl_init_with_hostname(sd, (sni_specified ? sni : NULL)); 270 mp_subcheck tls_connection_result = mp_subcheck_init();
233 if (result == STATE_OK && check_cert) { 271 mp_state_enum result = np_net_ssl_init_with_hostname(
234 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 272 socket_descriptor, (config.sni_specified ? config.sni : NULL));
273 tls_connection_result = mp_set_subcheck_default_state(tls_connection_result, result);
274
275 if (result == STATE_OK) {
276 xasprintf(&tls_connection_result.output, "TLS connection succeeded");
277
278 if (config.check_cert) {
279 result =
280 np_net_ssl_check_cert(config.days_till_exp_warn, config.days_till_exp_crit);
281
282 mp_subcheck tls_certificate_lifetime_result = mp_subcheck_init();
283 tls_certificate_lifetime_result =
284 mp_set_subcheck_state(tls_certificate_lifetime_result, result);
285
286 if (result == STATE_OK) {
287 xasprintf(&tls_certificate_lifetime_result.output,
288 "Certificate lifetime is within thresholds");
289 } else if (result == STATE_WARNING) {
290 xasprintf(&tls_certificate_lifetime_result.output,
291 "Certificate lifetime is violating warning threshold (%i)",
292 config.days_till_exp_warn);
293 } else if (result == STATE_CRITICAL) {
294 xasprintf(&tls_certificate_lifetime_result.output,
295 "Certificate lifetime is violating critical threshold (%i)",
296 config.days_till_exp_crit);
297 } else {
298 xasprintf(&tls_certificate_lifetime_result.output,
299 "Certificate lifetime is somehow unknown");
300 }
301
302 mp_add_subcheck_to_subcheck(&tls_connection_result,
303 tls_certificate_lifetime_result);
304 }
305
306 mp_add_subcheck_to_check(&overall, tls_connection_result);
307 } else {
308 xasprintf(&tls_connection_result.output, "TLS connection failed");
309 mp_add_subcheck_to_check(&overall, tls_connection_result);
310
311 if (socket_descriptor) {
312 close(socket_descriptor);
313 }
314 np_net_ssl_cleanup();
315
316 mp_exit(overall);
235 } 317 }
236 } 318 }
237 if (result != STATE_OK) {
238 if (sd)
239 close(sd);
240 np_net_ssl_cleanup();
241 return result;
242 }
243#endif /* HAVE_SSL */ 319#endif /* HAVE_SSL */
244 320
245 if (server_send != NULL) { /* Something to send? */ 321 if (config.send != NULL) { /* Something to send? */
246 my_send(server_send, strlen(server_send)); 322 my_send(socket_descriptor, config.send, strlen(config.send), config.use_tls);
247 } 323 }
248 324
249 if (delay > 0) { 325 if (config.delay > 0) {
250 tv.tv_sec += delay; 326 start_time.tv_sec += config.delay;
251 sleep(delay); 327 sleep(config.delay);
252 } 328 }
253 329
254 if (flags & FLAG_VERBOSE) { 330 if (verbosity > 0) {
255 if (server_send) { 331 if (config.send) {
256 printf("Send string: %s\n", server_send); 332 printf("Send string: %s\n", config.send);
333 }
334 if (config.quit) {
335 printf("Quit string: %s\n", config.quit);
257 } 336 }
258 if (server_quit) { 337 printf("server_expect_count: %d\n", (int)config.server_expect_count);
259 printf("Quit string: %s\n", server_quit); 338 for (size_t i = 0; i < config.server_expect_count; i++) {
339 printf("\t%zd: %s\n", i, config.server_expect[i]);
260 } 340 }
261 printf("server_expect_count: %d\n", (int)server_expect_count);
262 for (size_t i = 0; i < server_expect_count; i++)
263 printf("\t%zd: %s\n", i, server_expect[i]);
264 } 341 }
265 342
266 /* if(len) later on, we know we have a non-NULL response */ 343 /* if(len) later on, we know we have a non-NULL response */
267 ssize_t len = 0; 344 ssize_t len = 0;
345 char *received_buffer = NULL;
346 enum np_match_result match = NP_MATCH_NONE;
347 mp_subcheck expected_data_result = mp_subcheck_init();
268 348
269 int match = -1; 349 if (config.server_expect_count) {
270 struct timeval timeout;
271 fd_set rfds;
272 FD_ZERO(&rfds);
273 if (server_expect_count) {
274 ssize_t received = 0; 350 ssize_t received = 0;
351 char buffer[MAXBUF];
275 352
276 /* watch for the expect string */ 353 /* watch for the expect string */
277 while ((received = my_recv(buffer, sizeof(buffer))) > 0) { 354 while ((received = my_recv(socket_descriptor, buffer, sizeof(buffer), config.use_tls)) >
278 status = realloc(status, len + received + 1); 355 0) {
279 memcpy(&status[len], buffer, received); 356 received_buffer = realloc(received_buffer, len + received + 1);
357
358 if (received_buffer == NULL) {
359 die(STATE_UNKNOWN, _("Allocation failed"));
360 }
361
362 memcpy(&received_buffer[len], buffer, received);
280 len += received; 363 len += received;
281 status[len] = '\0'; 364 received_buffer[len] = '\0';
282 365
283 /* stop reading if user-forced */ 366 /* stop reading if user-forced */
284 if (maxbytes && len >= maxbytes) 367 if (config.maxbytes && len >= config.maxbytes) {
285 break; 368 break;
369 }
286 370
287 if ((match = np_expect_match(status, server_expect, server_expect_count, match_flags)) != NP_MATCH_RETRY) 371 if ((match = np_expect_match(received_buffer, config.server_expect,
372 config.server_expect_count, config.match_flags)) !=
373 NP_MATCH_RETRY) {
288 break; 374 break;
375 }
376
377 fd_set rfds;
378 FD_ZERO(&rfds);
379 FD_SET(socket_descriptor, &rfds);
289 380
290 /* some protocols wait for further input, so make sure we don't wait forever */ 381 /* some protocols wait for further input, so make sure we don't wait forever */
291 FD_SET(sd, &rfds); 382 struct timeval timeout;
292 timeout.tv_sec = READ_TIMEOUT; 383 timeout.tv_sec = READ_TIMEOUT;
293 timeout.tv_usec = 0; 384 timeout.tv_usec = 0;
294 if (select(sd + 1, &rfds, NULL, NULL, &timeout) <= 0) 385
386 if (select(socket_descriptor + 1, &rfds, NULL, NULL, &timeout) <= 0) {
295 break; 387 break;
388 }
296 } 389 }
297 390
298 if (match == NP_MATCH_RETRY) 391 if (match == NP_MATCH_RETRY) {
299 match = NP_MATCH_FAILURE; 392 match = NP_MATCH_FAILURE;
393 }
300 394
301 /* no data when expected, so return critical */ 395 /* no data when expected, so return critical */
302 if (len == 0) 396 if (len == 0) {
303 die(STATE_CRITICAL, _("No data received from host\n")); 397 xasprintf(&expected_data_result.output, "Received no data when some was expected");
398 expected_data_result = mp_set_subcheck_state(expected_data_result, STATE_CRITICAL);
399 mp_add_subcheck_to_check(&overall, expected_data_result);
400 mp_exit(overall);
401 }
304 402
305 /* print raw output if we're debugging */ 403 /* print raw output if we're debugging */
306 if (flags & FLAG_VERBOSE) 404 if (verbosity > 0) {
307 printf("received %d bytes from host\n#-raw-recv-------#\n%s\n#-raw-recv-------#\n", (int)len + 1, status); 405 printf("received %d bytes from host\n#-raw-recv-------#\n%s\n#-raw-recv-------#\n",
406 (int)len + 1, received_buffer);
407 }
308 /* strip whitespace from end of output */ 408 /* strip whitespace from end of output */
309 while (--len > 0 && isspace(status[len])) 409 while (--len > 0 && isspace(received_buffer[len])) {
310 status[len] = '\0'; 410 received_buffer[len] = '\0';
411 }
311 } 412 }
312 413
313 if (server_quit != NULL) { 414 if (config.quit != NULL) {
314 my_send(server_quit, strlen(server_quit)); 415 my_send(socket_descriptor, config.quit, strlen(config.quit), config.use_tls);
416 }
417
418 if (socket_descriptor) {
419 close(socket_descriptor);
315 } 420 }
316 if (sd)
317 close(sd);
318#ifdef HAVE_SSL 421#ifdef HAVE_SSL
319 np_net_ssl_cleanup(); 422 np_net_ssl_cleanup();
320#endif 423#endif
321 424
322 microsec = deltime(tv); 425 long microsec = deltime(start_time);
323 elapsed_time = (double)microsec / 1.0e6; 426 double elapsed_time = (double)microsec / 1.0e6;
427
428 mp_subcheck elapsed_time_result = mp_subcheck_init();
429
430 mp_perfdata time_pd = perfdata_init();
431 time_pd = mp_set_pd_value(time_pd, elapsed_time);
432 time_pd.label = "time";
433 time_pd.uom = "s";
434
435 if (config.critical_time_set && elapsed_time > config.critical_time) {
436 xasprintf(&elapsed_time_result.output,
437 "Connection time %fs exceeded critical threshold (%f)", elapsed_time,
438 config.critical_time);
439
440 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_CRITICAL);
441 time_pd.crit_present = true;
442 mp_range crit_val = mp_range_init();
443
444 crit_val.end = mp_create_pd_value(config.critical_time);
445 crit_val.end_infinity = false;
446
447 time_pd.crit = crit_val;
448 } else if (config.warning_time_set && elapsed_time > config.warning_time) {
449 xasprintf(&elapsed_time_result.output,
450 "Connection time %fs exceeded warning threshold (%f)", elapsed_time,
451 config.critical_time);
452
453 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_WARNING);
454 time_pd.warn_present = true;
455 mp_range warn_val = mp_range_init();
456 warn_val.end = mp_create_pd_value(config.critical_time);
457 warn_val.end_infinity = false;
458
459 time_pd.warn = warn_val;
460 } else {
461 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_OK);
462 xasprintf(&elapsed_time_result.output, "Connection time %fs is within thresholds",
463 elapsed_time);
464 }
324 465
325 if (flags & FLAG_TIME_CRIT && elapsed_time > critical_time) 466 mp_add_perfdata_to_subcheck(&elapsed_time_result, time_pd);
326 result = STATE_CRITICAL; 467 mp_add_subcheck_to_check(&overall, elapsed_time_result);
327 else if (flags & FLAG_TIME_WARN && elapsed_time > warning_time)
328 result = STATE_WARNING;
329 468
330 /* did we get the response we hoped? */ 469 /* did we get the response we hoped? */
331 if (match == NP_MATCH_FAILURE && result != STATE_CRITICAL) 470 if (match == NP_MATCH_FAILURE) {
332 result = expect_mismatch_state; 471 expected_data_result =
472 mp_set_subcheck_state(expected_data_result, config.expect_mismatch_state);
473 xasprintf(&expected_data_result.output, "Answer failed to match expectation");
474 mp_add_subcheck_to_check(&overall, expected_data_result);
475 } else if (match == NP_MATCH_SUCCESS) {
476 expected_data_result = mp_set_subcheck_state(expected_data_result, STATE_OK);
477 xasprintf(&expected_data_result.output, "The answer of the server matched the expectation");
478 mp_add_subcheck_to_check(&overall, expected_data_result);
479 }
333 480
334 /* reset the alarm */ 481 /* reset the alarm */
335 alarm(0); 482 alarm(0);
336 483
337 /* this is a bit stupid, because we don't want to print the 484 mp_exit(overall);
338 * response time (which can look ok to the user) if we didn't get
339 * the response we were looking for. if-else */
340 printf("%s %s - ", SERVICE, state_text(result));
341
342 if (match == NP_MATCH_FAILURE && len && !(flags & FLAG_HIDE_OUTPUT))
343 printf("Unexpected response from host/socket: %s", status);
344 else {
345 if (match == NP_MATCH_FAILURE)
346 printf("Unexpected response from host/socket on ");
347 else
348 printf("%.3f second response time on ", elapsed_time);
349 if (server_address[0] != '/') {
350 if (host_specified)
351 printf("%s port %d", server_address, server_port);
352 else
353 printf("port %d", server_port);
354 } else
355 printf("socket %s", server_address);
356 }
357
358 if (match != NP_MATCH_FAILURE && !(flags & FLAG_HIDE_OUTPUT) && len)
359 printf(" [%s]", status);
360
361 /* perf-data doesn't apply when server doesn't talk properly,
362 * so print all zeroes on warn and crit. Use fperfdata since
363 * localisation settings can make different outputs */
364 if (match == NP_MATCH_FAILURE)
365 printf("|%s", fperfdata("time", elapsed_time, "s", (flags & FLAG_TIME_WARN ? true : false), 0,
366 (flags & FLAG_TIME_CRIT ? true : false), 0, true, 0, true, socket_timeout));
367 else
368 printf("|%s", fperfdata("time", elapsed_time, "s", (flags & FLAG_TIME_WARN ? true : false), warning_time,
369 (flags & FLAG_TIME_CRIT ? true : false), critical_time, true, 0, true, socket_timeout));
370
371 putchar('\n');
372 return result;
373} 485}
374 486
375/* process command-line arguments */ 487/* process command-line arguments */
376static int process_arguments(int argc, char **argv) { 488static check_tcp_config_wrapper process_arguments(int argc, char **argv, check_tcp_config config) {
377 enum { 489 enum {
378 SNI_OPTION = CHAR_MAX + 1 490 SNI_OPTION = CHAR_MAX + 1,
491 output_format_index,
379 }; 492 };
380 493
381 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 494 static struct option longopts[] = {
382 {"critical", required_argument, 0, 'c'}, 495 {"hostname", required_argument, 0, 'H'},
383 {"warning", required_argument, 0, 'w'}, 496 {"critical", required_argument, 0, 'c'},
384 {"critical-codes", required_argument, 0, 'C'}, 497 {"warning", required_argument, 0, 'w'},
385 {"warning-codes", required_argument, 0, 'W'}, 498 {"critical-codes", required_argument, 0, 'C'},
386 {"timeout", required_argument, 0, 't'}, 499 {"warning-codes", required_argument, 0, 'W'},
387 {"protocol", required_argument, 0, 'P'}, /* FIXME: Unhandled */ 500 {"timeout", required_argument, 0, 't'},
388 {"port", required_argument, 0, 'p'}, 501 {"protocol", required_argument, 0, 'P'}, /* FIXME: Unhandled */
389 {"escape", no_argument, 0, 'E'}, 502 {"port", required_argument, 0, 'p'},
390 {"all", no_argument, 0, 'A'}, 503 {"escape", no_argument, 0, 'E'},
391 {"send", required_argument, 0, 's'}, 504 {"all", no_argument, 0, 'A'},
392 {"expect", required_argument, 0, 'e'}, 505 {"send", required_argument, 0, 's'},
393 {"maxbytes", required_argument, 0, 'm'}, 506 {"expect", required_argument, 0, 'e'},
394 {"quit", required_argument, 0, 'q'}, 507 {"maxbytes", required_argument, 0, 'm'},
395 {"jail", no_argument, 0, 'j'}, 508 {"quit", required_argument, 0, 'q'},
396 {"delay", required_argument, 0, 'd'}, 509 {"jail", no_argument, 0, 'j'},
397 {"refuse", required_argument, 0, 'r'}, 510 {"delay", required_argument, 0, 'd'},
398 {"mismatch", required_argument, 0, 'M'}, 511 {"refuse", required_argument, 0, 'r'},
399 {"use-ipv4", no_argument, 0, '4'}, 512 {"mismatch", required_argument, 0, 'M'},
400 {"use-ipv6", no_argument, 0, '6'}, 513 {"use-ipv4", no_argument, 0, '4'},
401 {"verbose", no_argument, 0, 'v'}, 514 {"use-ipv6", no_argument, 0, '6'},
402 {"version", no_argument, 0, 'V'}, 515 {"verbose", no_argument, 0, 'v'},
403 {"help", no_argument, 0, 'h'}, 516 {"version", no_argument, 0, 'V'},
404 {"ssl", no_argument, 0, 'S'}, 517 {"help", no_argument, 0, 'h'},
405 {"sni", required_argument, 0, SNI_OPTION}, 518 {"ssl", no_argument, 0, 'S'},
406 {"certificate", required_argument, 0, 'D'}, 519 {"sni", required_argument, 0, SNI_OPTION},
407 {0, 0, 0, 0}}; 520 {"certificate", required_argument, 0, 'D'},
408 521 {"output-format", required_argument, 0, output_format_index},
409 if (argc < 2) 522 {0, 0, 0, 0}};
523
524 if (argc < 2) {
410 usage4(_("No arguments found")); 525 usage4(_("No arguments found"));
526 }
411 527
412 /* backwards compatibility */ 528 /* backwards compatibility */
413 for (int i = 1; i < argc; i++) { 529 for (int i = 1; i < argc; i++) {
414 if (strcmp("-to", argv[i]) == 0) 530 if (strcmp("-to", argv[i]) == 0) {
415 strcpy(argv[i], "-t"); 531 strcpy(argv[i], "-t");
416 else if (strcmp("-wt", argv[i]) == 0) 532 } else if (strcmp("-wt", argv[i]) == 0) {
417 strcpy(argv[i], "-w"); 533 strcpy(argv[i], "-w");
418 else if (strcmp("-ct", argv[i]) == 0) 534 } else if (strcmp("-ct", argv[i]) == 0) {
419 strcpy(argv[i], "-c"); 535 strcpy(argv[i], "-c");
536 }
420 } 537 }
421 538
422 if (!is_option(argv[1])) { 539 if (!is_option(argv[1])) {
423 server_address = argv[1]; 540 config.server_address = argv[1];
424 argv[1] = argv[0]; 541 argv[1] = argv[0];
425 argv = &argv[1]; 542 argv = &argv[1];
426 argc--; 543 argc--;
427 } 544 }
428 545
429 int option_char;
430 bool escape = false; 546 bool escape = false;
547
431 while (true) { 548 while (true) {
432 int option = 0; 549 int option = 0;
433 option_char = getopt_long(argc, argv, "+hVv46EAH:s:e:q:m:c:w:t:p:C:W:d:Sr:jD:M:", longopts, &option); 550 int option_index =
551 getopt_long(argc, argv, "+hVv46EAH:s:e:q:m:c:w:t:p:C:W:d:Sr:jD:M:", longopts, &option);
434 552
435 if (option_char == -1 || option_char == EOF || option_char == 1) 553 if (option_index == -1 || option_index == EOF || option_index == 1) {
436 break; 554 break;
555 }
437 556
438 switch (option_char) { 557 switch (option_index) {
439 case '?': /* print short usage statement if args not parsable */ 558 case '?': /* print short usage statement if args not parsable */
440 usage5(); 559 usage5();
441 case 'h': /* help */ 560 case 'h': /* help */
442 print_help(); 561 print_help(config.service);
443 exit(STATE_UNKNOWN); 562 exit(STATE_UNKNOWN);
444 case 'V': /* version */ 563 case 'V': /* version */
445 print_revision(progname, NP_VERSION); 564 print_revision(progname, NP_VERSION);
446 exit(STATE_UNKNOWN); 565 exit(STATE_UNKNOWN);
447 case 'v': /* verbose mode */ 566 case 'v': /* verbose mode */
448 flags |= FLAG_VERBOSE; 567 verbosity++;
449 match_flags |= NP_MATCH_VERBOSE; 568 config.match_flags |= NP_MATCH_VERBOSE;
450 break; 569 break;
451 case '4': 570 case '4': // Apparently unused TODO
452 address_family = AF_INET; 571 address_family = AF_INET;
453 break; 572 break;
454 case '6': 573 case '6': // Apparently unused TODO
455#ifdef USE_IPV6 574#ifdef USE_IPV6
456 address_family = AF_INET6; 575 address_family = AF_INET6;
457#else 576#else
@@ -459,163 +578,192 @@ static int process_arguments(int argc, char **argv) {
459#endif 578#endif
460 break; 579 break;
461 case 'H': /* hostname */ 580 case 'H': /* hostname */
462 host_specified = true; 581 config.host_specified = true;
463 server_address = optarg; 582 config.server_address = optarg;
464 break; 583 break;
465 case 'c': /* critical */ 584 case 'c': /* critical */
466 critical_time = strtod(optarg, NULL); 585 config.critical_time = strtod(optarg, NULL);
467 flags |= FLAG_TIME_CRIT; 586 config.critical_time_set = true;
468 break; 587 break;
469 case 'j': /* hide output */ 588 case 'j': /* hide output */
470 flags |= FLAG_HIDE_OUTPUT; 589 config.hide_output = true;
471 break; 590 break;
472 case 'w': /* warning */ 591 case 'w': /* warning */
473 warning_time = strtod(optarg, NULL); 592 config.warning_time = strtod(optarg, NULL);
474 flags |= FLAG_TIME_WARN; 593 config.warning_time_set = true;
475 break;
476 case 'C':
477 crit_codes = realloc(crit_codes, ++crit_codes_count);
478 crit_codes[crit_codes_count - 1] = optarg;
479 break;
480 case 'W':
481 warn_codes = realloc(warn_codes, ++warn_codes_count);
482 warn_codes[warn_codes_count - 1] = optarg;
483 break; 594 break;
484 case 't': /* timeout */ 595 case 't': /* timeout */
485 if (!is_intpos(optarg)) 596 if (!is_intpos(optarg)) {
486 usage4(_("Timeout interval must be a positive integer")); 597 usage4(_("Timeout interval must be a positive integer"));
487 else 598 } else {
488 socket_timeout = atoi(optarg); 599 socket_timeout = atoi(optarg);
600 }
489 break; 601 break;
490 case 'p': /* port */ 602 case 'p': /* port */
491 if (!is_intpos(optarg)) 603 if (!is_intpos(optarg)) {
492 usage4(_("Port must be a positive integer")); 604 usage4(_("Port must be a positive integer"));
493 else 605 } else {
494 server_port = atoi(optarg); 606 config.server_port = atoi(optarg);
607 }
495 break; 608 break;
496 case 'E': 609 case 'E':
497 escape = true; 610 escape = true;
498 break; 611 break;
499 case 's': 612 case 's':
500 if (escape) 613 if (escape) {
501 server_send = np_escaped_string(optarg); 614 config.send = np_escaped_string(optarg);
502 else 615 } else {
503 xasprintf(&server_send, "%s", optarg); 616 xasprintf(&config.send, "%s", optarg);
617 }
504 break; 618 break;
505 case 'e': /* expect string (may be repeated) */ 619 case 'e': /* expect string (may be repeated) */
506 match_flags &= ~NP_MATCH_EXACT; 620 config.match_flags &= ~NP_MATCH_EXACT;
507 if (server_expect_count == 0) 621 if (config.server_expect_count == 0) {
508 server_expect = malloc(sizeof(char *) * (++server_expect_count)); 622 config.server_expect = malloc(sizeof(char *) * (++config.server_expect_count));
509 else 623 } else {
510 server_expect = realloc(server_expect, sizeof(char *) * (++server_expect_count)); 624 config.server_expect =
511 server_expect[server_expect_count - 1] = optarg; 625 realloc(config.server_expect, sizeof(char *) * (++config.server_expect_count));
626 }
627
628 if (config.server_expect == NULL) {
629 die(STATE_UNKNOWN, _("Allocation failed"));
630 }
631 config.server_expect[config.server_expect_count - 1] = optarg;
512 break; 632 break;
513 case 'm': 633 case 'm':
514 if (!is_intpos(optarg)) 634 if (!is_intpos(optarg)) {
515 usage4(_("Maxbytes must be a positive integer")); 635 usage4(_("Maxbytes must be a positive integer"));
516 else 636 } else {
517 maxbytes = strtol(optarg, NULL, 0); 637 config.maxbytes = strtol(optarg, NULL, 0);
638 }
518 break; 639 break;
519 case 'q': 640 case 'q':
520 if (escape) 641 if (escape) {
521 server_quit = np_escaped_string(optarg); 642 config.quit = np_escaped_string(optarg);
522 else 643 } else {
523 xasprintf(&server_quit, "%s\r\n", optarg); 644 xasprintf(&config.quit, "%s\r\n", optarg);
645 }
524 break; 646 break;
525 case 'r': 647 case 'r':
526 if (!strncmp(optarg, "ok", 2)) 648 if (!strncmp(optarg, "ok", 2)) {
527 econn_refuse_state = STATE_OK; 649 config.econn_refuse_state = STATE_OK;
528 else if (!strncmp(optarg, "warn", 4)) 650 } else if (!strncmp(optarg, "warn", 4)) {
529 econn_refuse_state = STATE_WARNING; 651 config.econn_refuse_state = STATE_WARNING;
530 else if (!strncmp(optarg, "crit", 4)) 652 } else if (!strncmp(optarg, "crit", 4)) {
531 econn_refuse_state = STATE_CRITICAL; 653 config.econn_refuse_state = STATE_CRITICAL;
532 else 654 } else {
533 usage4(_("Refuse must be one of ok, warn, crit")); 655 usage4(_("Refuse must be one of ok, warn, crit"));
656 }
534 break; 657 break;
535 case 'M': 658 case 'M':
536 if (!strncmp(optarg, "ok", 2)) 659 if (!strncmp(optarg, "ok", 2)) {
537 expect_mismatch_state = STATE_OK; 660 config.expect_mismatch_state = STATE_OK;
538 else if (!strncmp(optarg, "warn", 4)) 661 } else if (!strncmp(optarg, "warn", 4)) {
539 expect_mismatch_state = STATE_WARNING; 662 config.expect_mismatch_state = STATE_WARNING;
540 else if (!strncmp(optarg, "crit", 4)) 663 } else if (!strncmp(optarg, "crit", 4)) {
541 expect_mismatch_state = STATE_CRITICAL; 664 config.expect_mismatch_state = STATE_CRITICAL;
542 else 665 } else {
543 usage4(_("Mismatch must be one of ok, warn, crit")); 666 usage4(_("Mismatch must be one of ok, warn, crit"));
667 }
544 break; 668 break;
545 case 'd': 669 case 'd':
546 if (is_intpos(optarg)) 670 if (is_intpos(optarg)) {
547 delay = atoi(optarg); 671 config.delay = atoi(optarg);
548 else 672 } else {
549 usage4(_("Delay must be a positive integer")); 673 usage4(_("Delay must be a positive integer"));
674 }
550 break; 675 break;
551 case 'D': { /* Check SSL cert validity - days 'til certificate expiration */ 676 case 'D': /* Check SSL cert validity - days 'til certificate expiration */
552#ifdef HAVE_SSL 677#ifdef HAVE_SSL
553# ifdef USE_OPENSSL /* XXX */ 678# ifdef USE_OPENSSL /* XXX */
679 {
554 char *temp; 680 char *temp;
555 if ((temp = strchr(optarg, ',')) != NULL) { 681 if ((temp = strchr(optarg, ',')) != NULL) {
556 *temp = '\0'; 682 *temp = '\0';
557 if (!is_intnonneg(optarg)) 683 if (!is_intnonneg(optarg)) {
558 usage2(_("Invalid certificate expiration period"), optarg); 684 usage2(_("Invalid certificate expiration period"), optarg);
559 days_till_exp_warn = atoi(optarg); 685 }
686 config.days_till_exp_warn = atoi(optarg);
560 *temp = ','; 687 *temp = ',';
561 temp++; 688 temp++;
562 if (!is_intnonneg(temp)) 689 if (!is_intnonneg(temp)) {
563 usage2(_("Invalid certificate expiration period"), temp); 690 usage2(_("Invalid certificate expiration period"), temp);
564 days_till_exp_crit = atoi(temp); 691 }
692 config.days_till_exp_crit = atoi(temp);
565 } else { 693 } else {
566 days_till_exp_crit = 0; 694 config.days_till_exp_crit = 0;
567 if (!is_intnonneg(optarg)) 695 if (!is_intnonneg(optarg)) {
568 usage2(_("Invalid certificate expiration period"), optarg); 696 usage2(_("Invalid certificate expiration period"), optarg);
569 days_till_exp_warn = atoi(optarg); 697 }
698 config.days_till_exp_warn = atoi(optarg);
570 } 699 }
571 check_cert = true; 700 config.check_cert = true;
572 flags |= FLAG_SSL; 701 config.use_tls = true;
573 } break; 702 } break;
574# endif /* USE_OPENSSL */ 703# endif /* USE_OPENSSL */
575#endif 704#endif
576 /* fallthrough if we don't have ssl */ 705 /* fallthrough if we don't have ssl */
577 case 'S': 706 case 'S':
578#ifdef HAVE_SSL 707#ifdef HAVE_SSL
579 flags |= FLAG_SSL; 708 config.use_tls = true;
580#else 709#else
581 die(STATE_UNKNOWN, _("Invalid option - SSL is not available")); 710 die(STATE_UNKNOWN, _("Invalid option - SSL is not available"));
582#endif 711#endif
583 break; 712 break;
584 case SNI_OPTION: 713 case SNI_OPTION:
585#ifdef HAVE_SSL 714#ifdef HAVE_SSL
586 flags |= FLAG_SSL; 715 config.use_tls = true;
587 sni_specified = true; 716 config.sni_specified = true;
588 sni = optarg; 717 config.sni = optarg;
589#else 718#else
590 die(STATE_UNKNOWN, _("Invalid option - SSL is not available")); 719 die(STATE_UNKNOWN, _("Invalid option - SSL is not available"));
591#endif 720#endif
592 break; 721 break;
593 case 'A': 722 case 'A':
594 match_flags |= NP_MATCH_ALL; 723 config.match_flags |= NP_MATCH_ALL;
724 break;
725 case output_format_index: {
726 parsed_output_format parser = mp_parse_output_format(optarg);
727 if (!parser.parsing_success) {
728 // TODO List all available formats here, maybe add anothoer usage function
729 printf("Invalid output format: %s\n", optarg);
730 exit(STATE_UNKNOWN);
731 }
732
733 config.output_format_set = true;
734 config.output_format = parser.output_format;
595 break; 735 break;
596 } 736 }
737 }
597 } 738 }
598 739
599 option_char = optind; 740 int index = optind;
600 if (!host_specified && option_char < argc) 741 if (!config.host_specified && index < argc) {
601 server_address = strdup(argv[option_char++]); 742 config.server_address = strdup(argv[index++]);
743 }
602 744
603 if (server_address == NULL) 745 if (config.server_address == NULL) {
604 usage4(_("You must provide a server address")); 746 usage4(_("You must provide a server address"));
605 else if (server_address[0] != '/' && !is_host(server_address)) 747 } else if (config.server_address[0] != '/' && !is_host(config.server_address)) {
606 die(STATE_CRITICAL, "%s %s - %s: %s\n", SERVICE, state_text(STATE_CRITICAL), _("Invalid hostname, address or socket"), 748 die(STATE_CRITICAL, "%s %s - %s: %s\n", config.service, state_text(STATE_CRITICAL),
607 server_address); 749 _("Invalid hostname, address or socket"), config.server_address);
750 }
608 751
609 return OK; 752 check_tcp_config_wrapper result = {
753 .config = config,
754 .errorcode = OK,
755 };
756 return result;
610} 757}
611 758
612void print_help(void) { 759void print_help(const char *service) {
613 print_revision(progname, NP_VERSION); 760 print_revision(progname, NP_VERSION);
614 761
615 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 762 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
616 printf(COPYRIGHT, copyright, email); 763 printf(COPYRIGHT, copyright, email);
617 764
618 printf(_("This plugin tests %s connections with the specified host (or unix socket).\n\n"), SERVICE); 765 printf(_("This plugin tests %s connections with the specified host (or unix socket).\n\n"),
766 service);
619 767
620 print_usage(); 768 print_usage();
621 769
@@ -627,7 +775,8 @@ void print_help(void) {
627 printf(UT_IPv46); 775 printf(UT_IPv46);
628 776
629 printf(" %s\n", "-E, --escape"); 777 printf(" %s\n", "-E, --escape");
630 printf(" %s\n", _("Can use \\n, \\r, \\t or \\\\ in send or quit string. Must come before send or quit option")); 778 printf(" %s\n", _("Can use \\n, \\r, \\t or \\\\ in send or quit string. Must come before "
779 "send or quit option"));
631 printf(" %s\n", _("Default: nothing added to send, \\r\\n added to end of quit")); 780 printf(" %s\n", _("Default: nothing added to send, \\r\\n added to end of quit"));
632 printf(" %s\n", "-s, --send=STRING"); 781 printf(" %s\n", "-s, --send=STRING");
633 printf(" %s\n", _("String to send to the server")); 782 printf(" %s\n", _("String to send to the server"));
@@ -640,7 +789,8 @@ void print_help(void) {
640 printf(" %s\n", "-r, --refuse=ok|warn|crit"); 789 printf(" %s\n", "-r, --refuse=ok|warn|crit");
641 printf(" %s\n", _("Accept TCP refusals with states ok, warn, crit (default: crit)")); 790 printf(" %s\n", _("Accept TCP refusals with states ok, warn, crit (default: crit)"));
642 printf(" %s\n", "-M, --mismatch=ok|warn|crit"); 791 printf(" %s\n", "-M, --mismatch=ok|warn|crit");
643 printf(" %s\n", _("Accept expected string mismatches with states ok, warn, crit (default: warn)")); 792 printf(" %s\n",
793 _("Accept expected string mismatches with states ok, warn, crit (default: warn)"));
644 printf(" %s\n", "-j, --jail"); 794 printf(" %s\n", "-j, --jail");
645 printf(" %s\n", _("Hide output from TCP socket")); 795 printf(" %s\n", _("Hide output from TCP socket"));
646 printf(" %s\n", "-m, --maxbytes=INTEGER"); 796 printf(" %s\n", "-m, --maxbytes=INTEGER");
@@ -662,6 +812,7 @@ void print_help(void) {
662 812
663 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 813 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
664 814
815 printf(UT_OUTPUT_FORMAT);
665 printf(UT_VERBOSE); 816 printf(UT_VERBOSE);
666 817
667 printf(UT_SUPPORT); 818 printf(UT_SUPPORT);
@@ -669,7 +820,8 @@ void print_help(void) {
669 820
670void print_usage(void) { 821void print_usage(void) {
671 printf("%s\n", _("Usage:")); 822 printf("%s\n", _("Usage:"));
672 printf("%s -H host -p port [-w <warning time>] [-c <critical time>] [-s <send string>]\n", progname); 823 printf("%s -H host -p port [-w <warning time>] [-c <critical time>] [-s <send string>]\n",
824 progname);
673 printf("[-e <expect string>] [-q <quit string>][-m <maximum bytes>] [-d <delay>]\n"); 825 printf("[-e <expect string>] [-q <quit string>][-m <maximum bytes>] [-d <delay>]\n");
674 printf("[-t <timeout seconds>] [-r <refuse state>] [-M <mismatch state>] [-v] [-4|-6] [-j]\n"); 826 printf("[-t <timeout seconds>] [-r <refuse state>] [-M <mismatch state>] [-v] [-4|-6] [-j]\n");
675 printf("[-D <warn days cert expire>[,<crit days cert expire>]] [-S <use SSL>] [-E]\n"); 827 printf("[-D <warn days cert expire>[,<crit days cert expire>]] [-S <use SSL>] [-E]\n");
diff --git a/plugins/check_tcp.d/config.h b/plugins/check_tcp.d/config.h
new file mode 100644
index 00000000..dc25d79e
--- /dev/null
+++ b/plugins/check_tcp.d/config.h
@@ -0,0 +1,84 @@
1#pragma once
2
3#include "../../lib/utils_tcp.h"
4#include "output.h"
5#include "states.h"
6#include <netinet/in.h>
7
8typedef struct {
9 char *server_address;
10 bool host_specified;
11 int server_port; // TODO can this be a uint16?
12
13 int protocol; /* most common is default */
14 char *service;
15 char *send;
16 char *quit;
17 char **server_expect;
18 size_t server_expect_count;
19 bool use_tls;
20#ifdef HAVE_SSL
21 char *sni;
22 bool sni_specified;
23 bool check_cert;
24 int days_till_exp_warn;
25 int days_till_exp_crit;
26#endif // HAVE_SSL
27 int match_flags;
28 mp_state_enum expect_mismatch_state;
29 unsigned int delay;
30
31 bool warning_time_set;
32 double warning_time;
33 bool critical_time_set;
34 double critical_time;
35
36 mp_state_enum econn_refuse_state;
37
38 ssize_t maxbytes;
39
40 bool hide_output;
41
42 bool output_format_set;
43 mp_output_format output_format;
44} check_tcp_config;
45
46check_tcp_config check_tcp_config_init() {
47 check_tcp_config result = {
48 .server_address = "127.0.0.1",
49 .host_specified = false,
50 .server_port = 0,
51
52 .protocol = IPPROTO_TCP,
53 .service = "TCP",
54 .send = NULL,
55 .quit = NULL,
56 .server_expect = NULL,
57 .server_expect_count = 0,
58 .use_tls = false,
59#ifdef HAVE_SSL
60 .sni = NULL,
61 .sni_specified = false,
62 .check_cert = false,
63 .days_till_exp_warn = 0,
64 .days_till_exp_crit = 0,
65#endif // HAVE_SSL
66 .match_flags = NP_MATCH_EXACT,
67 .expect_mismatch_state = STATE_WARNING,
68 .delay = 0,
69
70 .warning_time_set = false,
71 .warning_time = 0,
72 .critical_time_set = false,
73 .critical_time = 0,
74
75 .econn_refuse_state = STATE_CRITICAL,
76
77 .maxbytes = 0,
78
79 .hide_output = false,
80
81 .output_format_set = false,
82 };
83 return result;
84}
diff --git a/plugins/check_time.c b/plugins/check_time.c
index d1f50683..fc9ba3f9 100644
--- a/plugins/check_time.c
+++ b/plugins/check_time.c
@@ -28,6 +28,7 @@
28 * 28 *
29 *****************************************************************************/ 29 *****************************************************************************/
30 30
31#include "states.h"
31const char *progname = "check_time"; 32const char *progname = "check_time";
32const char *copyright = "1999-2024"; 33const char *copyright = "1999-2024";
33const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
@@ -35,28 +36,15 @@ const char *email = "devel@monitoring-plugins.org";
35#include "common.h" 36#include "common.h"
36#include "netutils.h" 37#include "netutils.h"
37#include "utils.h" 38#include "utils.h"
38 39#include "check_time.d/config.h"
39enum {
40 TIME_PORT = 37
41};
42 40
43#define UNIX_EPOCH 2208988800UL 41#define UNIX_EPOCH 2208988800UL
44 42
45static uint32_t raw_server_time; 43typedef struct {
46static unsigned long server_time, diff_time; 44 int errorcode;
47static int warning_time = 0; 45 check_time_config config;
48static bool check_warning_time = false; 46} check_time_config_wrapper;
49static int critical_time = 0; 47static check_time_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50static bool check_critical_time = false;
51static unsigned long warning_diff = 0;
52static bool check_warning_diff = false;
53static unsigned long critical_diff = 0;
54static bool check_critical_diff = false;
55static int server_port = TIME_PORT;
56static char *server_address = NULL;
57static bool use_udp = false;
58
59static int process_arguments(int, char **);
60static void print_help(void); 48static void print_help(void);
61void print_usage(void); 49void print_usage(void);
62 50
@@ -68,8 +56,12 @@ int main(int argc, char **argv) {
68 /* Parse extra opts if any */ 56 /* Parse extra opts if any */
69 argv = np_extra_opts(&argc, argv, progname); 57 argv = np_extra_opts(&argc, argv, progname);
70 58
71 if (process_arguments(argc, argv) == ERROR) 59 check_time_config_wrapper tmp_config = process_arguments(argc, argv);
60 if (tmp_config.errorcode == ERROR) {
72 usage4(_("Could not parse arguments")); 61 usage4(_("Could not parse arguments"));
62 }
63
64 const check_time_config config = tmp_config.config;
73 65
74 /* initialize alarm signal handling */ 66 /* initialize alarm signal handling */
75 signal(SIGALRM, socket_timeout_alarm_handler); 67 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -79,37 +71,42 @@ int main(int argc, char **argv) {
79 time(&start_time); 71 time(&start_time);
80 72
81 int socket; 73 int socket;
82 int result = STATE_UNKNOWN; 74 mp_state_enum result = STATE_UNKNOWN;
83 /* try to connect to the host at the given port number */ 75 /* try to connect to the host at the given port number */
84 if (use_udp) { 76 if (config.use_udp) {
85 result = my_udp_connect(server_address, server_port, &socket); 77 result = my_udp_connect(config.server_address, config.server_port, &socket);
86 } else { 78 } else {
87 result = my_tcp_connect(server_address, server_port, &socket); 79 result = my_tcp_connect(config.server_address, config.server_port, &socket);
88 } 80 }
89 81
90 if (result != STATE_OK) { 82 if (result != STATE_OK) {
91 if (check_critical_time) 83 if (config.check_critical_time) {
92 result = STATE_CRITICAL; 84 result = STATE_CRITICAL;
93 else if (check_warning_time) 85 } else if (config.check_warning_time) {
94 result = STATE_WARNING; 86 result = STATE_WARNING;
95 else 87 } else {
96 result = STATE_UNKNOWN; 88 result = STATE_UNKNOWN;
97 die(result, _("TIME UNKNOWN - could not connect to server %s, port %d\n"), server_address, server_port); 89 }
90 die(result, _("TIME UNKNOWN - could not connect to server %s, port %d\n"),
91 config.server_address, config.server_port);
98 } 92 }
99 93
100 if (use_udp) { 94 if (config.use_udp) {
101 if (send(socket, "", 0, 0) < 0) { 95 if (send(socket, "", 0, 0) < 0) {
102 if (check_critical_time) 96 if (config.check_critical_time) {
103 result = STATE_CRITICAL; 97 result = STATE_CRITICAL;
104 else if (check_warning_time) 98 } else if (config.check_warning_time) {
105 result = STATE_WARNING; 99 result = STATE_WARNING;
106 else 100 } else {
107 result = STATE_UNKNOWN; 101 result = STATE_UNKNOWN;
108 die(result, _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"), server_address, server_port); 102 }
103 die(result, _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"),
104 config.server_address, config.server_port);
109 } 105 }
110 } 106 }
111 107
112 /* watch for the connection string */ 108 /* watch for the connection string */
109 uint32_t raw_server_time;
113 result = recv(socket, (void *)&raw_server_time, sizeof(raw_server_time), 0); 110 result = recv(socket, (void *)&raw_server_time, sizeof(raw_server_time), 0);
114 111
115 /* close the connection */ 112 /* close the connection */
@@ -121,48 +118,59 @@ int main(int argc, char **argv) {
121 118
122 /* return a WARNING status if we couldn't read any data */ 119 /* return a WARNING status if we couldn't read any data */
123 if (result <= 0) { 120 if (result <= 0) {
124 if (check_critical_time) 121 if (config.check_critical_time) {
125 result = STATE_CRITICAL; 122 result = STATE_CRITICAL;
126 else if (check_warning_time) 123 } else if (config.check_warning_time) {
127 result = STATE_WARNING; 124 result = STATE_WARNING;
128 else 125 } else {
129 result = STATE_UNKNOWN; 126 result = STATE_UNKNOWN;
130 die(result, _("TIME UNKNOWN - no data received from server %s, port %d\n"), server_address, server_port); 127 }
128 die(result, _("TIME UNKNOWN - no data received from server %s, port %d\n"),
129 config.server_address, config.server_port);
131 } 130 }
132 131
133 result = STATE_OK; 132 result = STATE_OK;
134 133
135 time_t conntime = (end_time - start_time); 134 time_t conntime = (end_time - start_time);
136 if (check_critical_time && conntime > critical_time) 135 if (config.check_critical_time && conntime > config.critical_time) {
137 result = STATE_CRITICAL; 136 result = STATE_CRITICAL;
138 else if (check_warning_time && conntime > warning_time) 137 } else if (config.check_warning_time && conntime > config.warning_time) {
139 result = STATE_WARNING; 138 result = STATE_WARNING;
139 }
140 140
141 if (result != STATE_OK) 141 if (result != STATE_OK) {
142 die(result, _("TIME %s - %d second response time|%s\n"), state_text(result), (int)conntime, 142 die(result, _("TIME %s - %d second response time|%s\n"), state_text(result), (int)conntime,
143 perfdata("time", (long)conntime, "s", check_warning_time, (long)warning_time, check_critical_time, (long)critical_time, true, 0, 143 perfdata("time", (long)conntime, "s", config.check_warning_time,
144 false, 0)); 144 (long)config.warning_time, config.check_critical_time,
145 (long)config.critical_time, true, 0, false, 0));
146 }
145 147
148 unsigned long server_time;
149 unsigned long diff_time;
146 server_time = ntohl(raw_server_time) - UNIX_EPOCH; 150 server_time = ntohl(raw_server_time) - UNIX_EPOCH;
147 if (server_time > (unsigned long)end_time) 151 if (server_time > (unsigned long)end_time) {
148 diff_time = server_time - (unsigned long)end_time; 152 diff_time = server_time - (unsigned long)end_time;
149 else 153 } else {
150 diff_time = (unsigned long)end_time - server_time; 154 diff_time = (unsigned long)end_time - server_time;
155 }
151 156
152 if (check_critical_diff && diff_time > critical_diff) 157 if (config.check_critical_diff && diff_time > config.critical_diff) {
153 result = STATE_CRITICAL; 158 result = STATE_CRITICAL;
154 else if (check_warning_diff && diff_time > warning_diff) 159 } else if (config.check_warning_diff && diff_time > config.warning_diff) {
155 result = STATE_WARNING; 160 result = STATE_WARNING;
161 }
156 162
157 printf(_("TIME %s - %lu second time difference|%s %s\n"), state_text(result), diff_time, 163 printf(_("TIME %s - %lu second time difference|%s %s\n"), state_text(result), diff_time,
158 perfdata("time", (long)conntime, "s", check_warning_time, (long)warning_time, check_critical_time, (long)critical_time, true, 0, 164 perfdata("time", (long)conntime, "s", config.check_warning_time,
159 false, 0), 165 (long)config.warning_time, config.check_critical_time,
160 perfdata("offset", diff_time, "s", check_warning_diff, warning_diff, check_critical_diff, critical_diff, true, 0, false, 0)); 166 (long)config.critical_time, true, 0, false, 0),
167 perfdata("offset", diff_time, "s", config.check_warning_diff, config.warning_diff,
168 config.check_critical_diff, config.critical_diff, true, 0, false, 0));
161 return result; 169 return result;
162} 170}
163 171
164/* process command-line arguments */ 172/* process command-line arguments */
165int process_arguments(int argc, char **argv) { 173check_time_config_wrapper process_arguments(int argc, char **argv) {
166 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 174 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
167 {"warning-variance", required_argument, 0, 'w'}, 175 {"warning-variance", required_argument, 0, 'w'},
168 {"critical-variance", required_argument, 0, 'c'}, 176 {"critical-variance", required_argument, 0, 'c'},
@@ -175,29 +183,37 @@ int process_arguments(int argc, char **argv) {
175 {"help", no_argument, 0, 'h'}, 183 {"help", no_argument, 0, 'h'},
176 {0, 0, 0, 0}}; 184 {0, 0, 0, 0}};
177 185
178 if (argc < 2) 186 if (argc < 2) {
179 usage("\n"); 187 usage("\n");
188 }
180 189
181 for (int i = 1; i < argc; i++) { 190 for (int i = 1; i < argc; i++) {
182 if (strcmp("-to", argv[i]) == 0) 191 if (strcmp("-to", argv[i]) == 0) {
183 strcpy(argv[i], "-t"); 192 strcpy(argv[i], "-t");
184 else if (strcmp("-wd", argv[i]) == 0) 193 } else if (strcmp("-wd", argv[i]) == 0) {
185 strcpy(argv[i], "-w"); 194 strcpy(argv[i], "-w");
186 else if (strcmp("-cd", argv[i]) == 0) 195 } else if (strcmp("-cd", argv[i]) == 0) {
187 strcpy(argv[i], "-c"); 196 strcpy(argv[i], "-c");
188 else if (strcmp("-wt", argv[i]) == 0) 197 } else if (strcmp("-wt", argv[i]) == 0) {
189 strcpy(argv[i], "-W"); 198 strcpy(argv[i], "-W");
190 else if (strcmp("-ct", argv[i]) == 0) 199 } else if (strcmp("-ct", argv[i]) == 0) {
191 strcpy(argv[i], "-C"); 200 strcpy(argv[i], "-C");
201 }
192 } 202 }
193 203
204 check_time_config_wrapper result = {
205 .errorcode = OK,
206 .config = check_time_config_init(),
207 };
208
194 int option_char; 209 int option_char;
195 while (true) { 210 while (true) {
196 int option = 0; 211 int option = 0;
197 option_char = getopt_long(argc, argv, "hVH:w:c:W:C:p:t:u", longopts, &option); 212 option_char = getopt_long(argc, argv, "hVH:w:c:W:C:p:t:u", longopts, &option);
198 213
199 if (option_char == -1 || option_char == EOF) 214 if (option_char == -1 || option_char == EOF) {
200 break; 215 break;
216 }
201 217
202 switch (option_char) { 218 switch (option_char) {
203 case '?': /* print short usage statement if args not parsable */ 219 case '?': /* print short usage statement if args not parsable */
@@ -209,18 +225,20 @@ int process_arguments(int argc, char **argv) {
209 print_revision(progname, NP_VERSION); 225 print_revision(progname, NP_VERSION);
210 exit(STATE_UNKNOWN); 226 exit(STATE_UNKNOWN);
211 case 'H': /* hostname */ 227 case 'H': /* hostname */
212 if (!is_host(optarg)) 228 if (!is_host(optarg)) {
213 usage2(_("Invalid hostname/address"), optarg); 229 usage2(_("Invalid hostname/address"), optarg);
214 server_address = optarg; 230 }
231 result.config.server_address = optarg;
215 break; 232 break;
216 case 'w': /* warning-variance */ 233 case 'w': /* warning-variance */
217 if (is_intnonneg(optarg)) { 234 if (is_intnonneg(optarg)) {
218 warning_diff = strtoul(optarg, NULL, 10); 235 result.config.warning_diff = strtoul(optarg, NULL, 10);
219 check_warning_diff = true; 236 result.config.check_warning_diff = true;
220 } else if (strspn(optarg, "0123456789:,") > 0) { 237 } else if (strspn(optarg, "0123456789:,") > 0) {
221 if (sscanf(optarg, "%lu%*[:,]%d", &warning_diff, &warning_time) == 2) { 238 if (sscanf(optarg, "%lu%*[:,]%d", &result.config.warning_diff,
222 check_warning_diff = true; 239 &result.config.warning_time) == 2) {
223 check_warning_time = true; 240 result.config.check_warning_diff = true;
241 result.config.check_warning_time = true;
224 } else { 242 } else {
225 usage4(_("Warning thresholds must be a positive integer")); 243 usage4(_("Warning thresholds must be a positive integer"));
226 } 244 }
@@ -230,12 +248,13 @@ int process_arguments(int argc, char **argv) {
230 break; 248 break;
231 case 'c': /* critical-variance */ 249 case 'c': /* critical-variance */
232 if (is_intnonneg(optarg)) { 250 if (is_intnonneg(optarg)) {
233 critical_diff = strtoul(optarg, NULL, 10); 251 result.config.critical_diff = strtoul(optarg, NULL, 10);
234 check_critical_diff = true; 252 result.config.check_critical_diff = true;
235 } else if (strspn(optarg, "0123456789:,") > 0) { 253 } else if (strspn(optarg, "0123456789:,") > 0) {
236 if (sscanf(optarg, "%lu%*[:,]%d", &critical_diff, &critical_time) == 2) { 254 if (sscanf(optarg, "%lu%*[:,]%d", &result.config.critical_diff,
237 check_critical_diff = true; 255 &result.config.critical_time) == 2) {
238 check_critical_time = true; 256 result.config.check_critical_diff = true;
257 result.config.check_critical_time = true;
239 } else { 258 } else {
240 usage4(_("Critical thresholds must be a positive integer")); 259 usage4(_("Critical thresholds must be a positive integer"));
241 } 260 }
@@ -244,48 +263,53 @@ int process_arguments(int argc, char **argv) {
244 } 263 }
245 break; 264 break;
246 case 'W': /* warning-connect */ 265 case 'W': /* warning-connect */
247 if (!is_intnonneg(optarg)) 266 if (!is_intnonneg(optarg)) {
248 usage4(_("Warning threshold must be a positive integer")); 267 usage4(_("Warning threshold must be a positive integer"));
249 else 268 } else {
250 warning_time = atoi(optarg); 269 result.config.warning_time = atoi(optarg);
251 check_warning_time = true; 270 }
271 result.config.check_warning_time = true;
252 break; 272 break;
253 case 'C': /* critical-connect */ 273 case 'C': /* critical-connect */
254 if (!is_intnonneg(optarg)) 274 if (!is_intnonneg(optarg)) {
255 usage4(_("Critical threshold must be a positive integer")); 275 usage4(_("Critical threshold must be a positive integer"));
256 else 276 } else {
257 critical_time = atoi(optarg); 277 result.config.critical_time = atoi(optarg);
258 check_critical_time = true; 278 }
279 result.config.check_critical_time = true;
259 break; 280 break;
260 case 'p': /* port */ 281 case 'p': /* port */
261 if (!is_intnonneg(optarg)) 282 if (!is_intnonneg(optarg)) {
262 usage4(_("Port must be a positive integer")); 283 usage4(_("Port must be a positive integer"));
263 else 284 } else {
264 server_port = atoi(optarg); 285 result.config.server_port = atoi(optarg);
286 }
265 break; 287 break;
266 case 't': /* timeout */ 288 case 't': /* timeout */
267 if (!is_intnonneg(optarg)) 289 if (!is_intnonneg(optarg)) {
268 usage2(_("Timeout interval must be a positive integer"), optarg); 290 usage2(_("Timeout interval must be a positive integer"), optarg);
269 else 291 } else {
270 socket_timeout = atoi(optarg); 292 socket_timeout = atoi(optarg);
293 }
271 break; 294 break;
272 case 'u': /* udp */ 295 case 'u': /* udp */
273 use_udp = true; 296 result.config.use_udp = true;
274 } 297 }
275 } 298 }
276 299
277 option_char = optind; 300 option_char = optind;
278 if (server_address == NULL) { 301 if (result.config.server_address == NULL) {
279 if (argc > option_char) { 302 if (argc > option_char) {
280 if (!is_host(argv[option_char])) 303 if (!is_host(argv[option_char])) {
281 usage2(_("Invalid hostname/address"), optarg); 304 usage2(_("Invalid hostname/address"), optarg);
282 server_address = argv[option_char]; 305 }
306 result.config.server_address = argv[option_char];
283 } else { 307 } else {
284 usage4(_("Hostname was not supplied")); 308 usage4(_("Hostname was not supplied"));
285 } 309 }
286 } 310 }
287 311
288 return OK; 312 return result;
289} 313}
290 314
291void print_help(void) { 315void print_help(void) {
diff --git a/plugins/check_time.d/config.h b/plugins/check_time.d/config.h
new file mode 100644
index 00000000..09bd7c45
--- /dev/null
+++ b/plugins/check_time.d/config.h
@@ -0,0 +1,42 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6enum {
7 TIME_PORT = 37
8};
9
10typedef struct {
11 char *server_address;
12 int server_port;
13 bool use_udp;
14
15 int warning_time;
16 bool check_warning_time;
17 int critical_time;
18 bool check_critical_time;
19 unsigned long warning_diff;
20 bool check_warning_diff;
21 unsigned long critical_diff;
22 bool check_critical_diff;
23} check_time_config;
24
25check_time_config check_time_config_init() {
26 check_time_config tmp = {
27 .server_address = NULL,
28 .server_port = TIME_PORT,
29 .use_udp = false,
30
31 .warning_time = 0,
32 .check_warning_time = false,
33 .critical_time = 0,
34 .check_critical_time = false,
35
36 .warning_diff = 0,
37 .check_warning_diff = false,
38 .critical_diff = 0,
39 .check_critical_diff = false,
40 };
41 return tmp;
42}
diff --git a/plugins/check_ups.c b/plugins/check_ups.c
index 526a29df..54decce3 100644
--- a/plugins/check_ups.c
+++ b/plugins/check_ups.c
@@ -39,69 +39,29 @@ const char *email = "devel@monitoring-plugins.org";
39#include "common.h" 39#include "common.h"
40#include "netutils.h" 40#include "netutils.h"
41#include "utils.h" 41#include "utils.h"
42 42#include "check_ups.d/config.h"
43enum { 43#include "states.h"
44 PORT = 3493
45};
46
47#define UPS_NONE 0 /* no supported options */
48#define UPS_UTILITY 1 /* supports utility line */
49#define UPS_BATTPCT 2 /* supports percent battery remaining */
50#define UPS_STATUS 4 /* supports UPS status */
51#define UPS_TEMP 8 /* supports UPS temperature */
52#define UPS_LOADPCT 16 /* supports load percent */
53#define UPS_REALPOWER 32 /* supports real power */
54
55#define UPSSTATUS_NONE 0
56#define UPSSTATUS_OFF 1
57#define UPSSTATUS_OL 2
58#define UPSSTATUS_OB 4
59#define UPSSTATUS_LB 8
60#define UPSSTATUS_CAL 16
61#define UPSSTATUS_RB 32 /*Replace Battery */
62#define UPSSTATUS_BYPASS 64
63#define UPSSTATUS_OVER 128
64#define UPSSTATUS_TRIM 256
65#define UPSSTATUS_BOOST 512
66#define UPSSTATUS_CHRG 1024
67#define UPSSTATUS_DISCHRG 2048
68#define UPSSTATUS_UNKNOWN 4096
69#define UPSSTATUS_ALARM 8192
70 44
71enum { 45enum {
72 NOSUCHVAR = ERROR - 1 46 NOSUCHVAR = ERROR - 1
73}; 47};
74 48
75typedef struct ups_config {
76 unsigned int server_port;
77 char *server_address;
78 char *ups_name;
79 double warning_value;
80 double critical_value;
81 bool check_warn;
82 bool check_crit;
83 int check_variable;
84 int status;
85 bool temp_output_c;
86} ups_config;
87
88ups_config ups_config_init(void) {
89 ups_config tmp = {0};
90 tmp.server_port = PORT;
91 tmp.server_address = NULL;
92 tmp.ups_name = NULL;
93 tmp.check_variable = UPS_NONE;
94 tmp.status = UPSSTATUS_NONE;
95
96 return tmp;
97}
98
99// Forward declarations 49// Forward declarations
100static int determine_status(ups_config * /*config*/, int *supported_options); 50typedef struct {
101static int get_ups_variable(const char * /*varname*/, char * /*buf*/, ups_config config); 51 int errorcode;
52 int ups_status;
53 int supported_options;
54} determine_status_result;
55static determine_status_result determine_status(check_ups_config /*config*/);
56static int get_ups_variable(const char * /*varname*/, char * /*buf*/, check_ups_config config);
57
58typedef struct {
59 int errorcode;
60 check_ups_config config;
61} check_ups_config_wrapper;
62static check_ups_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
63static check_ups_config_wrapper validate_arguments(check_ups_config_wrapper /*config_wrapper*/);
102 64
103static int process_arguments(int /*argc*/, char ** /*argv*/, ups_config * /*config*/);
104static int validate_arguments(ups_config /*config*/);
105static void print_help(void); 65static void print_help(void);
106void print_usage(void); 66void print_usage(void);
107 67
@@ -109,28 +69,16 @@ int main(int argc, char **argv) {
109 setlocale(LC_ALL, ""); 69 setlocale(LC_ALL, "");
110 bindtextdomain(PACKAGE, LOCALEDIR); 70 bindtextdomain(PACKAGE, LOCALEDIR);
111 textdomain(PACKAGE); 71 textdomain(PACKAGE);
112
113 char *ups_status;
114 ups_status = strdup("N/A");
115
116 char *data;
117 data = strdup("");
118
119 char *message;
120 message = strdup("");
121
122 // Exit result
123 int result = STATE_UNKNOWN;
124
125 /* Parse extra opts if any */ 72 /* Parse extra opts if any */
126 argv = np_extra_opts(&argc, argv, progname); 73 argv = np_extra_opts(&argc, argv, progname);
127 74
128 // Config from commandline 75 check_ups_config_wrapper tmp_config = process_arguments(argc, argv);
129 ups_config config = ups_config_init();
130 76
131 if (process_arguments(argc, argv, &config) == ERROR) { 77 if (tmp_config.errorcode == ERROR) {
132 usage4(_("Could not parse arguments")); 78 usage4(_("Could not parse arguments"));
133 } 79 }
80 // Config from commandline
81 check_ups_config config = tmp_config.config;
134 82
135 /* initialize alarm signal handling */ 83 /* initialize alarm signal handling */
136 signal(SIGALRM, socket_timeout_alarm_handler); 84 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -138,71 +86,76 @@ int main(int argc, char **argv) {
138 /* set socket timeout */ 86 /* set socket timeout */
139 alarm(socket_timeout); 87 alarm(socket_timeout);
140 88
141 int supported_options = UPS_NONE;
142
143 /* get the ups status if possible */ 89 /* get the ups status if possible */
144 if (determine_status(&config, &supported_options) != OK) { 90 determine_status_result query_result = determine_status(config);
91 if (query_result.errorcode != OK) {
145 return STATE_CRITICAL; 92 return STATE_CRITICAL;
146 } 93 }
147 94
148 if (supported_options & UPS_STATUS) { 95 int ups_status_flags = query_result.ups_status;
96 int supported_options = query_result.supported_options;
149 97
150 ups_status = strdup(""); 98 // Exit result
99 mp_state_enum result = STATE_UNKNOWN;
100 char *message = NULL;
151 101
102 if (supported_options & UPS_STATUS) {
103 char *ups_status = strdup("");
152 result = STATE_OK; 104 result = STATE_OK;
153 105
154 if (config.status & UPSSTATUS_OFF) { 106 if (ups_status_flags & UPSSTATUS_OFF) {
155 xasprintf(&ups_status, "Off"); 107 xasprintf(&ups_status, "Off");
156 result = STATE_CRITICAL; 108 result = STATE_CRITICAL;
157 } else if ((config.status & (UPSSTATUS_OB | UPSSTATUS_LB)) == (UPSSTATUS_OB | UPSSTATUS_LB)) { 109 } else if ((ups_status_flags & (UPSSTATUS_OB | UPSSTATUS_LB)) ==
110 (UPSSTATUS_OB | UPSSTATUS_LB)) {
158 xasprintf(&ups_status, _("On Battery, Low Battery")); 111 xasprintf(&ups_status, _("On Battery, Low Battery"));
159 result = STATE_CRITICAL; 112 result = STATE_CRITICAL;
160 } else { 113 } else {
161 if (config.status & UPSSTATUS_OL) { 114 if (ups_status_flags & UPSSTATUS_OL) {
162 xasprintf(&ups_status, "%s%s", ups_status, _("Online")); 115 xasprintf(&ups_status, "%s%s", ups_status, _("Online"));
163 } 116 }
164 if (config.status & UPSSTATUS_OB) { 117 if (ups_status_flags & UPSSTATUS_OB) {
165 xasprintf(&ups_status, "%s%s", ups_status, _("On Battery")); 118 xasprintf(&ups_status, "%s%s", ups_status, _("On Battery"));
166 result = max_state(result, STATE_WARNING); 119 result = max_state(result, STATE_WARNING);
167 } 120 }
168 if (config.status & UPSSTATUS_LB) { 121 if (ups_status_flags & UPSSTATUS_LB) {
169 xasprintf(&ups_status, "%s%s", ups_status, _(", Low Battery")); 122 xasprintf(&ups_status, "%s%s", ups_status, _(", Low Battery"));
170 result = max_state(result, STATE_WARNING); 123 result = max_state(result, STATE_WARNING);
171 } 124 }
172 if (config.status & UPSSTATUS_CAL) { 125 if (ups_status_flags & UPSSTATUS_CAL) {
173 xasprintf(&ups_status, "%s%s", ups_status, _(", Calibrating")); 126 xasprintf(&ups_status, "%s%s", ups_status, _(", Calibrating"));
174 } 127 }
175 if (config.status & UPSSTATUS_RB) { 128 if (ups_status_flags & UPSSTATUS_RB) {
176 xasprintf(&ups_status, "%s%s", ups_status, _(", Replace Battery")); 129 xasprintf(&ups_status, "%s%s", ups_status, _(", Replace Battery"));
177 result = max_state(result, STATE_WARNING); 130 result = max_state(result, STATE_WARNING);
178 } 131 }
179 if (config.status & UPSSTATUS_BYPASS) { 132 if (ups_status_flags & UPSSTATUS_BYPASS) {
180 xasprintf(&ups_status, "%s%s", ups_status, _(", On Bypass")); 133 xasprintf(&ups_status, "%s%s", ups_status, _(", On Bypass"));
181 // Bypassing the battery is likely a bad thing 134 // Bypassing the battery is likely a bad thing
182 result = STATE_CRITICAL; 135 result = STATE_CRITICAL;
183 } 136 }
184 if (config.status & UPSSTATUS_OVER) { 137 if (ups_status_flags & UPSSTATUS_OVER) {
185 xasprintf(&ups_status, "%s%s", ups_status, _(", Overload")); 138 xasprintf(&ups_status, "%s%s", ups_status, _(", Overload"));
186 result = max_state(result, STATE_WARNING); 139 result = max_state(result, STATE_WARNING);
187 } 140 }
188 if (config.status & UPSSTATUS_TRIM) { 141 if (ups_status_flags & UPSSTATUS_TRIM) {
189 xasprintf(&ups_status, "%s%s", ups_status, _(", Trimming")); 142 xasprintf(&ups_status, "%s%s", ups_status, _(", Trimming"));
190 } 143 }
191 if (config.status & UPSSTATUS_BOOST) { 144 if (ups_status_flags & UPSSTATUS_BOOST) {
192 xasprintf(&ups_status, "%s%s", ups_status, _(", Boosting")); 145 xasprintf(&ups_status, "%s%s", ups_status, _(", Boosting"));
193 } 146 }
194 if (config.status & UPSSTATUS_CHRG) { 147 if (ups_status_flags & UPSSTATUS_CHRG) {
195 xasprintf(&ups_status, "%s%s", ups_status, _(", Charging")); 148 xasprintf(&ups_status, "%s%s", ups_status, _(", Charging"));
196 } 149 }
197 if (config.status & UPSSTATUS_DISCHRG) { 150 if (ups_status_flags & UPSSTATUS_DISCHRG) {
198 xasprintf(&ups_status, "%s%s", ups_status, _(", Discharging")); 151 xasprintf(&ups_status, "%s%s", ups_status, _(", Discharging"));
199 result = max_state(result, STATE_WARNING); 152 result = max_state(result, STATE_WARNING);
200 } 153 }
201 if (config.status & UPSSTATUS_ALARM) { 154 if (ups_status_flags & UPSSTATUS_ALARM) {
202 xasprintf(&ups_status, "%s%s", ups_status, _(", ALARM")); 155 xasprintf(&ups_status, "%s%s", ups_status, _(", ALARM"));
203 result = STATE_CRITICAL; 156 result = STATE_CRITICAL;
204 } 157 }
205 if (config.status & UPSSTATUS_UNKNOWN) { 158 if (ups_status_flags & UPSSTATUS_UNKNOWN) {
206 xasprintf(&ups_status, "%s%s", ups_status, _(", Unknown")); 159 xasprintf(&ups_status, "%s%s", ups_status, _(", Unknown"));
207 } 160 }
208 } 161 }
@@ -211,7 +164,7 @@ int main(int argc, char **argv) {
211 164
212 int res; 165 int res;
213 char temp_buffer[MAX_INPUT_BUFFER]; 166 char temp_buffer[MAX_INPUT_BUFFER];
214 167 char *performance_data = strdup("");
215 /* get the ups utility voltage if possible */ 168 /* get the ups utility voltage if possible */
216 res = get_ups_variable("input.voltage", temp_buffer, config); 169 res = get_ups_variable("input.voltage", temp_buffer, config);
217 if (res == NOSUCHVAR) { 170 if (res == NOSUCHVAR) {
@@ -239,11 +192,15 @@ int main(int argc, char **argv) {
239 } else if (config.check_warn && ups_utility_deviation >= config.warning_value) { 192 } else if (config.check_warn && ups_utility_deviation >= config.warning_value) {
240 result = max_state(result, STATE_WARNING); 193 result = max_state(result, STATE_WARNING);
241 } 194 }
242 xasprintf(&data, "%s", 195 xasprintf(&performance_data, "%s",
243 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", config.check_warn, (long)(1000 * config.warning_value), 196 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV",
244 config.check_crit, (long)(1000 * config.critical_value), true, 0, false, 0)); 197 config.check_warn, (long)(1000 * config.warning_value),
198 config.check_crit, (long)(1000 * config.critical_value), true, 0,
199 false, 0));
245 } else { 200 } else {
246 xasprintf(&data, "%s", perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", false, 0, false, 0, true, 0, false, 0)); 201 xasprintf(&performance_data, "%s",
202 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", false, 0, false,
203 0, true, 0, false, 0));
247 } 204 }
248 } 205 }
249 206
@@ -266,11 +223,14 @@ int main(int argc, char **argv) {
266 } else if (config.check_warn && ups_battery_percent <= config.warning_value) { 223 } else if (config.check_warn && ups_battery_percent <= config.warning_value) {
267 result = max_state(result, STATE_WARNING); 224 result = max_state(result, STATE_WARNING);
268 } 225 }
269 xasprintf(&data, "%s %s", data, 226 xasprintf(&performance_data, "%s %s", performance_data,
270 perfdata("battery", (long)ups_battery_percent, "%", config.check_warn, (long)(config.warning_value), 227 perfdata("battery", (long)ups_battery_percent, "%", config.check_warn,
271 config.check_crit, (long)(config.critical_value), true, 0, true, 100)); 228 (long)(config.warning_value), config.check_crit,
229 (long)(config.critical_value), true, 0, true, 100));
272 } else { 230 } else {
273 xasprintf(&data, "%s %s", data, perfdata("battery", (long)ups_battery_percent, "%", false, 0, false, 0, true, 0, true, 100)); 231 xasprintf(&performance_data, "%s %s", performance_data,
232 perfdata("battery", (long)ups_battery_percent, "%", false, 0, false, 0, true,
233 0, true, 100));
274 } 234 }
275 } 235 }
276 236
@@ -293,11 +253,14 @@ int main(int argc, char **argv) {
293 } else if (config.check_warn && ups_load_percent >= config.warning_value) { 253 } else if (config.check_warn && ups_load_percent >= config.warning_value) {
294 result = max_state(result, STATE_WARNING); 254 result = max_state(result, STATE_WARNING);
295 } 255 }
296 xasprintf(&data, "%s %s", data, 256 xasprintf(&performance_data, "%s %s", performance_data,
297 perfdata("load", (long)ups_load_percent, "%", config.check_warn, (long)(config.warning_value), config.check_crit, 257 perfdata("load", (long)ups_load_percent, "%", config.check_warn,
258 (long)(config.warning_value), config.check_crit,
298 (long)(config.critical_value), true, 0, true, 100)); 259 (long)(config.critical_value), true, 0, true, 100));
299 } else { 260 } else {
300 xasprintf(&data, "%s %s", data, perfdata("load", (long)ups_load_percent, "%", false, 0, false, 0, true, 0, true, 100)); 261 xasprintf(&performance_data, "%s %s", performance_data,
262 perfdata("load", (long)ups_load_percent, "%", false, 0, false, 0, true, 0,
263 true, 100));
301 } 264 }
302 } 265 }
303 266
@@ -329,11 +292,14 @@ int main(int argc, char **argv) {
329 } else if (config.check_warn && ups_temperature >= config.warning_value) { 292 } else if (config.check_warn && ups_temperature >= config.warning_value) {
330 result = max_state(result, STATE_WARNING); 293 result = max_state(result, STATE_WARNING);
331 } 294 }
332 xasprintf(&data, "%s %s", data, 295 xasprintf(&performance_data, "%s %s", performance_data,
333 perfdata("temp", (long)ups_temperature, tunits, config.check_warn, (long)(config.warning_value), config.check_crit, 296 perfdata("temp", (long)ups_temperature, tunits, config.check_warn,
297 (long)(config.warning_value), config.check_crit,
334 (long)(config.critical_value), true, 0, false, 0)); 298 (long)(config.critical_value), true, 0, false, 0));
335 } else { 299 } else {
336 xasprintf(&data, "%s %s", data, perfdata("temp", (long)ups_temperature, tunits, false, 0, false, 0, true, 0, false, 0)); 300 xasprintf(&performance_data, "%s %s", performance_data,
301 perfdata("temp", (long)ups_temperature, tunits, false, 0, false, 0, true, 0,
302 false, 0));
337 } 303 }
338 } 304 }
339 305
@@ -355,11 +321,14 @@ int main(int argc, char **argv) {
355 } else if (config.check_warn && ups_realpower >= config.warning_value) { 321 } else if (config.check_warn && ups_realpower >= config.warning_value) {
356 result = max_state(result, STATE_WARNING); 322 result = max_state(result, STATE_WARNING);
357 } 323 }
358 xasprintf(&data, "%s %s", data, 324 xasprintf(&performance_data, "%s %s", performance_data,
359 perfdata("realpower", (long)ups_realpower, "W", config.check_warn, (long)(config.warning_value), config.check_crit, 325 perfdata("realpower", (long)ups_realpower, "W", config.check_warn,
326 (long)(config.warning_value), config.check_crit,
360 (long)(config.critical_value), true, 0, false, 0)); 327 (long)(config.critical_value), true, 0, false, 0));
361 } else { 328 } else {
362 xasprintf(&data, "%s %s", data, perfdata("realpower", (long)ups_realpower, "W", false, 0, false, 0, true, 0, false, 0)); 329 xasprintf(&performance_data, "%s %s", performance_data,
330 perfdata("realpower", (long)ups_realpower, "W", false, 0, false, 0, true, 0,
331 false, 0));
363 } 332 }
364 } 333 }
365 334
@@ -373,71 +342,79 @@ int main(int argc, char **argv) {
373 /* reset timeout */ 342 /* reset timeout */
374 alarm(0); 343 alarm(0);
375 344
376 printf("UPS %s - %s|%s\n", state_text(result), message, data); 345 printf("UPS %s - %s|%s\n", state_text(result), message, performance_data);
377 return result; 346 exit(result);
378} 347}
379 348
380/* determines what options are supported by the UPS */ 349/* determines what options are supported by the UPS */
381int determine_status(ups_config *config, int *supported_options) { 350determine_status_result determine_status(const check_ups_config config) {
382 char recv_buffer[MAX_INPUT_BUFFER];
383 351
384 int res = get_ups_variable("ups.status", recv_buffer, *config); 352 determine_status_result result = {
353 .errorcode = OK,
354 .ups_status = UPSSTATUS_NONE,
355 .supported_options = 0,
356 };
357
358 char recv_buffer[MAX_INPUT_BUFFER];
359 int res = get_ups_variable("ups.status", recv_buffer, config);
385 if (res == NOSUCHVAR) { 360 if (res == NOSUCHVAR) {
386 return OK; 361 return result;
387 } 362 }
388 363
389 if (res != STATE_OK) { 364 if (res != STATE_OK) {
390 printf("%s\n", _("Invalid response received from host")); 365 printf("%s\n", _("Invalid response received from host"));
391 return ERROR; 366 result.errorcode = ERROR;
367 return result;
392 } 368 }
393 369
394 *supported_options |= UPS_STATUS; 370 result.supported_options |= UPS_STATUS;
395 371
396 char temp_buffer[MAX_INPUT_BUFFER]; 372 char temp_buffer[MAX_INPUT_BUFFER];
397 373
398 strcpy(temp_buffer, recv_buffer); 374 strcpy(temp_buffer, recv_buffer);
399 for (char *ptr = (char *)strtok(temp_buffer, " "); ptr != NULL; ptr = (char *)strtok(NULL, " ")) { 375 for (char *ptr = strtok(temp_buffer, " "); ptr != NULL; ptr = strtok(NULL, " ")) {
400 if (!strcmp(ptr, "OFF")) { 376 if (!strcmp(ptr, "OFF")) {
401 config->status |= UPSSTATUS_OFF; 377 result.ups_status |= UPSSTATUS_OFF;
402 } else if (!strcmp(ptr, "OL")) { 378 } else if (!strcmp(ptr, "OL")) {
403 config->status |= UPSSTATUS_OL; 379 result.ups_status |= UPSSTATUS_OL;
404 } else if (!strcmp(ptr, "OB")) { 380 } else if (!strcmp(ptr, "OB")) {
405 config->status |= UPSSTATUS_OB; 381 result.ups_status |= UPSSTATUS_OB;
406 } else if (!strcmp(ptr, "LB")) { 382 } else if (!strcmp(ptr, "LB")) {
407 config->status |= UPSSTATUS_LB; 383 result.ups_status |= UPSSTATUS_LB;
408 } else if (!strcmp(ptr, "CAL")) { 384 } else if (!strcmp(ptr, "CAL")) {
409 config->status |= UPSSTATUS_CAL; 385 result.ups_status |= UPSSTATUS_CAL;
410 } else if (!strcmp(ptr, "RB")) { 386 } else if (!strcmp(ptr, "RB")) {
411 config->status |= UPSSTATUS_RB; 387 result.ups_status |= UPSSTATUS_RB;
412 } else if (!strcmp(ptr, "BYPASS")) { 388 } else if (!strcmp(ptr, "BYPASS")) {
413 config->status |= UPSSTATUS_BYPASS; 389 result.ups_status |= UPSSTATUS_BYPASS;
414 } else if (!strcmp(ptr, "OVER")) { 390 } else if (!strcmp(ptr, "OVER")) {
415 config->status |= UPSSTATUS_OVER; 391 result.ups_status |= UPSSTATUS_OVER;
416 } else if (!strcmp(ptr, "TRIM")) { 392 } else if (!strcmp(ptr, "TRIM")) {
417 config->status |= UPSSTATUS_TRIM; 393 result.ups_status |= UPSSTATUS_TRIM;
418 } else if (!strcmp(ptr, "BOOST")) { 394 } else if (!strcmp(ptr, "BOOST")) {
419 config->status |= UPSSTATUS_BOOST; 395 result.ups_status |= UPSSTATUS_BOOST;
420 } else if (!strcmp(ptr, "CHRG")) { 396 } else if (!strcmp(ptr, "CHRG")) {
421 config->status |= UPSSTATUS_CHRG; 397 result.ups_status |= UPSSTATUS_CHRG;
422 } else if (!strcmp(ptr, "DISCHRG")) { 398 } else if (!strcmp(ptr, "DISCHRG")) {
423 config->status |= UPSSTATUS_DISCHRG; 399 result.ups_status |= UPSSTATUS_DISCHRG;
424 } else if (!strcmp(ptr, "ALARM")) { 400 } else if (!strcmp(ptr, "ALARM")) {
425 config->status |= UPSSTATUS_ALARM; 401 result.ups_status |= UPSSTATUS_ALARM;
426 } else { 402 } else {
427 config->status |= UPSSTATUS_UNKNOWN; 403 result.ups_status |= UPSSTATUS_UNKNOWN;
428 } 404 }
429 } 405 }
430 406
431 return OK; 407 return result;
432} 408}
433 409
434/* gets a variable value for a specific UPS */ 410/* gets a variable value for a specific UPS */
435int get_ups_variable(const char *varname, char *buf, const ups_config config) { 411int get_ups_variable(const char *varname, char *buf, const check_ups_config config) {
436 char send_buffer[MAX_INPUT_BUFFER]; 412 char send_buffer[MAX_INPUT_BUFFER];
437 413
438 /* create the command string to send to the UPS daemon */ 414 /* create the command string to send to the UPS daemon */
439 /* Add LOGOUT to avoid read failure logs */ 415 /* Add LOGOUT to avoid read failure logs */
440 int res = snprintf(send_buffer, sizeof(send_buffer), "GET VAR %s %s\nLOGOUT\n", config.ups_name, varname); 416 int res = snprintf(send_buffer, sizeof(send_buffer), "GET VAR %s %s\nLOGOUT\n", config.ups_name,
417 varname);
441 if ((res > 0) && ((size_t)res >= sizeof(send_buffer))) { 418 if ((res > 0) && ((size_t)res >= sizeof(send_buffer))) {
442 printf("%s\n", _("UPS name to long for buffer")); 419 printf("%s\n", _("UPS name to long for buffer"));
443 return ERROR; 420 return ERROR;
@@ -446,7 +423,8 @@ int get_ups_variable(const char *varname, char *buf, const ups_config config) {
446 char temp_buffer[MAX_INPUT_BUFFER]; 423 char temp_buffer[MAX_INPUT_BUFFER];
447 424
448 /* send the command to the daemon and get a response back */ 425 /* send the command to the daemon and get a response back */
449 if (process_tcp_request(config.server_address, config.server_port, send_buffer, temp_buffer, sizeof(temp_buffer)) != STATE_OK) { 426 if (process_tcp_request(config.server_address, config.server_port, send_buffer, temp_buffer,
427 sizeof(temp_buffer)) != STATE_OK) {
450 printf("%s\n", _("Invalid response received from host")); 428 printf("%s\n", _("Invalid response received from host"));
451 return ERROR; 429 return ERROR;
452 } 430 }
@@ -500,7 +478,7 @@ int get_ups_variable(const char *varname, char *buf, const ups_config config) {
500 [-wv warn_value] [-cv crit_value] [-to to_sec] */ 478 [-wv warn_value] [-cv crit_value] [-to to_sec] */
501 479
502/* process command-line arguments */ 480/* process command-line arguments */
503int process_arguments(int argc, char **argv, ups_config *config) { 481check_ups_config_wrapper process_arguments(int argc, char **argv) {
504 482
505 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 483 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
506 {"ups", required_argument, 0, 'u'}, 484 {"ups", required_argument, 0, 'u'},
@@ -514,8 +492,14 @@ int process_arguments(int argc, char **argv, ups_config *config) {
514 {"help", no_argument, 0, 'h'}, 492 {"help", no_argument, 0, 'h'},
515 {0, 0, 0, 0}}; 493 {0, 0, 0, 0}};
516 494
495 check_ups_config_wrapper result = {
496 .errorcode = OK,
497 .config = check_ups_config_init(),
498 };
499
517 if (argc < 2) { 500 if (argc < 2) {
518 return ERROR; 501 result.errorcode = ERROR;
502 return result;
519 } 503 }
520 504
521 int c; 505 int c;
@@ -542,52 +526,52 @@ int process_arguments(int argc, char **argv, ups_config *config) {
542 usage5(); 526 usage5();
543 case 'H': /* hostname */ 527 case 'H': /* hostname */
544 if (is_host(optarg)) { 528 if (is_host(optarg)) {
545 config->server_address = optarg; 529 result.config.server_address = optarg;
546 } else { 530 } else {
547 usage2(_("Invalid hostname/address"), optarg); 531 usage2(_("Invalid hostname/address"), optarg);
548 } 532 }
549 break; 533 break;
550 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for 534 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for
551 Fahrenheit) */ 535 Fahrenheit) */
552 config->temp_output_c = true; 536 result.config.temp_output_c = true;
553 break; 537 break;
554 case 'u': /* ups name */ 538 case 'u': /* ups name */
555 config->ups_name = optarg; 539 result.config.ups_name = optarg;
556 break; 540 break;
557 case 'p': /* port */ 541 case 'p': /* port */
558 if (is_intpos(optarg)) { 542 if (is_intpos(optarg)) {
559 config->server_port = atoi(optarg); 543 result.config.server_port = atoi(optarg);
560 } else { 544 } else {
561 usage2(_("Port must be a positive integer"), optarg); 545 usage2(_("Port must be a positive integer"), optarg);
562 } 546 }
563 break; 547 break;
564 case 'c': /* critical time threshold */ 548 case 'c': /* critical time threshold */
565 if (is_intnonneg(optarg)) { 549 if (is_intnonneg(optarg)) {
566 config->critical_value = atoi(optarg); 550 result.config.critical_value = atoi(optarg);
567 config->check_crit = true; 551 result.config.check_crit = true;
568 } else { 552 } else {
569 usage2(_("Critical time must be a positive integer"), optarg); 553 usage2(_("Critical time must be a positive integer"), optarg);
570 } 554 }
571 break; 555 break;
572 case 'w': /* warning time threshold */ 556 case 'w': /* warning time threshold */
573 if (is_intnonneg(optarg)) { 557 if (is_intnonneg(optarg)) {
574 config->warning_value = atoi(optarg); 558 result.config.warning_value = atoi(optarg);
575 config->check_warn = true; 559 result.config.check_warn = true;
576 } else { 560 } else {
577 usage2(_("Warning time must be a positive integer"), optarg); 561 usage2(_("Warning time must be a positive integer"), optarg);
578 } 562 }
579 break; 563 break;
580 case 'v': /* variable */ 564 case 'v': /* variable */
581 if (!strcmp(optarg, "LINE")) { 565 if (!strcmp(optarg, "LINE")) {
582 config->check_variable = UPS_UTILITY; 566 result.config.check_variable = UPS_UTILITY;
583 } else if (!strcmp(optarg, "TEMP")) { 567 } else if (!strcmp(optarg, "TEMP")) {
584 config->check_variable = UPS_TEMP; 568 result.config.check_variable = UPS_TEMP;
585 } else if (!strcmp(optarg, "BATTPCT")) { 569 } else if (!strcmp(optarg, "BATTPCT")) {
586 config->check_variable = UPS_BATTPCT; 570 result.config.check_variable = UPS_BATTPCT;
587 } else if (!strcmp(optarg, "LOADPCT")) { 571 } else if (!strcmp(optarg, "LOADPCT")) {
588 config->check_variable = UPS_LOADPCT; 572 result.config.check_variable = UPS_LOADPCT;
589 } else if (!strcmp(optarg, "REALPOWER")) { 573 } else if (!strcmp(optarg, "REALPOWER")) {
590 config->check_variable = UPS_REALPOWER; 574 result.config.check_variable = UPS_REALPOWER;
591 } else { 575 } else {
592 usage2(_("Unrecognized UPS variable"), optarg); 576 usage2(_("Unrecognized UPS variable"), optarg);
593 } 577 }
@@ -608,27 +592,27 @@ int process_arguments(int argc, char **argv, ups_config *config) {
608 } 592 }
609 } 593 }
610 594
611 if (config->server_address == NULL && argc > optind) { 595 if (result.config.server_address == NULL && argc > optind) {
612 if (is_host(argv[optind])) { 596 if (is_host(argv[optind])) {
613 config->server_address = argv[optind++]; 597 result.config.server_address = argv[optind++];
614 } else { 598 } else {
615 usage2(_("Invalid hostname/address"), optarg); 599 usage2(_("Invalid hostname/address"), optarg);
616 } 600 }
617 } 601 }
618 602
619 if (config->server_address == NULL) { 603 if (result.config.server_address == NULL) {
620 config->server_address = strdup("127.0.0.1"); 604 result.config.server_address = strdup("127.0.0.1");
621 } 605 }
622 606
623 return validate_arguments(*config); 607 return validate_arguments(result);
624} 608}
625 609
626int validate_arguments(ups_config config) { 610check_ups_config_wrapper validate_arguments(check_ups_config_wrapper config_wrapper) {
627 if (!config.ups_name) { 611 if (config_wrapper.config.ups_name) {
628 printf("%s\n", _("Error : no UPS indicated")); 612 printf("%s\n", _("Error : no UPS indicated"));
629 return ERROR; 613 config_wrapper.errorcode = ERROR;
630 } 614 }
631 return OK; 615 return config_wrapper;
632} 616}
633 617
634void print_help(void) { 618void print_help(void) {
@@ -660,7 +644,8 @@ void print_help(void) {
660 printf(" %s\n", "-T, --temperature"); 644 printf(" %s\n", "-T, --temperature");
661 printf(" %s\n", _("Output of temperatures in Celsius")); 645 printf(" %s\n", _("Output of temperatures in Celsius"));
662 printf(" %s\n", "-v, --variable=STRING"); 646 printf(" %s\n", "-v, --variable=STRING");
663 printf(" %s %s\n", _("Valid values for STRING are"), "LINE, TEMP, BATTPCT, LOADPCT or REALPOWER"); 647 printf(" %s %s\n", _("Valid values for STRING are"),
648 "LINE, TEMP, BATTPCT, LOADPCT or REALPOWER");
664 649
665 printf(UT_WARN_CRIT); 650 printf(UT_WARN_CRIT);
666 651
diff --git a/plugins/check_ups.d/config.h b/plugins/check_ups.d/config.h
new file mode 100644
index 00000000..e05edceb
--- /dev/null
+++ b/plugins/check_ups.d/config.h
@@ -0,0 +1,54 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6#define UPS_NONE 0 /* no supported options */
7#define UPS_UTILITY 1 /* supports utility line */
8#define UPS_BATTPCT 2 /* supports percent battery remaining */
9#define UPS_STATUS 4 /* supports UPS status */
10#define UPS_TEMP 8 /* supports UPS temperature */
11#define UPS_LOADPCT 16 /* supports load percent */
12#define UPS_REALPOWER 32 /* supports real power */
13
14#define UPSSTATUS_NONE 0
15#define UPSSTATUS_OFF 1
16#define UPSSTATUS_OL 2
17#define UPSSTATUS_OB 4
18#define UPSSTATUS_LB 8
19#define UPSSTATUS_CAL 16
20#define UPSSTATUS_RB 32 /*Replace Battery */
21#define UPSSTATUS_BYPASS 64
22#define UPSSTATUS_OVER 128
23#define UPSSTATUS_TRIM 256
24#define UPSSTATUS_BOOST 512
25#define UPSSTATUS_CHRG 1024
26#define UPSSTATUS_DISCHRG 2048
27#define UPSSTATUS_UNKNOWN 4096
28#define UPSSTATUS_ALARM 8192
29
30enum {
31 PORT = 3493
32};
33
34typedef struct ups_config {
35 unsigned int server_port;
36 char *server_address;
37 char *ups_name;
38 double warning_value;
39 double critical_value;
40 bool check_warn;
41 bool check_crit;
42 int check_variable;
43 bool temp_output_c;
44} check_ups_config;
45
46check_ups_config check_ups_config_init(void) {
47 check_ups_config tmp = {0};
48 tmp.server_port = PORT;
49 tmp.server_address = NULL;
50 tmp.ups_name = NULL;
51 tmp.check_variable = UPS_NONE;
52
53 return tmp;
54}
diff --git a/plugins/check_users.c b/plugins/check_users.c
index f1e1c39d..3b2e265e 100644
--- a/plugins/check_users.c
+++ b/plugins/check_users.c
@@ -34,8 +34,15 @@ const char *progname = "check_users";
34const char *copyright = "2000-2024"; 34const char *copyright = "2000-2024";
35const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
36 36
37#include "common.h" 37#include "check_users.d/users.h"
38#include "utils.h" 38#include "output.h"
39#include "perfdata.h"
40#include "states.h"
41#include "utils_base.h"
42#include "./common.h"
43#include "./utils.h"
44#include "check_users.d/config.h"
45#include "thresholds.h"
39 46
40#if HAVE_WTSAPI32_H 47#if HAVE_WTSAPI32_H
41# include <windows.h> 48# include <windows.h>
@@ -44,8 +51,6 @@ const char *email = "devel@monitoring-plugins.org";
44# define ERROR -1 51# define ERROR -1
45#elif HAVE_UTMPX_H 52#elif HAVE_UTMPX_H
46# include <utmpx.h> 53# include <utmpx.h>
47#else
48# include "popen.h"
49#endif 54#endif
50 55
51#ifdef HAVE_LIBSYSTEMD 56#ifdef HAVE_LIBSYSTEMD
@@ -53,29 +58,16 @@ const char *email = "devel@monitoring-plugins.org";
53# include <systemd/sd-login.h> 58# include <systemd/sd-login.h>
54#endif 59#endif
55 60
56#define possibly_set(a, b) ((a) == 0 ? (b) : 0) 61typedef struct process_argument_wrapper {
62 int errorcode;
63 check_users_config config;
64} check_users_config_wrapper;
65check_users_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
57 66
58static int process_arguments(int, char **); 67void print_help(void);
59static void print_help(void);
60void print_usage(void); 68void print_usage(void);
61 69
62static char *warning_range = NULL;
63static char *critical_range = NULL;
64static thresholds *thlds = NULL;
65
66int main(int argc, char **argv) { 70int main(int argc, char **argv) {
67 int users = -1;
68 int result = STATE_UNKNOWN;
69#if HAVE_WTSAPI32_H
70 WTS_SESSION_INFO *wtsinfo;
71 DWORD wtscount;
72 DWORD index;
73#elif HAVE_UTMPX_H
74 struct utmpx *putmpx;
75#else
76 char input_buffer[MAX_INPUT_BUFFER];
77#endif
78
79 setlocale(LC_ALL, ""); 71 setlocale(LC_ALL, "");
80 bindtextdomain(PACKAGE, LOCALEDIR); 72 bindtextdomain(PACKAGE, LOCALEDIR);
81 textdomain(PACKAGE); 73 textdomain(PACKAGE);
@@ -83,121 +75,104 @@ int main(int argc, char **argv) {
83 /* Parse extra opts if any */ 75 /* Parse extra opts if any */
84 argv = np_extra_opts(&argc, argv, progname); 76 argv = np_extra_opts(&argc, argv, progname);
85 77
86 if (process_arguments(argc, argv) == ERROR) 78 check_users_config_wrapper tmp_config = process_arguments(argc, argv);
87 usage4(_("Could not parse arguments"));
88
89 users = 0;
90
91#ifdef HAVE_LIBSYSTEMD
92 if (sd_booted() > 0)
93 users = sd_get_sessions(NULL);
94 else {
95#endif
96#if HAVE_WTSAPI32_H
97 if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &wtsinfo, &wtscount)) {
98 printf(_("Could not enumerate RD sessions: %d\n"), GetLastError());
99 return STATE_UNKNOWN;
100 }
101
102 for (index = 0; index < wtscount; index++) {
103 LPTSTR username;
104 DWORD size;
105 int len;
106
107 if (!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, wtsinfo[index].SessionId, WTSUserName, &username, &size))
108 continue;
109
110 len = lstrlen(username);
111
112 WTSFreeMemory(username);
113
114 if (len == 0)
115 continue;
116
117 if (wtsinfo[index].State == WTSActive || wtsinfo[index].State == WTSDisconnected)
118 users++;
119 }
120
121 WTSFreeMemory(wtsinfo);
122#elif HAVE_UTMPX_H
123 /* get currently logged users from utmpx */
124 setutxent();
125
126 while ((putmpx = getutxent()) != NULL)
127 if (putmpx->ut_type == USER_PROCESS)
128 users++;
129 79
130 endutxent(); 80 if (tmp_config.errorcode == ERROR) {
131#else 81 usage4(_("Could not parse arguments"));
132 /* run the command */
133 child_process = spopen(WHO_COMMAND);
134 if (child_process == NULL) {
135 printf(_("Could not open pipe: %s\n"), WHO_COMMAND);
136 return STATE_UNKNOWN;
137 } 82 }
138 83
139 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r"); 84 check_users_config config = tmp_config.config;
140 if (child_stderr == NULL)
141 printf(_("Could not open stderr for %s\n"), WHO_COMMAND);
142
143 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
144 /* increment 'users' on all lines except total user count */
145 if (input_buffer[0] != '#') {
146 users++;
147 continue;
148 }
149 85
150 /* get total logged in users */ 86#ifdef _WIN32
151 if (sscanf(input_buffer, _("# users=%d"), &users) == 1) 87# if HAVE_WTSAPI32_H
152 break; 88 get_num_of_users_wrapper user_wrapper = get_num_of_users_windows();
89# else
90# error Did not find WTSAPI32
91# endif // HAVE_WTSAPI32_H
92#else
93# ifdef HAVE_LIBSYSTEMD
94 get_num_of_users_wrapper user_wrapper = get_num_of_users_systemd();
95# elif HAVE_UTMPX_H
96 get_num_of_users_wrapper user_wrapper = get_num_of_users_utmp();
97# else // !HAVE_LIBSYSTEMD && !HAVE_UTMPX_H
98 get_num_of_users_wrapper user_wrapper = get_num_of_users_who_command();
99# endif // HAVE_LIBSYSTEMD
100#endif // _WIN32
101
102 mp_check overall = mp_check_init();
103 if (config.output_format_is_set) {
104 mp_set_format(config.output_format);
153 } 105 }
106 mp_subcheck sc_users = mp_subcheck_init();
154 107
155 /* check STDERR */ 108 if (user_wrapper.errorcode != 0) {
156 if (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) 109 sc_users = mp_set_subcheck_state(sc_users, STATE_UNKNOWN);
157 result = possibly_set(result, STATE_UNKNOWN); 110 sc_users.output = "Failed to retrieve number of users";
158 (void)fclose(child_stderr); 111 mp_add_subcheck_to_check(&overall, sc_users);
159 112 mp_exit(overall);
160 /* close the pipe */
161 if (spclose(child_process))
162 result = possibly_set(result, STATE_UNKNOWN);
163#endif
164#ifdef HAVE_LIBSYSTEMD
165 } 113 }
166#endif
167
168 /* check the user count against warning and critical thresholds */ 114 /* check the user count against warning and critical thresholds */
169 result = get_status((double)users, thlds);
170 115
171 if (result == STATE_UNKNOWN) 116 mp_perfdata users_pd = {
172 printf("%s\n", _("Unable to read output")); 117 .label = "users",
173 else { 118 .value = mp_create_pd_value(user_wrapper.users),
174 printf(_("USERS %s - %d users currently logged in |%s\n"), state_text(result), users, 119 };
175 sperfdata_int("users", users, "", warning_range, critical_range, true, 0, false, 0)); 120
121 users_pd = mp_pd_set_thresholds(users_pd, config.thresholds);
122 mp_add_perfdata_to_subcheck(&sc_users, users_pd);
123
124 int tmp_status = mp_get_pd_status(users_pd);
125 sc_users = mp_set_subcheck_state(sc_users, tmp_status);
126
127 switch (tmp_status) {
128 case STATE_WARNING:
129 xasprintf(&sc_users.output,
130 "%d users currently logged in. This violates the warning threshold",
131 user_wrapper.users);
132 break;
133 case STATE_CRITICAL:
134 xasprintf(&sc_users.output,
135 "%d users currently logged in. This violates the critical threshold",
136 user_wrapper.users);
137 break;
138 default:
139 xasprintf(&sc_users.output, "%d users currently logged in", user_wrapper.users);
176 } 140 }
177 141
178 return result; 142 mp_add_subcheck_to_check(&overall, sc_users);
143 mp_exit(overall);
179} 144}
180 145
146#define output_format_index CHAR_MAX + 1
147
181/* process command-line arguments */ 148/* process command-line arguments */
182int process_arguments(int argc, char **argv) { 149check_users_config_wrapper process_arguments(int argc, char **argv) {
183 static struct option longopts[] = {{"critical", required_argument, 0, 'c'}, 150 static struct option longopts[] = {{"critical", required_argument, 0, 'c'},
184 {"warning", required_argument, 0, 'w'}, 151 {"warning", required_argument, 0, 'w'},
185 {"version", no_argument, 0, 'V'}, 152 {"version", no_argument, 0, 'V'},
186 {"help", no_argument, 0, 'h'}, 153 {"help", no_argument, 0, 'h'},
154 {"output-format", required_argument, 0, output_format_index},
187 {0, 0, 0, 0}}; 155 {0, 0, 0, 0}};
188 156
189 if (argc < 2) 157 if (argc < 2) {
190 usage("\n"); 158 usage(progname);
159 }
160
161 char *warning_range = NULL;
162 char *critical_range = NULL;
163 check_users_config_wrapper result = {
164 .config = check_users_config_init(),
165 .errorcode = OK,
166 };
191 167
192 int option_char;
193 while (true) { 168 while (true) {
194 int option = 0; 169 int counter = getopt_long(argc, argv, "+hVvc:w:", longopts, NULL);
195 option_char = getopt_long(argc, argv, "+hVvc:w:", longopts, &option);
196 170
197 if (option_char == -1 || option_char == EOF || option_char == 1) 171 if (counter == -1 || counter == EOF || counter == 1) {
198 break; 172 break;
173 }
199 174
200 switch (option_char) { 175 switch (counter) {
201 case '?': /* print short usage statement if args not parsable */ 176 case '?': /* print short usage statement if args not parsable */
202 usage5(); 177 usage5();
203 case 'h': /* help */ 178 case 'h': /* help */
@@ -212,29 +187,66 @@ int process_arguments(int argc, char **argv) {
212 case 'w': /* warning */ 187 case 'w': /* warning */
213 warning_range = optarg; 188 warning_range = optarg;
214 break; 189 break;
190 case output_format_index: {
191 parsed_output_format parser = mp_parse_output_format(optarg);
192 if (!parser.parsing_success) {
193 // TODO List all available formats here, maybe add anothoer usage function
194 printf("Invalid output format: %s\n", optarg);
195 exit(STATE_UNKNOWN);
196 }
197
198 result.config.output_format_is_set = true;
199 result.config.output_format = parser.output_format;
200 break;
201 }
215 } 202 }
216 } 203 }
217 204
218 option_char = optind; 205 int option_char = optind;
219 206
220 if (warning_range == NULL && argc > option_char) 207 if (warning_range == NULL && argc > option_char) {
221 warning_range = argv[option_char++]; 208 warning_range = argv[option_char++];
209 }
222 210
223 if (critical_range == NULL && argc > option_char) 211 if (critical_range == NULL && argc > option_char) {
224 critical_range = argv[option_char++]; 212 critical_range = argv[option_char++];
213 }
214
215 // TODO add proper verification for ranges here!
216 mp_range_parsed tmp;
217 if (warning_range) {
218 tmp = mp_parse_range_string(warning_range);
219 } else {
220 printf("Warning threshold missing\n");
221 print_usage();
222 exit(STATE_UNKNOWN);
223 }
225 224
226 /* this will abort in case of invalid ranges */ 225 if (tmp.error == MP_PARSING_SUCCES) {
227 set_thresholds(&thlds, warning_range, critical_range); 226 result.config.thresholds.warning = tmp.range;
227 result.config.thresholds.warning_is_set = true;
228 } else {
229 printf("Failed to parse warning range: %s", warning_range);
230 exit(STATE_UNKNOWN);
231 }
228 232
229 if (!thlds->warning) { 233 if (critical_range) {
230 usage4(_("Warning threshold must be a valid range expression")); 234 tmp = mp_parse_range_string(critical_range);
235 } else {
236 printf("Critical threshold missing\n");
237 print_usage();
238 exit(STATE_UNKNOWN);
231 } 239 }
232 240
233 if (!thlds->critical) { 241 if (tmp.error == MP_PARSING_SUCCES) {
234 usage4(_("Critical threshold must be a valid range expression")); 242 result.config.thresholds.critical = tmp.range;
243 result.config.thresholds.critical_is_set = true;
244 } else {
245 printf("Failed to parse critical range: %s", critical_range);
246 exit(STATE_UNKNOWN);
235 } 247 }
236 248
237 return OK; 249 return result;
238} 250}
239 251
240void print_help(void) { 252void print_help(void) {
@@ -244,7 +256,8 @@ void print_help(void) {
244 printf(COPYRIGHT, copyright, email); 256 printf(COPYRIGHT, copyright, email);
245 257
246 printf("%s\n", _("This plugin checks the number of users currently logged in on the local")); 258 printf("%s\n", _("This plugin checks the number of users currently logged in on the local"));
247 printf("%s\n", _("system and generates an error if the number exceeds the thresholds specified.")); 259 printf("%s\n",
260 _("system and generates an error if the number exceeds the thresholds specified."));
248 261
249 printf("\n\n"); 262 printf("\n\n");
250 263
@@ -254,9 +267,12 @@ void print_help(void) {
254 printf(UT_EXTRA_OPTS); 267 printf(UT_EXTRA_OPTS);
255 268
256 printf(" %s\n", "-w, --warning=RANGE_EXPRESSION"); 269 printf(" %s\n", "-w, --warning=RANGE_EXPRESSION");
257 printf(" %s\n", _("Set WARNING status if number of logged in users violates RANGE_EXPRESSION")); 270 printf(" %s\n",
271 _("Set WARNING status if number of logged in users violates RANGE_EXPRESSION"));
258 printf(" %s\n", "-c, --critical=RANGE_EXPRESSION"); 272 printf(" %s\n", "-c, --critical=RANGE_EXPRESSION");
259 printf(" %s\n", _("Set CRITICAL status if number of logged in users violates RANGE_EXPRESSION")); 273 printf(" %s\n",
274 _("Set CRITICAL status if number of logged in users violates RANGE_EXPRESSION"));
275 printf(UT_OUTPUT_FORMAT);
260 276
261 printf(UT_SUPPORT); 277 printf(UT_SUPPORT);
262} 278}
diff --git a/plugins/check_users.d/config.h b/plugins/check_users.d/config.h
new file mode 100644
index 00000000..26d3ee70
--- /dev/null
+++ b/plugins/check_users.d/config.h
@@ -0,0 +1,20 @@
1#pragma once
2
3#include "output.h"
4#include "thresholds.h"
5
6typedef struct check_users_config {
7 mp_thresholds thresholds;
8
9 bool output_format_is_set;
10 mp_output_format output_format;
11} check_users_config;
12
13check_users_config check_users_config_init() {
14 check_users_config tmp = {
15 .thresholds = mp_thresholds_init(),
16
17 .output_format_is_set = false,
18 };
19 return tmp;
20}
diff --git a/plugins/check_users.d/users.c b/plugins/check_users.d/users.c
new file mode 100644
index 00000000..a08f79c5
--- /dev/null
+++ b/plugins/check_users.d/users.c
@@ -0,0 +1,169 @@
1#include "./users.h"
2
3#ifdef _WIN32
4# ifdef HAVE_WTSAPI32_H
5# include <windows.h>
6# include <wtsapi32.h>
7# undef ERROR
8# define ERROR -1
9
10get_num_of_users_wrapper get_num_of_users_windows() {
11 WTS_SESSION_INFO *wtsinfo;
12 DWORD wtscount;
13
14 get_num_of_users_wrapper result = {};
15
16 if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &wtsinfo, &wtscount)) {
17 // printf(_("Could not enumerate RD sessions: %d\n"), GetLastError());
18 result.error = WINDOWS_COULD_NOT_ENUMERATE_SESSIONS;
19 return result;
20 }
21
22 for (DWORD index = 0; index < wtscount; index++) {
23 LPTSTR username;
24 DWORD size;
25
26 if (!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, wtsinfo[index].SessionId,
27 WTSUserName, &username, &size)) {
28 continue;
29 }
30
31 int len = lstrlen(username);
32
33 WTSFreeMemory(username);
34
35 if (len == 0) {
36 continue;
37 }
38
39 if (wtsinfo[index].State == WTSActive || wtsinfo[index].State == WTSDisconnected) {
40 result.users++;
41 }
42 }
43
44 WTSFreeMemory(wtsinfo);
45 return result;
46}
47# else // HAVE_WTSAPI32_H
48# error On windows but without the WTSAPI32 lib
49# endif // HAVE_WTSAPI32_H
50
51#else // _WIN32
52
53# include "../../config.h"
54# include <stddef.h>
55
56# ifdef HAVE_LIBSYSTEMD
57# include <systemd/sd-daemon.h>
58# include <systemd/sd-login.h>
59
60get_num_of_users_wrapper get_num_of_users_systemd() {
61 get_num_of_users_wrapper result = {};
62
63 // Test whether we booted with systemd
64 if (sd_booted() > 0) {
65 int users = sd_get_uids(NULL);
66 if (users >= 0) {
67 // Success
68 result.users = users;
69 return result;
70 }
71
72 // Failure! return the error code
73 result.errorcode = users;
74 return result;
75 }
76
77 // Looks like we are not running systemd,
78 // return with error here
79 result.errorcode = NO_SYSTEMD_ERROR;
80 return result;
81}
82# endif
83
84# ifdef HAVE_UTMPX_H
85# include <utmpx.h>
86
87get_num_of_users_wrapper get_num_of_users_utmp() {
88 int users = 0;
89
90 /* get currently logged users from utmpx */
91 setutxent();
92
93 struct utmpx *putmpx;
94 while ((putmpx = getutxent()) != NULL) {
95 if (putmpx->ut_type == USER_PROCESS) {
96 users++;
97 }
98 }
99
100 endutxent();
101
102 get_num_of_users_wrapper result = {
103 .errorcode = 0,
104 .users = users,
105 };
106
107 return result;
108}
109# endif
110
111# ifndef HAVE_WTSAPI32_H
112# ifndef HAVE_LIBSYSTEMD
113# ifndef HAVE_UTMPX_H
114// Fall back option here for the others (probably still not on windows)
115
116# include "../common.h"
117# include "../popen.h"
118# include "../utils.h"
119
120get_num_of_users_wrapper get_num_of_users_who_command() {
121 /* run the command */
122 child_process = spopen(WHO_COMMAND);
123 if (child_process == NULL) {
124 // printf(_("Could not open pipe: %s\n"), WHO_COMMAND);
125 get_num_of_users_wrapper result = {
126 .errorcode = COULD_NOT_OPEN_PIPE,
127 };
128 return result;
129 }
130
131 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
132 if (child_stderr == NULL) {
133 // printf(_("Could not open stderr for %s\n"), WHO_COMMAND);
134 // TODO this error should probably be reported
135 }
136
137 get_num_of_users_wrapper result = {};
138 char input_buffer[MAX_INPUT_BUFFER];
139 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
140 /* increment 'users' on all lines except total user count */
141 if (input_buffer[0] != '#') {
142 result.users++;
143 continue;
144 }
145
146 /* get total logged in users */
147 if (sscanf(input_buffer, _("# users=%d"), &result.users) == 1) {
148 break;
149 }
150 }
151
152 /* check STDERR */
153 if (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
154 // if this fails, something broke and the result can not be relied upon or so is the theorie
155 // here
156 result.errorcode = STDERR_COULD_NOT_BE_READ;
157 }
158 (void)fclose(child_stderr);
159
160 /* close the pipe */
161 spclose(child_process);
162
163 return result;
164}
165
166# endif
167# endif
168# endif
169#endif
diff --git a/plugins/check_users.d/users.h b/plugins/check_users.d/users.h
new file mode 100644
index 00000000..aacba775
--- /dev/null
+++ b/plugins/check_users.d/users.h
@@ -0,0 +1,18 @@
1#pragma once
2
3typedef struct get_num_of_users_wrapper {
4 int errorcode;
5 int users;
6} get_num_of_users_wrapper;
7
8enum {
9 NO_SYSTEMD_ERROR = 64,
10 WINDOWS_COULD_NOT_ENUMERATE_SESSIONS,
11 COULD_NOT_OPEN_PIPE,
12 STDERR_COULD_NOT_BE_READ,
13};
14
15get_num_of_users_wrapper get_num_of_users_systemd();
16get_num_of_users_wrapper get_num_of_users_utmp();
17get_num_of_users_wrapper get_num_of_users_windows();
18get_num_of_users_wrapper get_num_of_users_who_command();
diff --git a/plugins/common.h b/plugins/common.h
index 603bae55..ef888d08 100644
--- a/plugins/common.h
+++ b/plugins/common.h
@@ -1,121 +1,122 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring Plugins common include file 3 * Monitoring Plugins common include file
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999 Ethan Galstad (nagios@nagios.org) 6 * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
7* Copyright (c) 2003-2007 Monitoring Plugins Development Team 7 * Copyright (c) 2003-2007 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains common include files and defines used in many of 11 * This file contains common include files and defines used in many of
12* the plugins. 12 * the plugins.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31#ifndef _COMMON_H_ 31#ifndef _COMMON_H_
32#define _COMMON_H_ 32#define _COMMON_H_
33 33
34#include "config.h" 34#include "../config.h"
35#include "../lib/monitoringplug.h" 35#include "../lib/monitoringplug.h"
36 36
37#ifdef HAVE_FEATURES_H 37#ifdef HAVE_FEATURES_H
38#include <features.h> 38# include <features.h>
39#endif 39#endif
40 40
41#include <stdio.h> /* obligatory includes */ 41#include <stdio.h> /* obligatory includes */
42#include <stdlib.h> 42#include <stdlib.h>
43#include <errno.h> 43#include <errno.h>
44 44
45/* This block provides uintmax_t - should be reported to coreutils that this should be added to fsuage.h */ 45/* This block provides uintmax_t - should be reported to coreutils that this should be added to
46 * fsuage.h */
46#if HAVE_INTTYPES_H 47#if HAVE_INTTYPES_H
47# include <inttypes.h> 48# include <inttypes.h>
48#endif 49#endif
49#if HAVE_STDINT_H 50#if HAVE_STDINT_H
50# include <stdint.h> 51# include <stdint.h>
51#endif 52#endif
52#include <unistd.h> 53#include <unistd.h>
53#ifndef UINTMAX_MAX 54#ifndef UINTMAX_MAX
54# define UINTMAX_MAX ((uintmax_t) -1) 55# define UINTMAX_MAX ((uintmax_t) - 1)
55#endif 56#endif
56 57
57#include <limits.h> /* This is assumed true, because coreutils assume it too */ 58#include <limits.h> /* This is assumed true, because coreutils assume it too */
58 59
59#ifdef HAVE_MATH_H 60#ifdef HAVE_MATH_H
60#include <math.h> 61# include <math.h>
61#endif 62#endif
62 63
63#ifdef _AIX 64#ifdef _AIX
64#ifdef HAVE_MP_H 65# ifdef HAVE_MP_H
65#include <mp.h> 66# include <mp.h>
66#endif 67# endif
67#endif 68#endif
68 69
69#ifdef HAVE_STRINGS_H 70#ifdef HAVE_STRINGS_H
70#include <strings.h> 71# include <strings.h>
71#endif 72#endif
72#ifdef HAVE_STRING_H 73#ifdef HAVE_STRING_H
73#include <string.h> 74# include <string.h>
74#endif 75#endif
75 76
76#ifdef HAVE_UNISTD_H 77#ifdef HAVE_UNISTD_H
77#include <unistd.h> 78# include <unistd.h>
78#endif 79#endif
79 80
80/* GET_NUMBER_OF_CPUS is a macro to return 81/* GET_NUMBER_OF_CPUS is a macro to return
81 number of CPUs, if we can get that data. 82 number of CPUs, if we can get that data.
82 Use configure.in to test for various OS ways of 83 Use configure.in to test for various OS ways of
83 getting that data 84 getting that data
84 Will return -1 if cannot get data 85 Will return -1 if cannot get data
85*/ 86*/
86#if defined(HAVE_SYSCONF__SC_NPROCESSORS_ONLN) 87#if defined(HAVE_SYSCONF__SC_NPROCESSORS_ONLN)
87# define GET_NUMBER_OF_CPUS() sysconf(_SC_NPROCESSORS_ONLN) 88# define GET_NUMBER_OF_CPUS() sysconf(_SC_NPROCESSORS_ONLN)
88#elif defined (HAVE_SYSCONF__SC_NPROCESSORS_CONF) 89#elif defined(HAVE_SYSCONF__SC_NPROCESSORS_CONF)
89# define GET_NUMBER_OF_CPUS() sysconf(_SC_NPROCESSORS_CONF) 90# define GET_NUMBER_OF_CPUS() sysconf(_SC_NPROCESSORS_CONF)
90#else 91#else
91# define GET_NUMBER_OF_CPUS() -1 92# define GET_NUMBER_OF_CPUS() -1
92#endif 93#endif
93 94
94#ifdef HAVE_SYS_TIME_H 95#ifdef HAVE_SYS_TIME_H
95# include <sys/time.h> 96# include <sys/time.h>
96#endif 97#endif
97#include <time.h> 98#include <time.h>
98 99
99#ifdef HAVE_SYS_TYPES_H 100#ifdef HAVE_SYS_TYPES_H
100#include <sys/types.h> 101# include <sys/types.h>
101#endif 102#endif
102 103
103#ifdef HAVE_SYS_SOCKET_H 104#ifdef HAVE_SYS_SOCKET_H
104#include <sys/socket.h> 105# include <sys/socket.h>
105#endif 106#endif
106 107
107#ifdef HAVE_SIGNAL_H 108#ifdef HAVE_SIGNAL_H
108#include <signal.h> 109# include <signal.h>
109#endif 110#endif
110 111
111/* GNU Libraries */ 112/* GNU Libraries */
112#include <getopt.h> 113#include <getopt.h>
113#include "dirname.h" 114#include "../gl/dirname.h"
114 115
115#include <locale.h> 116#include <locale.h>
116 117
117#ifdef HAVE_SYS_POLL_H 118#ifdef HAVE_SYS_POLL_H
118# include "sys/poll.h" 119# include "sys/poll.h"
119#endif 120#endif
120 121
121/* 122/*
@@ -125,42 +126,42 @@
125 */ 126 */
126 127
127#ifndef HAVE_STRTOL 128#ifndef HAVE_STRTOL
128# define strtol(a,b,c) atol((a)) 129# define strtol(a, b, c) atol((a))
129#endif 130#endif
130 131
131#ifndef HAVE_STRTOUL 132#ifndef HAVE_STRTOUL
132# define strtoul(a,b,c) (unsigned long)atol((a)) 133# define strtoul(a, b, c) (unsigned long)atol((a))
133#endif 134#endif
134 135
135/* SSL implementations */ 136/* SSL implementations */
136#ifdef HAVE_GNUTLS_OPENSSL_H 137#ifdef HAVE_GNUTLS_OPENSSL_H
137# include <gnutls/openssl.h> 138# include <gnutls/openssl.h>
138#else 139#else
139# define OPENSSL_LOAD_CONF /* See the OPENSSL_config(3) man page. */ 140# define OPENSSL_LOAD_CONF /* See the OPENSSL_config(3) man page. */
140# ifdef HAVE_SSL_H 141# ifdef HAVE_SSL_H
141# include <rsa.h> 142# include <rsa.h>
142# include <crypto.h> 143# include <crypto.h>
143# include <x509.h> 144# include <x509.h>
144# include <pem.h> 145# include <pem.h>
145# include <ssl.h> 146# include <ssl.h>
146# include <err.h> 147# include <err.h>
147# else 148# else
148# ifdef HAVE_OPENSSL_SSL_H 149# ifdef HAVE_OPENSSL_SSL_H
149# include <openssl/rsa.h> 150# include <openssl/rsa.h>
150# include <openssl/crypto.h> 151# include <openssl/crypto.h>
151# include <openssl/x509.h> 152# include <openssl/x509.h>
152# include <openssl/pem.h> 153# include <openssl/pem.h>
153# include <openssl/ssl.h> 154# include <openssl/ssl.h>
154# include <openssl/err.h> 155# include <openssl/err.h>
155# endif 156# endif
156# endif 157# endif
157#endif 158#endif
158 159
159/* openssl 1.1 does not set OPENSSL_NO_SSL2 by default but ships without ssl2 */ 160/* openssl 1.1 does not set OPENSSL_NO_SSL2 by default but ships without ssl2 */
160#ifdef OPENSSL_VERSION_NUMBER 161#ifdef OPENSSL_VERSION_NUMBER
161# if OPENSSL_VERSION_NUMBER >= 0x10100000 162# if OPENSSL_VERSION_NUMBER >= 0x10100000
162# define OPENSSL_NO_SSL2 163# define OPENSSL_NO_SSL2
163# endif 164# endif
164#endif 165#endif
165 166
166/* 167/*
@@ -171,7 +172,7 @@
171 172
172/* MariaDB 10.2 client does not set MYSQL_PORT */ 173/* MariaDB 10.2 client does not set MYSQL_PORT */
173#ifndef MYSQL_PORT 174#ifndef MYSQL_PORT
174# define MYSQL_PORT 3306 175# define MYSQL_PORT 3306
175#endif 176#endif
176 177
177enum { 178enum {
@@ -180,9 +181,9 @@ enum {
180}; 181};
181 182
182enum { 183enum {
183 DEFAULT_SOCKET_TIMEOUT = 10, /* timeout after 10 seconds */ 184 DEFAULT_SOCKET_TIMEOUT = 10, /* timeout after 10 seconds */
184 MAX_INPUT_BUFFER = 8192, /* max size of most buffers we use */ 185 MAX_INPUT_BUFFER = 8192, /* max size of most buffers we use */
185 MAX_HOST_ADDRESS_LENGTH = 256 /* max size of a host address */ 186 MAX_HOST_ADDRESS_LENGTH = 256 /* max size of a host address */
186}; 187};
187 188
188/* 189/*
@@ -190,18 +191,18 @@ enum {
190 * Internationalization 191 * Internationalization
191 * 192 *
192 */ 193 */
193#include "gettext.h" 194#include "../gl/gettext.h"
194#define _(String) gettext (String) 195#define _(String) gettext(String)
195#if ! ENABLE_NLS 196#if !ENABLE_NLS
196# undef textdomain 197# undef textdomain
197# define textdomain(Domainname) /* empty */ 198# define textdomain(Domainname) /* empty */
198# undef bindtextdomain 199# undef bindtextdomain
199# define bindtextdomain(Domainname, Dirname) /* empty */ 200# define bindtextdomain(Domainname, Dirname) /* empty */
200#endif 201#endif
201 202
202/* For non-GNU compilers to ignore __attribute__ */ 203/* For non-GNU compilers to ignore __attribute__ */
203#ifndef __GNUC__ 204#ifndef __GNUC__
204# define __attribute__(x) /* do nothing */ 205# define __attribute__(x) /* do nothing */
205#endif 206#endif
206 207
207#endif /* _COMMON_H_ */ 208#endif /* _COMMON_H_ */
diff --git a/plugins/negate.c b/plugins/negate.c
index 750c0bfb..a42a6c59 100644
--- a/plugins/negate.c
+++ b/plugins/negate.c
@@ -38,21 +38,18 @@ const char *email = "devel@monitoring-plugins.org";
38#include "common.h" 38#include "common.h"
39#include "utils.h" 39#include "utils.h"
40#include "utils_cmd.h" 40#include "utils_cmd.h"
41#include "negate.d/config.h"
42#include "../lib/states.h"
41 43
42#include <ctype.h> 44typedef struct {
45 int errorcode;
46 negate_config config;
47} negate_config_wrapper;
48static negate_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
49static negate_config_wrapper validate_arguments(negate_config_wrapper /*config_wrapper*/);
43 50
44static const char **process_arguments(int /*argc*/, char ** /*argv*/);
45static void validate_arguments(char ** /*command_line*/);
46static void print_help(void); 51static void print_help(void);
47void print_usage(void); 52void print_usage(void);
48static bool subst_text = false;
49
50static int state[4] = {
51 STATE_OK,
52 STATE_WARNING,
53 STATE_CRITICAL,
54 STATE_UNKNOWN,
55};
56 53
57int main(int argc, char **argv) { 54int main(int argc, char **argv) {
58 setlocale(LC_ALL, ""); 55 setlocale(LC_ALL, "");
@@ -61,15 +58,24 @@ int main(int argc, char **argv) {
61 58
62 timeout_interval = DEFAULT_TIMEOUT; 59 timeout_interval = DEFAULT_TIMEOUT;
63 60
64 char **command_line = (char **)process_arguments(argc, argv); 61 negate_config_wrapper tmp_config = process_arguments(argc, argv);
62
63 if (tmp_config.errorcode == ERROR) {
64 die(STATE_UNKNOWN, _("negate: Failed to parse input"));
65 }
66
67 negate_config config = tmp_config.config;
68
69 char **command_line = config.command_line;
65 70
66 /* Set signal handling and alarm */ 71 /* Set signal handling and alarm */
67 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) 72 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
68 die(STATE_UNKNOWN, _("Cannot catch SIGALRM")); 73 die(STATE_UNKNOWN, _("Cannot catch SIGALRM"));
74 }
69 75
70 (void)alarm((unsigned)timeout_interval); 76 (void)alarm(timeout_interval);
71 77
72 int result = STATE_UNKNOWN; 78 mp_state_enum result = STATE_UNKNOWN;
73 output chld_out; 79 output chld_out;
74 output chld_err; 80 output chld_err;
75 81
@@ -86,46 +92,54 @@ int main(int argc, char **argv) {
86 } 92 }
87 93
88 /* Return UNKNOWN or worse if no output is returned */ 94 /* Return UNKNOWN or worse if no output is returned */
89 if (chld_out.lines == 0) 95 if (chld_out.lines == 0) {
90 die(max_state_alt(result, STATE_UNKNOWN), _("No data returned from command\n")); 96 die(max_state_alt(result, STATE_UNKNOWN), _("No data returned from command\n"));
97 }
91 98
92 char *sub; 99 char *sub;
93 for (size_t i = 0; i < chld_out.lines; i++) { 100 for (size_t i = 0; i < chld_out.lines; i++) {
94 if (subst_text && result >= 0 && result <= 4 && result != state[result]) { 101 if (config.subst_text && result >= 0 && result <= 4 && result != config.state[result]) {
95 /* Loop over each match found */ 102 /* Loop over each match found */
96 while ((sub = strstr(chld_out.line[i], state_text(result)))) { 103 while ((sub = strstr(chld_out.line[i], state_text(result)))) {
97 /* Terminate the first part and skip over the string we'll substitute */ 104 /* Terminate the first part and skip over the string we'll substitute */
98 *sub = '\0'; 105 *sub = '\0';
99 sub += strlen(state_text(result)); 106 sub += strlen(state_text(result));
100 /* then put everything back together */ 107 /* then put everything back together */
101 xasprintf(&chld_out.line[i], "%s%s%s", chld_out.line[i], state_text(state[result]), sub); 108 xasprintf(&chld_out.line[i], "%s%s%s", chld_out.line[i],
109 state_text(config.state[result]), sub);
102 } 110 }
103 } 111 }
104 printf("%s\n", chld_out.line[i]); 112 printf("%s\n", chld_out.line[i]);
105 } 113 }
106 114
107 if (result >= 0 && result <= 4) { 115 if (result >= 0 && result <= 4) {
108 exit(state[result]); 116 exit(config.state[result]);
109 } else { 117 } else {
110 exit(result); 118 exit(result);
111 } 119 }
112} 120}
113 121
114/* process command-line arguments */ 122/* process command-line arguments */
115static const char **process_arguments(int argc, char **argv) { 123static negate_config_wrapper process_arguments(int argc, char **argv) {
116 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, 124 static struct option longopts[] = {
117 {"timeout", required_argument, 0, 't'}, {"timeout-result", required_argument, 0, 'T'}, 125 {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'},
118 {"ok", required_argument, 0, 'o'}, {"warning", required_argument, 0, 'w'}, 126 {"timeout", required_argument, 0, 't'}, {"timeout-result", required_argument, 0, 'T'},
119 {"critical", required_argument, 0, 'c'}, {"unknown", required_argument, 0, 'u'}, 127 {"ok", required_argument, 0, 'o'}, {"warning", required_argument, 0, 'w'},
120 {"substitute", no_argument, 0, 's'}, {0, 0, 0, 0}}; 128 {"critical", required_argument, 0, 'c'}, {"unknown", required_argument, 0, 'u'},
121 129 {"substitute", no_argument, 0, 's'}, {0, 0, 0, 0}};
130
131 negate_config_wrapper result = {
132 .errorcode = OK,
133 .config = negate_config_init(),
134 };
122 bool permute = true; 135 bool permute = true;
123 while (true) { 136 while (true) {
124 int option = 0; 137 int option = 0;
125 int option_char = getopt_long(argc, argv, "+hVt:T:o:w:c:u:s", longopts, &option); 138 int option_char = getopt_long(argc, argv, "+hVt:T:o:w:c:u:s", longopts, &option);
126 139
127 if (option_char == -1 || option_char == EOF) 140 if (option_char == -1 || option_char == EOF) {
128 break; 141 break;
142 }
129 143
130 switch (option_char) { 144 switch (option_char) {
131 case '?': /* help */ 145 case '?': /* help */
@@ -139,58 +153,74 @@ static const char **process_arguments(int argc, char **argv) {
139 print_revision(progname, NP_VERSION); 153 print_revision(progname, NP_VERSION);
140 exit(STATE_UNKNOWN); 154 exit(STATE_UNKNOWN);
141 case 't': /* timeout period */ 155 case 't': /* timeout period */
142 if (!is_integer(optarg)) 156 if (!is_integer(optarg)) {
143 usage2(_("Timeout interval must be a positive integer"), optarg); 157 usage2(_("Timeout interval must be a positive integer"), optarg);
144 else 158 } else {
145 timeout_interval = atoi(optarg); 159 timeout_interval = atoi(optarg);
160 }
146 break; 161 break;
147 case 'T': /* Result to return on timeouts */ 162 case 'T': /* Result to return on timeouts */
148 if ((timeout_state = mp_translate_state(optarg)) == ERROR) 163 if ((timeout_state = mp_translate_state(optarg)) == ERROR) {
149 usage4(_("Timeout result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 164 usage4(_("Timeout result must be a valid state name (OK, WARNING, CRITICAL, "
165 "UNKNOWN) or integer (0-3)."));
166 }
150 break; 167 break;
151 case 'o': /* replacement for OK */ 168 case 'o': /* replacement for OK */
152 if ((state[STATE_OK] = mp_translate_state(optarg)) == ERROR) 169 if ((result.config.state[STATE_OK] = mp_translate_state(optarg)) == ERROR) {
153 usage4(_("Ok must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 170 usage4(_("Ok must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or "
171 "integer (0-3)."));
172 }
154 permute = false; 173 permute = false;
155 break; 174 break;
156 175
157 case 'w': /* replacement for WARNING */ 176 case 'w': /* replacement for WARNING */
158 if ((state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR) 177 if ((result.config.state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR) {
159 usage4(_("Warning must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 178 usage4(_("Warning must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or "
179 "integer (0-3)."));
180 }
160 permute = false; 181 permute = false;
161 break; 182 break;
162 case 'c': /* replacement for CRITICAL */ 183 case 'c': /* replacement for CRITICAL */
163 if ((state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR) 184 if ((result.config.state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR) {
164 usage4(_("Critical must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 185 usage4(_("Critical must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or "
186 "integer (0-3)."));
187 }
165 permute = false; 188 permute = false;
166 break; 189 break;
167 case 'u': /* replacement for UNKNOWN */ 190 case 'u': /* replacement for UNKNOWN */
168 if ((state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR) 191 if ((result.config.state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR) {
169 usage4(_("Unknown must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 192 usage4(_("Unknown must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or "
193 "integer (0-3)."));
194 }
170 permute = false; 195 permute = false;
171 break; 196 break;
172 case 's': /* Substitute status text */ 197 case 's': /* Substitute status text */
173 subst_text = true; 198 result.config.subst_text = true;
174 break; 199 break;
175 } 200 }
176 } 201 }
177 202
178 validate_arguments(&argv[optind]);
179
180 if (permute) { /* No [owcu] switch specified, default to this */ 203 if (permute) { /* No [owcu] switch specified, default to this */
181 state[STATE_OK] = STATE_CRITICAL; 204 result.config.state[STATE_OK] = STATE_CRITICAL;
182 state[STATE_CRITICAL] = STATE_OK; 205 result.config.state[STATE_CRITICAL] = STATE_OK;
183 } 206 }
184 207
185 return (const char **)&argv[optind]; 208 result.config.command_line = &argv[optind];
209
210 return validate_arguments(result);
186} 211}
187 212
188void validate_arguments(char **command_line) { 213negate_config_wrapper validate_arguments(negate_config_wrapper config_wrapper) {
189 if (command_line[0] == NULL) 214 if (config_wrapper.config.command_line[0] == NULL) {
190 usage4(_("Could not parse arguments")); 215 usage4(_("Could not parse arguments"));
216 }
191 217
192 if (strncmp(command_line[0], "/", 1) != 0 && strncmp(command_line[0], "./", 2) != 0) 218 if (strncmp(config_wrapper.config.command_line[0], "/", 1) != 0 &&
219 strncmp(config_wrapper.config.command_line[0], "./", 2) != 0) {
193 usage4(_("Require path to command")); 220 usage4(_("Require path to command"));
221 }
222
223 return config_wrapper;
194} 224}
195 225
196void print_help(void) { 226void print_help(void) {
@@ -198,7 +228,8 @@ void print_help(void) {
198 228
199 printf(COPYRIGHT, copyright, email); 229 printf(COPYRIGHT, copyright, email);
200 230
201 printf("%s\n", _("Negates only the return code of a plugin (returns OK for CRITICAL and vice-versa) by default.")); 231 printf("%s\n", _("Negates only the return code of a plugin (returns OK for CRITICAL and "
232 "vice-versa) by default."));
202 printf("%s\n", _("Additional switches can be used to control:\n")); 233 printf("%s\n", _("Additional switches can be used to control:\n"));
203 printf("\t - which state becomes what\n"); 234 printf("\t - which state becomes what\n");
204 printf("\t - changing the plugin output text to match the return code"); 235 printf("\t - changing the plugin output text to match the return code");
@@ -228,17 +259,20 @@ void print_help(void) {
228 printf("%s\n", _("Examples:")); 259 printf("%s\n", _("Examples:"));
229 printf(" %s\n", "negate /usr/local/nagios/libexec/check_ping -H host"); 260 printf(" %s\n", "negate /usr/local/nagios/libexec/check_ping -H host");
230 printf(" %s\n", _("Run check_ping and invert result. Must use full path to plugin")); 261 printf(" %s\n", _("Run check_ping and invert result. Must use full path to plugin"));
231 printf(" %s\n", "negate -w OK -c UNKNOWN /usr/local/nagios/libexec/check_procs -a 'vi negate.c'"); 262 printf(" %s\n",
263 "negate -w OK -c UNKNOWN /usr/local/nagios/libexec/check_procs -a 'vi negate.c'");
232 printf(" %s\n", _("This will return OK instead of WARNING and UNKNOWN instead of CRITICAL")); 264 printf(" %s\n", _("This will return OK instead of WARNING and UNKNOWN instead of CRITICAL"));
233 printf("\n"); 265 printf("\n");
234 printf("%s\n", _("Notes:")); 266 printf("%s\n", _("Notes:"));
235 printf(" %s\n", _("This plugin is a wrapper to take the output of another plugin and invert it.")); 267 printf(" %s\n",
268 _("This plugin is a wrapper to take the output of another plugin and invert it."));
236 printf(" %s\n", _("The full path of the plugin must be provided.")); 269 printf(" %s\n", _("The full path of the plugin must be provided."));
237 printf(" %s\n", _("If the wrapped plugin returns OK, the wrapper will return CRITICAL.")); 270 printf(" %s\n", _("If the wrapped plugin returns OK, the wrapper will return CRITICAL."));
238 printf(" %s\n", _("If the wrapped plugin returns CRITICAL, the wrapper will return OK.")); 271 printf(" %s\n", _("If the wrapped plugin returns CRITICAL, the wrapper will return OK."));
239 printf(" %s\n", _("Otherwise, the output state of the wrapped plugin is unchanged.")); 272 printf(" %s\n", _("Otherwise, the output state of the wrapped plugin is unchanged."));
240 printf("\n"); 273 printf("\n");
241 printf(" %s\n", _("Using timeout-result, it is possible to override the timeout behaviour or a")); 274 printf(" %s\n",
275 _("Using timeout-result, it is possible to override the timeout behaviour or a"));
242 printf(" %s\n", _("plugin by setting the negate timeout a bit lower.")); 276 printf(" %s\n", _("plugin by setting the negate timeout a bit lower."));
243 277
244 printf(UT_SUPPORT); 278 printf(UT_SUPPORT);
diff --git a/plugins/negate.d/config.h b/plugins/negate.d/config.h
new file mode 100644
index 00000000..0cf30cd4
--- /dev/null
+++ b/plugins/negate.d/config.h
@@ -0,0 +1,24 @@
1#pragma once
2
3#include "states.h"
4
5typedef struct {
6 mp_state_enum state[4];
7 bool subst_text;
8 char **command_line;
9} negate_config;
10
11negate_config negate_config_init() {
12 negate_config tmp = {
13 .state =
14 {
15 STATE_OK,
16 STATE_WARNING,
17 STATE_CRITICAL,
18 STATE_UNKNOWN,
19 },
20 .subst_text = false,
21 .command_line = NULL,
22 };
23 return tmp;
24}
diff --git a/plugins/netutils.c b/plugins/netutils.c
index e2916c65..b4c6ff0a 100644
--- a/plugins/netutils.c
+++ b/plugins/netutils.c
@@ -30,13 +30,14 @@
30#include "common.h" 30#include "common.h"
31#include "output.h" 31#include "output.h"
32#include "states.h" 32#include "states.h"
33#include <sys/types.h>
33#include "netutils.h" 34#include "netutils.h"
34 35
35unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT; 36unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT;
36unsigned int socket_timeout_state = STATE_CRITICAL; 37mp_state_enum socket_timeout_state = STATE_CRITICAL;
37 38mp_state_enum econn_refuse_state = STATE_CRITICAL;
38int econn_refuse_state = STATE_CRITICAL;
39bool was_refused = false; 39bool was_refused = false;
40
40#if USE_IPV6 41#if USE_IPV6
41int address_family = AF_UNSPEC; 42int address_family = AF_UNSPEC;
42#else 43#else
@@ -63,38 +64,40 @@ void socket_timeout_alarm_handler(int sig) {
63/* connects to a host on a specified tcp port, sends a string, and gets a 64/* connects to a host on a specified tcp port, sends a string, and gets a
64 response. loops on select-recv until timeout or eof to get all of a 65 response. loops on select-recv until timeout or eof to get all of a
65 multi-packet answer */ 66 multi-packet answer */
66int process_tcp_request2(const char *server_address, int server_port, const char *send_buffer, char *recv_buffer, int recv_size) { 67mp_state_enum process_tcp_request2(const char *server_address, const int server_port,
68 const char *send_buffer, char *recv_buffer,
69 const int recv_size) {
67 70
68 int result; 71 int socket;
69 int send_result;
70 int recv_result;
71 int sd;
72 struct timeval tv;
73 fd_set readfds;
74 int recv_length = 0;
75 72
76 result = np_net_connect(server_address, server_port, &sd, IPPROTO_TCP); 73 mp_state_enum connect_result =
77 if (result != STATE_OK) { 74 np_net_connect(server_address, server_port, &socket, IPPROTO_TCP);
75 if (connect_result != STATE_OK) {
78 return STATE_CRITICAL; 76 return STATE_CRITICAL;
79 } 77 }
80 78
81 send_result = send(sd, send_buffer, strlen(send_buffer), 0); 79 mp_state_enum result;
80 ssize_t send_result = send(socket, send_buffer, strlen(send_buffer), 0);
82 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) { 81 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
83 // printf("%s\n", _("Send failed")); 82 // printf("%s\n", _("Send failed"));
84 result = STATE_WARNING; 83 result = STATE_WARNING;
85 } 84 }
86 85
87 while (1) { 86 fd_set readfds;
87 ssize_t recv_length = 0;
88 while (true) {
88 /* wait up to the number of seconds for socket timeout 89 /* wait up to the number of seconds for socket timeout
89 minus one for data from the host */ 90 minus one for data from the host */
90 tv.tv_sec = socket_timeout - 1; 91 struct timeval timeout = {
91 tv.tv_usec = 0; 92 .tv_sec = socket_timeout - 1,
93 .tv_usec = 0,
94 };
92 FD_ZERO(&readfds); 95 FD_ZERO(&readfds);
93 FD_SET(sd, &readfds); 96 FD_SET(socket, &readfds);
94 select(sd + 1, &readfds, NULL, NULL, &tv); 97 select(socket + 1, &readfds, NULL, NULL, &timeout);
95 98
96 /* make sure some data has arrived */ 99 /* make sure some data has arrived */
97 if (!FD_ISSET(sd, &readfds)) { /* it hasn't */ 100 if (!FD_ISSET(socket, &readfds)) { /* it hasn't */
98 if (!recv_length) { 101 if (!recv_length) {
99 strcpy(recv_buffer, ""); 102 strcpy(recv_buffer, "");
100 // printf("%s\n", _("No data was received from host!")); 103 // printf("%s\n", _("No data was received from host!"));
@@ -103,70 +106,69 @@ int process_tcp_request2(const char *server_address, int server_port, const char
103 recv_buffer[recv_length] = 0; 106 recv_buffer[recv_length] = 0;
104 } 107 }
105 break; 108 break;
106 } else { /* it has */ 109 } /* it has */
107 recv_result = recv(sd, recv_buffer + recv_length, (size_t)recv_size - recv_length - 1, 0); 110
108 if (recv_result == -1) { 111 ssize_t recv_result =
109 /* recv failed, bail out */ 112 recv(socket, recv_buffer + recv_length, (size_t)(recv_size - recv_length - 1), 0);
110 strcpy(recv_buffer + recv_length, ""); 113 if (recv_result == -1) {
111 result = STATE_WARNING; 114 /* recv failed, bail out */
112 break; 115 strcpy(recv_buffer + recv_length, "");
113 } else if (recv_result == 0) { 116 result = STATE_WARNING;
114 /* end of file ? */ 117 break;
115 recv_buffer[recv_length] = 0; 118 }
116 break; 119
117 } else { /* we got data! */ 120 if (recv_result == 0) {
118 recv_length += recv_result; 121 /* end of file ? */
119 if (recv_length >= recv_size - 1) { 122 recv_buffer[recv_length] = 0;
120 /* buffer full, we're done */ 123 break;
121 recv_buffer[recv_size - 1] = 0; 124 }
122 break; 125
123 } 126 /* we got data! */
124 } 127 recv_length += recv_result;
128 if (recv_length >= recv_size - 1) {
129 /* buffer full, we're done */
130 recv_buffer[recv_size - 1] = 0;
131 break;
125 } 132 }
126 /* end if(!FD_ISSET(sd,&readfds)) */ 133 /* end if(!FD_ISSET(sd,&readfds)) */
127 } 134 }
128 /* end while(1) */
129 135
130 close(sd); 136 close(socket);
131 return result; 137 return result;
132} 138}
133 139
134/* connects to a host on a specified port, sends a string, and gets a 140/* connects to a host on a specified port, sends a string, and gets a
135 response */ 141 response */
136int process_request(const char *server_address, int server_port, int proto, const char *send_buffer, char *recv_buffer, int recv_size) { 142mp_state_enum process_request(const char *server_address, const int server_port, const int proto,
137 int result; 143 const char *send_buffer, char *recv_buffer, const int recv_size) {
138 int sd;
139 144
140 result = STATE_OK; 145 mp_state_enum result = STATE_OK;
141 146 int socket;
142 result = np_net_connect(server_address, server_port, &sd, proto); 147 result = np_net_connect(server_address, server_port, &socket, proto);
143 if (result != STATE_OK) { 148 if (result != STATE_OK) {
144 return STATE_CRITICAL; 149 return STATE_CRITICAL;
145 } 150 }
146 151
147 result = send_request(sd, proto, send_buffer, recv_buffer, recv_size); 152 result = send_request(socket, proto, send_buffer, recv_buffer, recv_size);
148 153
149 close(sd); 154 close(socket);
150 155
151 return result; 156 return result;
152} 157}
153 158
154/* opens a tcp or udp connection to a remote host or local socket */ 159/* opens a tcp or udp connection to a remote host or local socket */
155int np_net_connect(const char *host_name, int port, int *sd, int proto) { 160mp_state_enum np_net_connect(const char *host_name, int port, int *socketDescriptor,
161 const int proto) {
156 /* send back STATE_UNKOWN if there's an error 162 /* send back STATE_UNKOWN if there's an error
157 send back STATE_OK if we connect 163 send back STATE_OK if we connect
158 send back STATE_CRITICAL if we can't connect. 164 send back STATE_CRITICAL if we can't connect.
159 Let upstream figure out what to send to the user. */ 165 Let upstream figure out what to send to the user. */
160 struct addrinfo hints; 166 bool is_socket = (host_name[0] == '/');
161 struct addrinfo *r, *res; 167 int socktype = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
162 struct sockaddr_un su;
163 char port_str[6], host[MAX_HOST_ADDRESS_LENGTH];
164 size_t len;
165 int socktype, result;
166 short is_socket = (host_name[0] == '/');
167
168 socktype = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
169 168
169 struct addrinfo hints = {};
170 struct addrinfo *res = NULL;
171 int result;
170 /* as long as it doesn't start with a '/', it's assumed a host or ip */ 172 /* as long as it doesn't start with a '/', it's assumed a host or ip */
171 if (!is_socket) { 173 if (!is_socket) {
172 memset(&hints, 0, sizeof(hints)); 174 memset(&hints, 0, sizeof(hints));
@@ -174,38 +176,46 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
174 hints.ai_protocol = proto; 176 hints.ai_protocol = proto;
175 hints.ai_socktype = socktype; 177 hints.ai_socktype = socktype;
176 178
177 len = strlen(host_name); 179 size_t len = strlen(host_name);
178 /* check for an [IPv6] address (and strip the brackets) */ 180 /* check for an [IPv6] address (and strip the brackets) */
179 if (len >= 2 && host_name[0] == '[' && host_name[len - 1] == ']') { 181 if (len >= 2 && host_name[0] == '[' && host_name[len - 1] == ']') {
180 host_name++; 182 host_name++;
181 len -= 2; 183 len -= 2;
182 } 184 }
185
186 char host[MAX_HOST_ADDRESS_LENGTH];
187
183 if (len >= sizeof(host)) { 188 if (len >= sizeof(host)) {
184 return STATE_UNKNOWN; 189 return STATE_UNKNOWN;
185 } 190 }
191
186 memcpy(host, host_name, len); 192 memcpy(host, host_name, len);
187 host[len] = '\0'; 193 host[len] = '\0';
194
195 char port_str[6];
188 snprintf(port_str, sizeof(port_str), "%d", port); 196 snprintf(port_str, sizeof(port_str), "%d", port);
189 result = getaddrinfo(host, port_str, &hints, &res); 197 int getaddrinfo_err = getaddrinfo(host, port_str, &hints, &res);
190 198
191 if (result != 0) { 199 if (getaddrinfo_err != 0) {
192 // printf("%s\n", gai_strerror(result)); 200 // printf("%s\n", gai_strerror(result));
193 return STATE_UNKNOWN; 201 return STATE_UNKNOWN;
194 } 202 }
195 203
196 r = res; 204 struct addrinfo *addressPointer = res;
197 while (r) { 205 while (addressPointer) {
198 /* attempt to create a socket */ 206 /* attempt to create a socket */
199 *sd = socket(r->ai_family, socktype, r->ai_protocol); 207 *socketDescriptor =
208 socket(addressPointer->ai_family, socktype, addressPointer->ai_protocol);
200 209
201 if (*sd < 0) { 210 if (*socketDescriptor < 0) {
202 // printf("%s\n", _("Socket creation failed")); 211 // printf("%s\n", _("Socket creation failed"));
203 freeaddrinfo(r); 212 freeaddrinfo(addressPointer);
204 return STATE_UNKNOWN; 213 return STATE_UNKNOWN;
205 } 214 }
206 215
207 /* attempt to open a connection */ 216 /* attempt to open a connection */
208 result = connect(*sd, r->ai_addr, r->ai_addrlen); 217 result =
218 connect(*socketDescriptor, addressPointer->ai_addr, addressPointer->ai_addrlen);
209 219
210 if (result == 0) { 220 if (result == 0) {
211 was_refused = false; 221 was_refused = false;
@@ -220,24 +230,28 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
220 } 230 }
221 } 231 }
222 232
223 close(*sd); 233 close(*socketDescriptor);
224 r = r->ai_next; 234 addressPointer = addressPointer->ai_next;
225 } 235 }
236
226 freeaddrinfo(res); 237 freeaddrinfo(res);
227 } 238
228 /* else the hostname is interpreted as a path to a unix socket */ 239 } else {
229 else { 240 /* else the hostname is interpreted as a path to a unix socket */
230 if (strlen(host_name) >= UNIX_PATH_MAX) { 241 if (strlen(host_name) >= UNIX_PATH_MAX) {
231 die(STATE_UNKNOWN, _("Supplied path too long unix domain socket")); 242 die(STATE_UNKNOWN, _("Supplied path too long unix domain socket"));
232 } 243 }
233 memset(&su, 0, sizeof(su)); 244
245 struct sockaddr_un su = {};
234 su.sun_family = AF_UNIX; 246 su.sun_family = AF_UNIX;
235 strncpy(su.sun_path, host_name, UNIX_PATH_MAX); 247 strncpy(su.sun_path, host_name, UNIX_PATH_MAX);
236 *sd = socket(PF_UNIX, SOCK_STREAM, 0); 248 *socketDescriptor = socket(PF_UNIX, SOCK_STREAM, 0);
237 if (*sd < 0) { 249
250 if (*socketDescriptor < 0) {
238 die(STATE_UNKNOWN, _("Socket creation failed")); 251 die(STATE_UNKNOWN, _("Socket creation failed"));
239 } 252 }
240 result = connect(*sd, (struct sockaddr *)&su, sizeof(su)); 253
254 result = connect(*socketDescriptor, (struct sockaddr *)&su, sizeof(su));
241 if (result < 0 && errno == ECONNREFUSED) { 255 if (result < 0 && errno == ECONNREFUSED) {
242 was_refused = true; 256 was_refused = true;
243 } 257 }
@@ -245,7 +259,9 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
245 259
246 if (result == 0) { 260 if (result == 0) {
247 return STATE_OK; 261 return STATE_OK;
248 } else if (was_refused) { 262 }
263
264 if (was_refused) {
249 switch (econn_refuse_state) { /* a user-defined expected outcome */ 265 switch (econn_refuse_state) { /* a user-defined expected outcome */
250 case STATE_OK: 266 case STATE_OK:
251 case STATE_WARNING: /* user wants WARN or OK on refusal, or... */ 267 case STATE_WARNING: /* user wants WARN or OK on refusal, or... */
@@ -253,7 +269,8 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
253 if (is_socket) { 269 if (is_socket) {
254 // printf("connect to file socket %s: %s\n", host_name, strerror(errno)); 270 // printf("connect to file socket %s: %s\n", host_name, strerror(errno));
255 } else { 271 } else {
256 // printf("connect to address %s and port %d: %s\n", host_name, port, strerror(errno)); 272 // printf("connect to address %s and port %d: %s\n", host_name, port,
273 // strerror(errno));
257 } 274 }
258 return STATE_CRITICAL; 275 return STATE_CRITICAL;
259 break; 276 break;
@@ -271,14 +288,11 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
271 } 288 }
272} 289}
273 290
274int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer, int recv_size) { 291mp_state_enum send_request(const int socket, const int proto, const char *send_buffer,
275 int result = STATE_OK; 292 char *recv_buffer, const int recv_size) {
276 int send_result; 293 mp_state_enum result = STATE_OK;
277 int recv_result;
278 struct timeval tv;
279 fd_set readfds;
280 294
281 send_result = send(sd, send_buffer, strlen(send_buffer), 0); 295 ssize_t send_result = send(socket, send_buffer, strlen(send_buffer), 0);
282 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) { 296 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
283 // printf("%s\n", _("Send failed")); 297 // printf("%s\n", _("Send failed"));
284 result = STATE_WARNING; 298 result = STATE_WARNING;
@@ -286,21 +300,22 @@ int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer,
286 300
287 /* wait up to the number of seconds for socket timeout minus one 301 /* wait up to the number of seconds for socket timeout minus one
288 for data from the host */ 302 for data from the host */
289 tv.tv_sec = socket_timeout - 1; 303 struct timeval timestamp = {
290 tv.tv_usec = 0; 304 .tv_sec = socket_timeout - 1,
305 .tv_usec = 0,
306 };
307 fd_set readfds;
291 FD_ZERO(&readfds); 308 FD_ZERO(&readfds);
292 FD_SET(sd, &readfds); 309 FD_SET(socket, &readfds);
293 select(sd + 1, &readfds, NULL, NULL, &tv); 310 select(socket + 1, &readfds, NULL, NULL, &timestamp);
294 311
295 /* make sure some data has arrived */ 312 /* make sure some data has arrived */
296 if (!FD_ISSET(sd, &readfds)) { 313 if (!FD_ISSET(socket, &readfds)) {
297 strcpy(recv_buffer, ""); 314 strcpy(recv_buffer, "");
298 // printf("%s\n", _("No data was received from host!")); 315 // printf("%s\n", _("No data was received from host!"));
299 result = STATE_WARNING; 316 result = STATE_WARNING;
300 } 317 } else {
301 318 ssize_t recv_result = recv(socket, recv_buffer, (size_t)(recv_size - 1), 0);
302 else {
303 recv_result = recv(sd, recv_buffer, (size_t)recv_size - 1, 0);
304 if (recv_result == -1) { 319 if (recv_result == -1) {
305 strcpy(recv_buffer, ""); 320 strcpy(recv_buffer, "");
306 if (proto != IPPROTO_TCP) { 321 if (proto != IPPROTO_TCP) {
@@ -314,6 +329,7 @@ int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer,
314 /* die returned string */ 329 /* die returned string */
315 recv_buffer[recv_size - 1] = 0; 330 recv_buffer[recv_size - 1] = 0;
316 } 331 }
332
317 return result; 333 return result;
318} 334}
319 335
@@ -335,27 +351,27 @@ bool is_addr(const char *address) {
335#ifdef USE_IPV6 351#ifdef USE_IPV6
336 if (address_family == AF_INET && is_inet_addr(address)) { 352 if (address_family == AF_INET && is_inet_addr(address)) {
337 return true; 353 return true;
338 } else if (address_family == AF_INET6 && is_inet6_addr(address)) { 354 }
355
356 if (address_family == AF_INET6 && is_inet6_addr(address)) {
339 return true; 357 return true;
340 } 358 }
341#else 359#else
342 if (is_inet_addr(address)) { 360 if (is_inet_addr(address)) {
343 return (true); 361 return true;
344 } 362 }
345#endif 363#endif
346 364
347 return (false); 365 return false;
348} 366}
349 367
350int dns_lookup(const char *in, struct sockaddr_storage *ss, int family) { 368bool dns_lookup(const char *node_string, struct sockaddr_storage *ss, const int family) {
351 struct addrinfo hints; 369 struct addrinfo hints;
352 struct addrinfo *res;
353 int retval;
354
355 memset(&hints, 0, sizeof(struct addrinfo)); 370 memset(&hints, 0, sizeof(struct addrinfo));
356 hints.ai_family = family; 371 hints.ai_family = family;
357 372
358 retval = getaddrinfo(in, NULL, &hints, &res); 373 struct addrinfo *res;
374 int retval = getaddrinfo(node_string, NULL, &hints, &res);
359 if (retval != 0) { 375 if (retval != 0) {
360 return false; 376 return false;
361 } 377 }
@@ -363,6 +379,8 @@ int dns_lookup(const char *in, struct sockaddr_storage *ss, int family) {
363 if (ss != NULL) { 379 if (ss != NULL) {
364 memcpy(ss, res->ai_addr, res->ai_addrlen); 380 memcpy(ss, res->ai_addr, res->ai_addrlen);
365 } 381 }
382
366 freeaddrinfo(res); 383 freeaddrinfo(res);
384
367 return true; 385 return true;
368} 386}
diff --git a/plugins/netutils.h b/plugins/netutils.h
index a95057e0..dbd22398 100644
--- a/plugins/netutils.h
+++ b/plugins/netutils.h
@@ -1,120 +1,140 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring Plugins net utilities include file 3 * Monitoring Plugins net utilities include file
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999 Ethan Galstad (nagios@nagios.org) 6 * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
7* Copyright (c) 2003-2007 Monitoring Plugins Development Team 7 * Copyright (c) 2003-2007 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains common include files and function definitions 11 * This file contains common include files and function definitions
12* used in many of the plugins. 12 * used in many of the plugins.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31#ifndef _NETUTILS_H_ 31#ifndef _NETUTILS_H_
32#define _NETUTILS_H_ 32#define _NETUTILS_H_
33 33
34#include "common.h" 34#include "output.h"
35#include "states.h"
35#include "utils.h" 36#include "utils.h"
36#include <netinet/in.h> 37#include <netinet/in.h>
37#include <arpa/inet.h> 38#include <arpa/inet.h>
38#include <netdb.h> 39#include <netdb.h>
39 40
40#ifdef HAVE_SYS_UN_H 41#ifdef HAVE_SYS_UN_H
41# include <sys/un.h> 42# include <sys/un.h>
42# ifndef UNIX_PATH_MAX 43# ifndef UNIX_PATH_MAX
43 /* linux uses this, on sun it's hard-coded at 108 without a define, on BSD at 104 */ 44/* linux uses this, on sun it's hard-coded at 108 without a define, on BSD at 104 */
44# define UNIX_PATH_MAX 104 45# define UNIX_PATH_MAX 104
45# endif /* UNIX_PATH_MAX */ 46# endif /* UNIX_PATH_MAX */
46#endif /* HAVE_SYS_UN_H */ 47#endif /* HAVE_SYS_UN_H */
47 48
48#ifndef HOST_MAX_BYTES 49#ifndef HOST_MAX_BYTES
49# define HOST_MAX_BYTES 255 50# define HOST_MAX_BYTES 255
50#endif 51#endif
51 52
52/* process_request and wrapper macros */ 53/* process_request and wrapper macros */
53#define process_tcp_request(addr, port, sbuf, rbuf, rsize) \ 54#define process_tcp_request(addr, port, sbuf, rbuf, rsize) \
54 process_request(addr, port, IPPROTO_TCP, sbuf, rbuf, rsize) 55 process_request(addr, port, IPPROTO_TCP, sbuf, rbuf, rsize)
55#define process_udp_request(addr, port, sbuf, rbuf, rsize) \ 56#define process_udp_request(addr, port, sbuf, rbuf, rsize) \
56 process_request(addr, port, IPPROTO_UDP, sbuf, rbuf, rsize) 57 process_request(addr, port, IPPROTO_UDP, sbuf, rbuf, rsize)
57int process_tcp_request2 (const char *address, int port, 58mp_state_enum process_tcp_request2(const char *server_address, int server_port,
58 const char *sbuffer, char *rbuffer, int rsize); 59 const char *send_buffer, char *recv_buffer, int recv_size);
59int process_request (const char *address, int port, int proto, 60mp_state_enum process_request(const char *server_address, int server_port, int proto,
60 const char *sbuffer, char *rbuffer, int rsize); 61 const char *send_buffer, char *recv_buffer, int recv_size);
61 62
62/* my_connect and wrapper macros */ 63/* my_connect and wrapper macros */
63#define my_tcp_connect(addr, port, s) np_net_connect(addr, port, s, IPPROTO_TCP) 64#define my_tcp_connect(addr, port, s) np_net_connect(addr, port, s, IPPROTO_TCP)
64#define my_udp_connect(addr, port, s) np_net_connect(addr, port, s, IPPROTO_UDP) 65#define my_udp_connect(addr, port, s) np_net_connect(addr, port, s, IPPROTO_UDP)
65int np_net_connect(const char *address, int port, int *sd, int proto); 66mp_state_enum np_net_connect(const char *host_name, int port, int *socketDescriptor, int proto);
66 67
67/* send_request and wrapper macros */ 68/* send_request and wrapper macros */
68#define send_tcp_request(s, sbuf, rbuf, rsize) \ 69#define send_tcp_request(s, sbuf, rbuf, rsize) send_request(s, IPPROTO_TCP, sbuf, rbuf, rsize)
69 send_request(s, IPPROTO_TCP, sbuf, rbuf, rsize) 70#define send_udp_request(s, sbuf, rbuf, rsize) send_request(s, IPPROTO_UDP, sbuf, rbuf, rsize)
70#define send_udp_request(s, sbuf, rbuf, rsize) \ 71mp_state_enum send_request(int socket, int proto, const char *send_buffer, char *recv_buffer,
71 send_request(s, IPPROTO_UDP, sbuf, rbuf, rsize) 72 int recv_size);
72int send_request (int sd, int proto, const char *send_buffer, char *recv_buffer, int recv_size);
73
74 73
75/* "is_*" wrapper macros and functions */ 74/* "is_*" wrapper macros and functions */
76bool is_host (const char *); 75bool is_host(const char *);
77bool is_addr (const char *); 76bool is_addr(const char *);
78int dns_lookup (const char *, struct sockaddr_storage *, int); 77bool dns_lookup(const char *, struct sockaddr_storage *, int);
79void host_or_die(const char *str); 78void host_or_die(const char *str);
80#define resolve_host_or_addr(addr, family) dns_lookup(addr, NULL, family) 79#define resolve_host_or_addr(addr, family) dns_lookup(addr, NULL, family)
81#define is_inet_addr(addr) resolve_host_or_addr(addr, AF_INET) 80#define is_inet_addr(addr) resolve_host_or_addr(addr, AF_INET)
82#ifdef USE_IPV6 81#ifdef USE_IPV6
83# define is_inet6_addr(addr) resolve_host_or_addr(addr, AF_INET6) 82# define is_inet6_addr(addr) resolve_host_or_addr(addr, AF_INET6)
84# define is_hostname(addr) resolve_host_or_addr(addr, address_family) 83# define is_hostname(addr) resolve_host_or_addr(addr, address_family)
85#else 84#else
86# define is_hostname(addr) resolve_host_or_addr(addr, AF_INET) 85# define is_hostname(addr) resolve_host_or_addr(addr, AF_INET)
87#endif 86#endif
88 87
89extern unsigned int socket_timeout; 88extern unsigned int socket_timeout;
90extern unsigned int socket_timeout_state; 89extern mp_state_enum socket_timeout_state;
91extern int econn_refuse_state; 90extern mp_state_enum econn_refuse_state;
92extern bool was_refused; 91extern bool was_refused;
93extern int address_family; 92extern int address_family;
94 93
95void socket_timeout_alarm_handler (int) __attribute__((noreturn)); 94void socket_timeout_alarm_handler(int) __attribute__((noreturn));
96 95
97/* SSL-Related functionality */ 96/* SSL-Related functionality */
98#ifdef HAVE_SSL 97#ifdef HAVE_SSL
99# define MP_SSLv2 1 98# define MP_SSLv2 1
100# define MP_SSLv3 2 99# define MP_SSLv3 2
101# define MP_TLSv1 3 100# define MP_TLSv1 3
102# define MP_TLSv1_1 4 101# define MP_TLSv1_1 4
103# define MP_TLSv1_2 5 102# define MP_TLSv1_2 5
104# define MP_SSLv2_OR_NEWER 6 103# define MP_SSLv2_OR_NEWER 6
105# define MP_SSLv3_OR_NEWER 7 104# define MP_SSLv3_OR_NEWER 7
106# define MP_TLSv1_OR_NEWER 8 105# define MP_TLSv1_OR_NEWER 8
107# define MP_TLSv1_1_OR_NEWER 9 106# define MP_TLSv1_1_OR_NEWER 9
108# define MP_TLSv1_2_OR_NEWER 10 107# define MP_TLSv1_2_OR_NEWER 10
109/* maybe this could be merged with the above np_net_connect, via some flags */ 108/* maybe this could be merged with the above np_net_connect, via some flags */
110int np_net_ssl_init(int sd); 109int np_net_ssl_init(int socket);
111int np_net_ssl_init_with_hostname(int sd, char *host_name); 110int np_net_ssl_init_with_hostname(int socket, char *host_name);
112int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version); 111int np_net_ssl_init_with_hostname_and_version(int socket, char *host_name, int version);
113int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int version, char *cert, char *privkey); 112int np_net_ssl_init_with_hostname_version_and_cert(int socket, char *host_name, int version,
114void np_net_ssl_cleanup(); 113 char *cert, char *privkey);
114void np_net_ssl_cleanup(void);
115int np_net_ssl_write(const void *buf, int num); 115int np_net_ssl_write(const void *buf, int num);
116int np_net_ssl_read(void *buf, int num); 116int np_net_ssl_read(void *buf, int num);
117int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit);
118#endif /* HAVE_SSL */
119 117
118typedef enum {
119 ALL_OK,
120 NO_SERVER_CERTIFICATE_PRESENT,
121 UNABLE_TO_RETRIEVE_CERTIFICATE_SUBJECT,
122 WRONG_TIME_FORMAT_IN_CERTIFICATE,
123} retrieve_expiration_date_errors;
124
125typedef struct {
126 double remaining_seconds;
127 retrieve_expiration_date_errors errors;
128} retrieve_expiration_time_result;
129
130typedef struct {
131 mp_state_enum result_state;
132 double remaining_seconds;
133 retrieve_expiration_date_errors errors;
134} net_ssl_check_cert_result;
135net_ssl_check_cert_result np_net_ssl_check_cert2(int days_till_exp_warn, int days_till_exp_crit);
136
137mp_state_enum np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit);
138mp_subcheck mp_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit);
139#endif /* HAVE_SSL */
120#endif /* _NETUTILS_H_ */ 140#endif /* _NETUTILS_H_ */
diff --git a/plugins/picohttpparser/picohttpparser.c b/plugins/picohttpparser/picohttpparser.c
index 2ae92d66..e87388b0 100644
--- a/plugins/picohttpparser/picohttpparser.c
+++ b/plugins/picohttpparser/picohttpparser.c
@@ -50,59 +50,61 @@
50# define ALIGNED(n) __attribute__((aligned(n))) 50# define ALIGNED(n) __attribute__((aligned(n)))
51#endif 51#endif
52 52
53#define IS_PRINTABLE_ASCII(c) ((unsigned char)(c)-040u < 0137u) 53#define IS_PRINTABLE_ASCII(c) ((unsigned char)(c) - 040u < 0137u)
54 54
55#define CHECK_EOF() \ 55#define CHECK_EOF() \
56 if (buf == buf_end) { \ 56 if (buf == buf_end) { \
57 *ret = -2; \ 57 *ret = -2; \
58 return NULL; \ 58 return NULL; \
59 } 59 }
60 60
61#define EXPECT_CHAR_NO_CHECK(ch) \ 61#define EXPECT_CHAR_NO_CHECK(ch) \
62 if (*buf++ != ch) { \ 62 if (*buf++ != ch) { \
63 *ret = -1; \ 63 *ret = -1; \
64 return NULL; \ 64 return NULL; \
65 } 65 }
66 66
67#define EXPECT_CHAR(ch) \ 67#define EXPECT_CHAR(ch) \
68 CHECK_EOF(); \ 68 CHECK_EOF(); \
69 EXPECT_CHAR_NO_CHECK(ch); 69 EXPECT_CHAR_NO_CHECK(ch);
70 70
71#define ADVANCE_TOKEN(tok, toklen) \ 71#define ADVANCE_TOKEN(tok, toklen) \
72 do { \ 72 do { \
73 const char *tok_start = buf; \ 73 const char *tok_start = buf; \
74 static const char ALIGNED(16) ranges2[16] = "\000\040\177\177"; \ 74 static const char ALIGNED(16) ranges2[16] = "\000\040\177\177"; \
75 int found2; \ 75 int found2; \
76 buf = findchar_fast(buf, buf_end, ranges2, 4, &found2); \ 76 buf = findchar_fast(buf, buf_end, ranges2, 4, &found2); \
77 if (!found2) { \ 77 if (!found2) { \
78 CHECK_EOF(); \ 78 CHECK_EOF(); \
79 } \ 79 } \
80 while (1) { \ 80 while (1) { \
81 if (*buf == ' ') { \ 81 if (*buf == ' ') { \
82 break; \ 82 break; \
83 } else if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { \ 83 } else if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { \
84 if ((unsigned char)*buf < '\040' || *buf == '\177') { \ 84 if ((unsigned char)*buf < '\040' || *buf == '\177') { \
85 *ret = -1; \ 85 *ret = -1; \
86 return NULL; \ 86 return NULL; \
87 } \ 87 } \
88 } \ 88 } \
89 ++buf; \ 89 ++buf; \
90 CHECK_EOF(); \ 90 CHECK_EOF(); \
91 } \ 91 } \
92 tok = tok_start; \ 92 tok = tok_start; \
93 toklen = buf - tok_start; \ 93 toklen = buf - tok_start; \
94 } while (0) 94 } while (0)
95 95
96static const char *token_char_map = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 96static const char *token_char_map =
97 "\0\1\0\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0" 97 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
98 "\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1" 98 "\0\1\0\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0"
99 "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0" 99 "\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1"
100 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 100 "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0"
101 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 101 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
102 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 102 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
103 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 103 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
104 104 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
105static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, size_t ranges_size, int *found) { 105
106static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges,
107 size_t ranges_size, int *found) {
106 *found = 0; 108 *found = 0;
107#if __SSE4_2__ 109#if __SSE4_2__
108 if (likely(buf_end - buf >= 16)) { 110 if (likely(buf_end - buf >= 16)) {
@@ -111,7 +113,8 @@ static const char *findchar_fast(const char *buf, const char *buf_end, const cha
111 size_t left = (buf_end - buf) & ~15; 113 size_t left = (buf_end - buf) & ~15;
112 do { 114 do {
113 __m128i b16 = _mm_loadu_si128((const __m128i *)buf); 115 __m128i b16 = _mm_loadu_si128((const __m128i *)buf);
114 int r = _mm_cmpestri(ranges16, ranges_size, b16, 16, _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS); 116 int r = _mm_cmpestri(ranges16, ranges_size, b16, 16,
117 _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS);
115 if (unlikely(r != 16)) { 118 if (unlikely(r != 16)) {
116 buf += r; 119 buf += r;
117 *found = 1; 120 *found = 1;
@@ -130,25 +133,29 @@ static const char *findchar_fast(const char *buf, const char *buf_end, const cha
130 return buf; 133 return buf;
131} 134}
132 135
133static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token, size_t *token_len, int *ret) { 136static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token,
137 size_t *token_len, int *ret) {
134 const char *token_start = buf; 138 const char *token_start = buf;
135 139
136#ifdef __SSE4_2__ 140#ifdef __SSE4_2__
137 static const char ALIGNED(16) ranges1[16] = "\0\010" /* allow HT */ 141 static const char ALIGNED(16) ranges1[16] =
138 "\012\037" /* allow SP and up to but not including DEL */ 142 "\0\010" /* allow HT */
139 "\177\177"; /* allow chars w. MSB set */ 143 "\012\037" /* allow SP and up to but not including DEL */
144 "\177\177"; /* allow chars w. MSB set */
140 int found; 145 int found;
141 buf = findchar_fast(buf, buf_end, ranges1, 6, &found); 146 buf = findchar_fast(buf, buf_end, ranges1, 6, &found);
142 if (found) 147 if (found) {
143 goto FOUND_CTL; 148 goto FOUND_CTL;
149 }
144#else 150#else
145 /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */ 151 /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined
152 */
146 while (likely(buf_end - buf >= 8)) { 153 while (likely(buf_end - buf >= 8)) {
147# define DOIT() \ 154# define DOIT() \
148 do { \ 155 do { \
149 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \ 156 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \
150 goto NonPrintable; \ 157 goto NonPrintable; \
151 ++buf; \ 158 ++buf; \
152 } while (0) 159 } while (0)
153 DOIT(); 160 DOIT();
154 DOIT(); 161 DOIT();
@@ -161,7 +168,8 @@ static const char *get_token_to_eol(const char *buf, const char *buf_end, const
161# undef DOIT 168# undef DOIT
162 continue; 169 continue;
163 NonPrintable: 170 NonPrintable:
164 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { 171 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) ||
172 unlikely(*buf == '\177')) {
165 goto FOUND_CTL; 173 goto FOUND_CTL;
166 } 174 }
167 ++buf; 175 ++buf;
@@ -170,7 +178,8 @@ static const char *get_token_to_eol(const char *buf, const char *buf_end, const
170 for (;; ++buf) { 178 for (;; ++buf) {
171 CHECK_EOF(); 179 CHECK_EOF();
172 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { 180 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) {
173 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { 181 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) ||
182 unlikely(*buf == '\177')) {
174 goto FOUND_CTL; 183 goto FOUND_CTL;
175 } 184 }
176 } 185 }
@@ -219,27 +228,28 @@ static const char *is_complete(const char *buf, const char *buf_end, size_t last
219 return NULL; 228 return NULL;
220} 229}
221 230
222#define PARSE_INT(valp_, mul_) \ 231#define PARSE_INT(valp_, mul_) \
223 if (*buf < '0' || '9' < *buf) { \ 232 if (*buf < '0' || '9' < *buf) { \
224 buf++; \ 233 buf++; \
225 *ret = -1; \ 234 *ret = -1; \
226 return NULL; \ 235 return NULL; \
227 } \ 236 } \
228 *(valp_) = (mul_) * (*buf++ - '0'); 237 *(valp_) = (mul_) * (*buf++ - '0');
229 238
230#define PARSE_INT_3(valp_) \ 239#define PARSE_INT_3(valp_) \
231 do { \ 240 do { \
232 int res_ = 0; \ 241 int res_ = 0; \
233 PARSE_INT(&res_, 100) \ 242 PARSE_INT(&res_, 100) \
234 *valp_ = res_; \ 243 *valp_ = res_; \
235 PARSE_INT(&res_, 10) \ 244 PARSE_INT(&res_, 10) \
236 *valp_ += res_; \ 245 *valp_ += res_; \
237 PARSE_INT(&res_, 1) \ 246 PARSE_INT(&res_, 1) \
238 *valp_ += res_; \ 247 *valp_ += res_; \
239 } while (0) 248 } while (0)
240 249
241/* returned pointer is always within [buf, buf_end), or null */ 250/* returned pointer is always within [buf, buf_end), or null */
242static const char *parse_http_version(const char *buf, const char *buf_end, int *major_version, int *minor_version, int *ret) { 251static const char *parse_http_version(const char *buf, const char *buf_end, int *major_version,
252 int *minor_version, int *ret) {
243 /* we want at least [HTTP/1.<two chars>] to try to parse */ 253 /* we want at least [HTTP/1.<two chars>] to try to parse */
244 if (buf_end - buf < 9) { 254 if (buf_end - buf < 9) {
245 *ret = -2; 255 *ret = -2;
@@ -260,8 +270,8 @@ static const char *parse_http_version(const char *buf, const char *buf_end, int
260 return buf; 270 return buf;
261} 271}
262 272
263static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers, size_t *num_headers, size_t max_headers, 273static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers,
264 int *ret) { 274 size_t *num_headers, size_t max_headers, int *ret) {
265 for (;; ++*num_headers) { 275 for (;; ++*num_headers) {
266 CHECK_EOF(); 276 CHECK_EOF();
267 if (*buf == '\015') { 277 if (*buf == '\015') {
@@ -337,9 +347,10 @@ static const char *parse_headers(const char *buf, const char *buf_end, struct ph
337 return buf; 347 return buf;
338} 348}
339 349
340static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len, const char **path, 350static const char *parse_request(const char *buf, const char *buf_end, const char **method,
341 size_t *path_len, int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, 351 size_t *method_len, const char **path, size_t *path_len,
342 size_t max_headers, int *ret) { 352 int *major_version, int *minor_version, struct phr_header *headers,
353 size_t *num_headers, size_t max_headers, int *ret) {
343 /* skip first empty line (some clients add CRLF after POST content) */ 354 /* skip first empty line (some clients add CRLF after POST content) */
344 CHECK_EOF(); 355 CHECK_EOF();
345 if (*buf == '\015') { 356 if (*buf == '\015') {
@@ -378,8 +389,9 @@ static const char *parse_request(const char *buf, const char *buf_end, const cha
378 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); 389 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret);
379} 390}
380 391
381int phr_parse_request(const char *buf_start, size_t len, const char **method, size_t *method_len, const char **path, size_t *path_len, 392int phr_parse_request(const char *buf_start, size_t len, const char **method, size_t *method_len,
382 int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len) { 393 const char **path, size_t *path_len, int *major_version, int *minor_version,
394 struct phr_header *headers, size_t *num_headers, size_t last_len) {
383 const char *buf = buf_start, *buf_end = buf_start + len; 395 const char *buf = buf_start, *buf_end = buf_start + len;
384 size_t max_headers = *num_headers; 396 size_t max_headers = *num_headers;
385 int r; 397 int r;
@@ -398,17 +410,18 @@ int phr_parse_request(const char *buf_start, size_t len, const char **method, si
398 return r; 410 return r;
399 } 411 }
400 412
401 if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, major_version, minor_version, headers, num_headers, 413 if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, major_version,
402 max_headers, &r)) == NULL) { 414 minor_version, headers, num_headers, max_headers, &r)) == NULL) {
403 return r; 415 return r;
404 } 416 }
405 417
406 return (int)(buf - buf_start); 418 return (int)(buf - buf_start);
407} 419}
408 420
409static const char *parse_response(const char *buf, const char *buf_end, int *major_version, int *minor_version, int *status, 421static const char *parse_response(const char *buf, const char *buf_end, int *major_version,
410 const char **msg, size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t max_headers, 422 int *minor_version, int *status, const char **msg,
411 int *ret) { 423 size_t *msg_len, struct phr_header *headers, size_t *num_headers,
424 size_t max_headers, int *ret) {
412 /* parse "HTTP/1.x" */ 425 /* parse "HTTP/1.x" */
413 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) { 426 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) {
414 return NULL; 427 return NULL;
@@ -421,7 +434,8 @@ static const char *parse_response(const char *buf, const char *buf_end, int *maj
421 do { 434 do {
422 ++buf; 435 ++buf;
423 } while (*buf == ' '); 436 } while (*buf == ' ');
424 /* parse status code, we want at least [:digit:][:digit:][:digit:]<other char> to try to parse */ 437 /* parse status code, we want at least [:digit:][:digit:][:digit:]<other char> to try to parse
438 */
425 if (buf_end - buf < 4) { 439 if (buf_end - buf < 4) {
426 *ret = -2; 440 *ret = -2;
427 return NULL; 441 return NULL;
@@ -449,8 +463,9 @@ static const char *parse_response(const char *buf, const char *buf_end, int *maj
449 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); 463 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret);
450} 464}
451 465
452int phr_parse_response(const char *buf_start, size_t len, int *major_version, int *minor_version, int *status, const char **msg, 466int phr_parse_response(const char *buf_start, size_t len, int *major_version, int *minor_version,
453 size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t last_len) { 467 int *status, const char **msg, size_t *msg_len, struct phr_header *headers,
468 size_t *num_headers, size_t last_len) {
454 const char *buf = buf_start, *buf_end = buf + len; 469 const char *buf = buf_start, *buf_end = buf + len;
455 size_t max_headers = *num_headers; 470 size_t max_headers = *num_headers;
456 int r; 471 int r;
@@ -468,15 +483,16 @@ int phr_parse_response(const char *buf_start, size_t len, int *major_version, in
468 return r; 483 return r;
469 } 484 }
470 485
471 if ((buf = parse_response(buf, buf_end, major_version, minor_version, status, msg, msg_len, headers, num_headers, max_headers, &r)) == 486 if ((buf = parse_response(buf, buf_end, major_version, minor_version, status, msg, msg_len,
472 NULL) { 487 headers, num_headers, max_headers, &r)) == NULL) {
473 return r; 488 return r;
474 } 489 }
475 490
476 return (int)(buf - buf_start); 491 return (int)(buf - buf_start);
477} 492}
478 493
479int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len) { 494int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers,
495 size_t *num_headers, size_t last_len) {
480 const char *buf = buf_start, *buf_end = buf + len; 496 const char *buf = buf_start, *buf_end = buf + len;
481 size_t max_headers = *num_headers; 497 size_t max_headers = *num_headers;
482 int r; 498 int r;
@@ -526,8 +542,9 @@ ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_
526 case CHUNKED_IN_CHUNK_SIZE: 542 case CHUNKED_IN_CHUNK_SIZE:
527 for (;; ++src) { 543 for (;; ++src) {
528 int v; 544 int v;
529 if (src == bufsz) 545 if (src == bufsz) {
530 goto Exit; 546 goto Exit;
547 }
531 if ((v = decode_hex(buf[src])) == -1) { 548 if ((v = decode_hex(buf[src])) == -1) {
532 if (decoder->_hex_count == 0) { 549 if (decoder->_hex_count == 0) {
533 ret = -1; 550 ret = -1;
@@ -548,10 +565,12 @@ ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_
548 case CHUNKED_IN_CHUNK_EXT: 565 case CHUNKED_IN_CHUNK_EXT:
549 /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */ 566 /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */
550 for (;; ++src) { 567 for (;; ++src) {
551 if (src == bufsz) 568 if (src == bufsz) {
552 goto Exit; 569 goto Exit;
553 if (buf[src] == '\012') 570 }
571 if (buf[src] == '\012') {
554 break; 572 break;
573 }
555 } 574 }
556 ++src; 575 ++src;
557 if (decoder->bytes_left_in_chunk == 0) { 576 if (decoder->bytes_left_in_chunk == 0) {
@@ -567,15 +586,17 @@ ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_
567 case CHUNKED_IN_CHUNK_DATA: { 586 case CHUNKED_IN_CHUNK_DATA: {
568 size_t avail = bufsz - src; 587 size_t avail = bufsz - src;
569 if (avail < decoder->bytes_left_in_chunk) { 588 if (avail < decoder->bytes_left_in_chunk) {
570 if (dst != src) 589 if (dst != src) {
571 memmove(buf + dst, buf + src, avail); 590 memmove(buf + dst, buf + src, avail);
591 }
572 src += avail; 592 src += avail;
573 dst += avail; 593 dst += avail;
574 decoder->bytes_left_in_chunk -= avail; 594 decoder->bytes_left_in_chunk -= avail;
575 goto Exit; 595 goto Exit;
576 } 596 }
577 if (dst != src) 597 if (dst != src) {
578 memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk); 598 memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk);
599 }
579 src += decoder->bytes_left_in_chunk; 600 src += decoder->bytes_left_in_chunk;
580 dst += decoder->bytes_left_in_chunk; 601 dst += decoder->bytes_left_in_chunk;
581 decoder->bytes_left_in_chunk = 0; 602 decoder->bytes_left_in_chunk = 0;
@@ -584,10 +605,12 @@ ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_
584 /* fallthru */ 605 /* fallthru */
585 case CHUNKED_IN_CHUNK_CRLF: 606 case CHUNKED_IN_CHUNK_CRLF:
586 for (;; ++src) { 607 for (;; ++src) {
587 if (src == bufsz) 608 if (src == bufsz) {
588 goto Exit; 609 goto Exit;
589 if (buf[src] != '\015') 610 }
611 if (buf[src] != '\015') {
590 break; 612 break;
613 }
591 } 614 }
592 if (buf[src] != '\012') { 615 if (buf[src] != '\012') {
593 ret = -1; 616 ret = -1;
@@ -598,21 +621,26 @@ ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_
598 break; 621 break;
599 case CHUNKED_IN_TRAILERS_LINE_HEAD: 622 case CHUNKED_IN_TRAILERS_LINE_HEAD:
600 for (;; ++src) { 623 for (;; ++src) {
601 if (src == bufsz) 624 if (src == bufsz) {
602 goto Exit; 625 goto Exit;
603 if (buf[src] != '\015') 626 }
627 if (buf[src] != '\015') {
604 break; 628 break;
629 }
605 } 630 }
606 if (buf[src++] == '\012') 631 if (buf[src++] == '\012') {
607 goto Complete; 632 goto Complete;
633 }
608 decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE; 634 decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE;
609 /* fallthru */ 635 /* fallthru */
610 case CHUNKED_IN_TRAILERS_LINE_MIDDLE: 636 case CHUNKED_IN_TRAILERS_LINE_MIDDLE:
611 for (;; ++src) { 637 for (;; ++src) {
612 if (src == bufsz) 638 if (src == bufsz) {
613 goto Exit; 639 goto Exit;
614 if (buf[src] == '\012') 640 }
641 if (buf[src] == '\012') {
615 break; 642 break;
643 }
616 } 644 }
617 ++src; 645 ++src;
618 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; 646 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD;
@@ -625,13 +653,16 @@ ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_
625Complete: 653Complete:
626 ret = bufsz - src; 654 ret = bufsz - src;
627Exit: 655Exit:
628 if (dst != src) 656 if (dst != src) {
629 memmove(buf + dst, buf + src, bufsz - src); 657 memmove(buf + dst, buf + src, bufsz - src);
658 }
630 *_bufsz = dst; 659 *_bufsz = dst;
631 return ret; 660 return ret;
632} 661}
633 662
634int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder) { return decoder->_state == CHUNKED_IN_CHUNK_DATA; } 663int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder) {
664 return decoder->_state == CHUNKED_IN_CHUNK_DATA;
665}
635 666
636#undef CHECK_EOF 667#undef CHECK_EOF
637#undef EXPECT_CHAR 668#undef EXPECT_CHAR
diff --git a/plugins/picohttpparser/picohttpparser.h b/plugins/picohttpparser/picohttpparser.h
index 8f13b36f..054c2812 100644
--- a/plugins/picohttpparser/picohttpparser.h
+++ b/plugins/picohttpparser/picohttpparser.h
@@ -30,7 +30,7 @@
30#include <sys/types.h> 30#include <sys/types.h>
31 31
32#ifdef _MSC_VER 32#ifdef _MSC_VER
33#define ssize_t intptr_t 33# define ssize_t intptr_t
34#endif 34#endif
35 35
36#ifdef __cplusplus 36#ifdef __cplusplus
@@ -40,30 +40,33 @@ extern "C" {
40/* contains name and value of a header (name == NULL if is a continuing line 40/* contains name and value of a header (name == NULL if is a continuing line
41 * of a multiline header */ 41 * of a multiline header */
42struct phr_header { 42struct phr_header {
43 const char *name; 43 const char *name;
44 size_t name_len; 44 size_t name_len;
45 const char *value; 45 const char *value;
46 size_t value_len; 46 size_t value_len;
47}; 47};
48 48
49/* returns number of bytes consumed if successful, -2 if request is partial, 49/* returns number of bytes consumed if successful, -2 if request is partial,
50 * -1 if failed */ 50 * -1 if failed */
51int phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len, const char **path, size_t *path_len, 51int phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len,
52 int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len); 52 const char **path, size_t *path_len, int *major_version, int *minor_version,
53 struct phr_header *headers, size_t *num_headers, size_t last_len);
53 54
54/* ditto */ 55/* ditto */
55int phr_parse_response(const char *_buf, size_t len, int *major_version, int *minor_version, int *status, const char **msg, size_t *msg_len, 56int phr_parse_response(const char *_buf, size_t len, int *major_version, int *minor_version,
56 struct phr_header *headers, size_t *num_headers, size_t last_len); 57 int *status, const char **msg, size_t *msg_len, struct phr_header *headers,
58 size_t *num_headers, size_t last_len);
57 59
58/* ditto */ 60/* ditto */
59int phr_parse_headers(const char *buf, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len); 61int phr_parse_headers(const char *buf, size_t len, struct phr_header *headers, size_t *num_headers,
62 size_t last_len);
60 63
61/* should be zero-filled before start */ 64/* should be zero-filled before start */
62struct phr_chunked_decoder { 65struct phr_chunked_decoder {
63 size_t bytes_left_in_chunk; /* number of bytes left in current chunk */ 66 size_t bytes_left_in_chunk; /* number of bytes left in current chunk */
64 char consume_trailer; /* if trailing headers should be consumed */ 67 char consume_trailer; /* if trailing headers should be consumed */
65 char _hex_count; 68 char _hex_count;
66 char _state; 69 char _state;
67}; 70};
68 71
69/* the function rewrites the buffer given as (buf, bufsz) removing the chunked- 72/* the function rewrites the buffer given as (buf, bufsz) removing the chunked-
diff --git a/plugins/popen.c b/plugins/popen.c
index cfe930b6..c596d1e0 100644
--- a/plugins/popen.c
+++ b/plugins/popen.c
@@ -68,7 +68,7 @@ void popen_timeout_alarm_handler(int /*signo*/);
68#endif 68#endif
69 69
70#ifndef WIFEXITED 70#ifndef WIFEXITED
71# define WIFEXITED(stat_val) (((stat_val)&255) == 0) 71# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
72#endif 72#endif
73 73
74/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */ 74/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */
@@ -96,24 +96,28 @@ FILE *spopen(const char *cmdstring) {
96 env[1] = NULL; 96 env[1] = NULL;
97 97
98 /* if no command was passed, return with no error */ 98 /* if no command was passed, return with no error */
99 if (cmdstring == NULL) 99 if (cmdstring == NULL) {
100 return (NULL); 100 return (NULL);
101 }
101 102
102 char *cmd = NULL; 103 char *cmd = NULL;
103 /* make copy of command string so strtok() doesn't silently modify it */ 104 /* make copy of command string so strtok() doesn't silently modify it */
104 /* (the calling program may want to access it later) */ 105 /* (the calling program may want to access it later) */
105 cmd = malloc(strlen(cmdstring) + 1); 106 cmd = malloc(strlen(cmdstring) + 1);
106 if (cmd == NULL) 107 if (cmd == NULL) {
107 return NULL; 108 return NULL;
109 }
108 strcpy(cmd, cmdstring); 110 strcpy(cmd, cmdstring);
109 111
110 /* This is not a shell, so we don't handle "???" */ 112 /* This is not a shell, so we don't handle "???" */
111 if (strstr(cmdstring, "\"")) 113 if (strstr(cmdstring, "\"")) {
112 return NULL; 114 return NULL;
115 }
113 116
114 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ 117 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
115 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''")) 118 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''")) {
116 return NULL; 119 return NULL;
120 }
117 121
118 int argc; 122 int argc;
119 char **argv = NULL; 123 char **argv = NULL;
@@ -140,15 +144,17 @@ FILE *spopen(const char *cmdstring) {
140 144
141 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */ 145 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */
142 str++; 146 str++;
143 if (!strstr(str, "'")) 147 if (!strstr(str, "'")) {
144 return NULL; /* balanced? */ 148 return NULL; /* balanced? */
149 }
145 cmd = 1 + strstr(str, "'"); 150 cmd = 1 + strstr(str, "'");
146 str[strcspn(str, "'")] = 0; 151 str[strcspn(str, "'")] = 0;
147 } else if (strcspn(str, "'") < strcspn(str, " \t\r\n")) { 152 } else if (strcspn(str, "'") < strcspn(str, " \t\r\n")) {
148 /* handle --option='foo bar' strings */ 153 /* handle --option='foo bar' strings */
149 char *tmp = str + strcspn(str, "'") + 1; 154 char *tmp = str + strcspn(str, "'") + 1;
150 if (!strstr(tmp, "'")) 155 if (!strstr(tmp, "'")) {
151 return NULL; /* balanced? */ 156 return NULL; /* balanced? */
157 }
152 tmp += strcspn(tmp, "'") + 1; 158 tmp += strcspn(tmp, "'") + 1;
153 *tmp = 0; 159 *tmp = 0;
154 cmd = tmp + 1; 160 cmd = tmp + 1;
@@ -161,8 +167,9 @@ FILE *spopen(const char *cmdstring) {
161 } 167 }
162 } 168 }
163 169
164 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n")) 170 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n")) {
165 cmd = NULL; 171 cmd = NULL;
172 }
166 173
167 argv[i++] = str; 174 argv[i++] = str;
168 } 175 }
@@ -171,22 +178,26 @@ FILE *spopen(const char *cmdstring) {
171 long maxfd = mp_open_max(); 178 long maxfd = mp_open_max();
172 179
173 if (childpid == NULL) { /* first time through */ 180 if (childpid == NULL) { /* first time through */
174 if ((childpid = calloc((size_t)maxfd, sizeof(pid_t))) == NULL) 181 if ((childpid = calloc((size_t)maxfd, sizeof(pid_t))) == NULL) {
175 return (NULL); 182 return (NULL);
183 }
176 } 184 }
177 185
178 if (child_stderr_array == NULL) { /* first time through */ 186 if (child_stderr_array == NULL) { /* first time through */
179 if ((child_stderr_array = calloc((size_t)maxfd, sizeof(int))) == NULL) 187 if ((child_stderr_array = calloc((size_t)maxfd, sizeof(int))) == NULL) {
180 return (NULL); 188 return (NULL);
189 }
181 } 190 }
182 191
183 int pfd[2]; 192 int pfd[2];
184 if (pipe(pfd) < 0) 193 if (pipe(pfd) < 0) {
185 return (NULL); /* errno set by pipe() */ 194 return (NULL); /* errno set by pipe() */
195 }
186 196
187 int pfderr[2]; 197 int pfderr[2];
188 if (pipe(pfderr) < 0) 198 if (pipe(pfderr) < 0) {
189 return (NULL); /* errno set by pipe() */ 199 return (NULL); /* errno set by pipe() */
200 }
190 201
191#ifdef REDHAT_SPOPEN_ERROR 202#ifdef REDHAT_SPOPEN_ERROR
192 if (signal(SIGCHLD, popen_sigchld_handler) == SIG_ERR) { 203 if (signal(SIGCHLD, popen_sigchld_handler) == SIG_ERR) {
@@ -195,8 +206,9 @@ FILE *spopen(const char *cmdstring) {
195#endif 206#endif
196 207
197 pid_t pid; 208 pid_t pid;
198 if ((pid = fork()) < 0) 209 if ((pid = fork()) < 0) {
199 return (NULL); /* errno set by fork() */ 210 return (NULL); /* errno set by fork() */
211 }
200 212
201 if (pid == 0) { /* child */ 213 if (pid == 0) { /* child */
202 close(pfd[0]); 214 close(pfd[0]);
@@ -210,17 +222,20 @@ FILE *spopen(const char *cmdstring) {
210 close(pfderr[1]); 222 close(pfderr[1]);
211 } 223 }
212 /* close all descriptors in childpid[] */ 224 /* close all descriptors in childpid[] */
213 for (i = 0; i < maxfd; i++) 225 for (i = 0; i < maxfd; i++) {
214 if (childpid[i] > 0) 226 if (childpid[i] > 0) {
215 close(i); 227 close(i);
228 }
229 }
216 230
217 execve(argv[0], argv, env); 231 execve(argv[0], argv, env);
218 _exit(0); 232 _exit(0);
219 } 233 }
220 234
221 close(pfd[1]); /* parent */ 235 close(pfd[1]); /* parent */
222 if ((child_process = fdopen(pfd[0], "r")) == NULL) 236 if ((child_process = fdopen(pfd[0], "r")) == NULL) {
223 return (NULL); 237 return (NULL);
238 }
224 close(pfderr[1]); 239 close(pfderr[1]);
225 240
226 childpid[fileno(child_process)] = pid; /* remember child pid for this fd */ 241 childpid[fileno(child_process)] = pid; /* remember child pid for this fd */
@@ -229,17 +244,20 @@ FILE *spopen(const char *cmdstring) {
229} 244}
230 245
231int spclose(FILE *fp) { 246int spclose(FILE *fp) {
232 if (childpid == NULL) 247 if (childpid == NULL) {
233 return (1); /* popen() has never been called */ 248 return (1); /* popen() has never been called */
249 }
234 250
235 pid_t pid; 251 pid_t pid;
236 int fd = fileno(fp); 252 int fd = fileno(fp);
237 if ((pid = childpid[fd]) == 0) 253 if ((pid = childpid[fd]) == 0) {
238 return (1); /* fp wasn't opened by popen() */ 254 return (1); /* fp wasn't opened by popen() */
255 }
239 256
240 childpid[fd] = 0; 257 childpid[fd] = 0;
241 if (fclose(fp) == EOF) 258 if (fclose(fp) == EOF) {
242 return (1); 259 return (1);
260 }
243 261
244#ifdef REDHAT_SPOPEN_ERROR 262#ifdef REDHAT_SPOPEN_ERROR
245 while (!childtermd) 263 while (!childtermd)
@@ -247,20 +265,24 @@ int spclose(FILE *fp) {
247#endif 265#endif
248 266
249 int status; 267 int status;
250 while (waitpid(pid, &status, 0) < 0) 268 while (waitpid(pid, &status, 0) < 0) {
251 if (errno != EINTR) 269 if (errno != EINTR) {
252 return (1); /* error other than EINTR from waitpid() */ 270 return (1); /* error other than EINTR from waitpid() */
271 }
272 }
253 273
254 if (WIFEXITED(status)) 274 if (WIFEXITED(status)) {
255 return (WEXITSTATUS(status)); /* return child's termination status */ 275 return (WEXITSTATUS(status)); /* return child's termination status */
276 }
256 277
257 return (1); 278 return (1);
258} 279}
259 280
260#ifdef REDHAT_SPOPEN_ERROR 281#ifdef REDHAT_SPOPEN_ERROR
261void popen_sigchld_handler(int signo) { 282void popen_sigchld_handler(int signo) {
262 if (signo == SIGCHLD) 283 if (signo == SIGCHLD) {
263 childtermd = 1; 284 childtermd = 1;
285 }
264} 286}
265#endif 287#endif
266 288
diff --git a/plugins/popen.h b/plugins/popen.h
index 1ea69632..e318ce25 100644
--- a/plugins/popen.h
+++ b/plugins/popen.h
@@ -1,13 +1,13 @@
1/****************************************************************************** 1/******************************************************************************
2* 2 *
3* 3 *
4*****************************************************************************/ 4 *****************************************************************************/
5 5
6FILE *spopen (const char *); 6FILE *spopen(const char *);
7int spclose (FILE *); 7int spclose(FILE *);
8void popen_timeout_alarm_handler (int); 8void popen_timeout_alarm_handler(int);
9 9
10pid_t *childpid=NULL; 10pid_t *childpid = NULL;
11int *child_stderr_array=NULL; 11int *child_stderr_array = NULL;
12FILE *child_process=NULL; 12FILE *child_process = NULL;
13FILE *child_stderr=NULL; 13FILE *child_stderr = NULL;
diff --git a/plugins/runcmd.c b/plugins/runcmd.c
index 4429ceb0..be6691d2 100644
--- a/plugins/runcmd.c
+++ b/plugins/runcmd.c
@@ -53,7 +53,7 @@
53#endif 53#endif
54 54
55#ifndef WIFEXITED 55#ifndef WIFEXITED
56# define WIFEXITED(stat_val) (((stat_val)&255) == 0) 56# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
57#endif 57#endif
58 58
59/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */ 59/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */
@@ -87,8 +87,9 @@ extern void die(int, const char *, ...) __attribute__((__noreturn__, __format__(
87 * through this api and thus achieve async-safeness throughout the api */ 87 * through this api and thus achieve async-safeness throughout the api */
88void np_runcmd_init(void) { 88void np_runcmd_init(void) {
89 long maxfd = mp_open_max(); 89 long maxfd = mp_open_max();
90 if (!np_pids) 90 if (!np_pids) {
91 np_pids = calloc(maxfd, sizeof(pid_t)); 91 np_pids = calloc(maxfd, sizeof(pid_t));
92 }
92} 93}
93 94
94/* Start running a command */ 95/* Start running a command */
@@ -106,8 +107,9 @@ static int np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr) {
106 107
107 int i = 0; 108 int i = 0;
108 109
109 if (!np_pids) 110 if (!np_pids) {
110 NP_RUNCMD_INIT; 111 NP_RUNCMD_INIT;
112 }
111 113
112 env[0] = strdup("LC_ALL=C"); 114 env[0] = strdup("LC_ALL=C");
113 env[1] = NULL; 115 env[1] = NULL;
@@ -115,18 +117,21 @@ static int np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr) {
115 /* make copy of command string so strtok() doesn't silently modify it */ 117 /* make copy of command string so strtok() doesn't silently modify it */
116 /* (the calling program may want to access it later) */ 118 /* (the calling program may want to access it later) */
117 cmdlen = strlen(cmdstring); 119 cmdlen = strlen(cmdstring);
118 if ((cmd = malloc(cmdlen + 1)) == NULL) 120 if ((cmd = malloc(cmdlen + 1)) == NULL) {
119 return -1; 121 return -1;
122 }
120 memcpy(cmd, cmdstring, cmdlen); 123 memcpy(cmd, cmdstring, cmdlen);
121 cmd[cmdlen] = '\0'; 124 cmd[cmdlen] = '\0';
122 125
123 /* This is not a shell, so we don't handle "???" */ 126 /* This is not a shell, so we don't handle "???" */
124 if (strstr(cmdstring, "\"")) 127 if (strstr(cmdstring, "\"")) {
125 return -1; 128 return -1;
129 }
126 130
127 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ 131 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
128 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''")) 132 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''")) {
129 return -1; 133 return -1;
134 }
130 135
131 /* each arg must be whitespace-separated, so args can be a maximum 136 /* each arg must be whitespace-separated, so args can be a maximum
132 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */ 137 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */
@@ -145,8 +150,9 @@ static int np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr) {
145 150
146 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */ 151 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */
147 str++; 152 str++;
148 if (!strstr(str, "'")) 153 if (!strstr(str, "'")) {
149 return -1; /* balanced? */ 154 return -1; /* balanced? */
155 }
150 cmd = 1 + strstr(str, "'"); 156 cmd = 1 + strstr(str, "'");
151 str[strcspn(str, "'")] = 0; 157 str[strcspn(str, "'")] = 0;
152 } else { 158 } else {
@@ -158,14 +164,16 @@ static int np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr) {
158 } 164 }
159 } 165 }
160 166
161 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n")) 167 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n")) {
162 cmd = NULL; 168 cmd = NULL;
169 }
163 170
164 argv[i++] = str; 171 argv[i++] = str;
165 } 172 }
166 173
167 if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0) 174 if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0) {
168 return -1; /* errno set by the failing function */ 175 return -1; /* errno set by the failing function */
176 }
169 177
170 /* child runs exceve() and _exit. */ 178 /* child runs exceve() and _exit. */
171 if (pid == 0) { 179 if (pid == 0) {
@@ -190,9 +198,11 @@ static int np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr) {
190 * This is executed in a separate address space (pure child), 198 * This is executed in a separate address space (pure child),
191 * so we don't have to worry about async safety */ 199 * so we don't have to worry about async safety */
192 long maxfd = mp_open_max(); 200 long maxfd = mp_open_max();
193 for (i = 0; i < maxfd; i++) 201 for (i = 0; i < maxfd; i++) {
194 if (np_pids[i] > 0) 202 if (np_pids[i] > 0) {
195 close(i); 203 close(i);
204 }
205 }
196 206
197 execve(argv[0], argv, env); 207 execve(argv[0], argv, env);
198 _exit(STATE_UNKNOWN); 208 _exit(STATE_UNKNOWN);
@@ -215,17 +225,21 @@ static int np_runcmd_close(int fd) {
215 225
216 /* make sure this fd was opened by popen() */ 226 /* make sure this fd was opened by popen() */
217 long maxfd = mp_open_max(); 227 long maxfd = mp_open_max();
218 if (fd < 0 || fd > maxfd || !np_pids || (pid = np_pids[fd]) == 0) 228 if (fd < 0 || fd > maxfd || !np_pids || (pid = np_pids[fd]) == 0) {
219 return -1; 229 return -1;
230 }
220 231
221 np_pids[fd] = 0; 232 np_pids[fd] = 0;
222 if (close(fd) == -1) 233 if (close(fd) == -1) {
223 return -1; 234 return -1;
235 }
224 236
225 /* EINTR is ok (sort of), everything else is bad */ 237 /* EINTR is ok (sort of), everything else is bad */
226 while (waitpid(pid, &status, 0) < 0) 238 while (waitpid(pid, &status, 0) < 0) {
227 if (errno != EINTR) 239 if (errno != EINTR) {
228 return -1; 240 return -1;
241 }
242 }
229 243
230 /* return child's termination status */ 244 /* return child's termination status */
231 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1; 245 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1;
@@ -233,15 +247,18 @@ static int np_runcmd_close(int fd) {
233 247
234void runcmd_timeout_alarm_handler(int signo) { 248void runcmd_timeout_alarm_handler(int signo) {
235 249
236 if (signo == SIGALRM) 250 if (signo == SIGALRM) {
237 puts(_("CRITICAL - Plugin timed out while executing system call")); 251 puts(_("CRITICAL - Plugin timed out while executing system call"));
252 }
238 253
239 long maxfd = mp_open_max(); 254 long maxfd = mp_open_max();
240 if (np_pids) 255 if (np_pids) {
241 for (long int i = 0; i < maxfd; i++) { 256 for (long int i = 0; i < maxfd; i++) {
242 if (np_pids[i] != 0) 257 if (np_pids[i] != 0) {
243 kill(np_pids[i], SIGKILL); 258 kill(np_pids[i], SIGKILL);
259 }
244 } 260 }
261 }
245 262
246 exit(STATE_CRITICAL); 263 exit(STATE_CRITICAL);
247} 264}
@@ -270,18 +287,19 @@ static int np_fetch_output(int fd, output *op, int flags) {
270 287
271 /* some plugins may want to keep output unbroken, and some commands 288 /* some plugins may want to keep output unbroken, and some commands
272 * will yield no output, so return here for those */ 289 * will yield no output, so return here for those */
273 if (flags & RUNCMD_NO_ARRAYS || !op->buf || !op->buflen) 290 if (flags & RUNCMD_NO_ARRAYS || !op->buf || !op->buflen) {
274 return op->buflen; 291 return op->buflen;
292 }
275 293
276 /* and some may want both */ 294 /* and some may want both */
277 if (flags & RUNCMD_NO_ASSOC) { 295 if (flags & RUNCMD_NO_ASSOC) {
278 buf = malloc(op->buflen); 296 buf = malloc(op->buflen);
279 memcpy(buf, op->buf, op->buflen); 297 memcpy(buf, op->buf, op->buflen);
280 } else 298 } else {
281 buf = op->buf; 299 buf = op->buf;
300 }
282 301
283 op->line = NULL; 302 op->line = NULL;
284 op->lens = NULL;
285 i = 0; 303 i = 0;
286 while (i < op->buflen) { 304 while (i < op->buflen) {
287 /* make sure we have enough memory */ 305 /* make sure we have enough memory */
@@ -292,20 +310,17 @@ static int np_fetch_output(int fd, output *op, int flags) {
292 } while (!ary_size); 310 } while (!ary_size);
293 311
294 op->line = realloc(op->line, ary_size * sizeof(char *)); 312 op->line = realloc(op->line, ary_size * sizeof(char *));
295 op->lens = realloc(op->lens, ary_size * sizeof(size_t));
296 } 313 }
297 314
298 /* set the pointer to the string */ 315 /* set the pointer to the string */
299 op->line[lineno] = &buf[i]; 316 op->line[lineno] = &buf[i];
300 317
301 /* hop to next newline or end of buffer */ 318 /* hop to next newline or end of buffer */
302 while (buf[i] != '\n' && i < op->buflen) 319 while (buf[i] != '\n' && i < op->buflen) {
303 i++; 320 i++;
321 }
304 buf[i] = '\0'; 322 buf[i] = '\0';
305 323
306 /* calculate the string length using pointer difference */
307 op->lens[lineno] = (size_t)&buf[i] - (size_t)op->line[lineno];
308
309 lineno++; 324 lineno++;
310 i++; 325 i++;
311 } 326 }
@@ -317,18 +332,23 @@ int np_runcmd(const char *cmd, output *out, output *err, int flags) {
317 int fd, pfd_out[2], pfd_err[2]; 332 int fd, pfd_out[2], pfd_err[2];
318 333
319 /* initialize the structs */ 334 /* initialize the structs */
320 if (out) 335 if (out) {
321 memset(out, 0, sizeof(output)); 336 memset(out, 0, sizeof(output));
322 if (err) 337 }
338 if (err) {
323 memset(err, 0, sizeof(output)); 339 memset(err, 0, sizeof(output));
340 }
324 341
325 if ((fd = np_runcmd_open(cmd, pfd_out, pfd_err)) == -1) 342 if ((fd = np_runcmd_open(cmd, pfd_out, pfd_err)) == -1) {
326 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd); 343 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd);
344 }
327 345
328 if (out) 346 if (out) {
329 out->lines = np_fetch_output(pfd_out[0], out, flags); 347 out->lines = np_fetch_output(pfd_out[0], out, flags);
330 if (err) 348 }
349 if (err) {
331 err->lines = np_fetch_output(pfd_err[0], err, flags); 350 err->lines = np_fetch_output(pfd_err[0], err, flags);
351 }
332 352
333 return np_runcmd_close(fd); 353 return np_runcmd_close(fd);
334} 354}
diff --git a/plugins/runcmd.h b/plugins/runcmd.h
index 2dcdadf0..63ce7b12 100644
--- a/plugins/runcmd.h
+++ b/plugins/runcmd.h
@@ -1,25 +1,25 @@
1/**************************************************************************** 1/****************************************************************************
2* 2 *
3* License: GPL 3 * License: GPL
4* Copyright (c) 2005 Monitoring Plugins Development Team 4 * Copyright (c) 2005 Monitoring Plugins Development Team
5* Author: Andreas Ericsson <ae@op5.se> 5 * Author: Andreas Ericsson <ae@op5.se>
6* 6 *
7* 7 *
8* This program is free software: you can redistribute it and/or modify 8 * This program is free software: you can redistribute it and/or modify
9* it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
10* the Free Software Foundation, either version 3 of the License, or 10 * the Free Software Foundation, either version 3 of the License, or
11* (at your option) any later version. 11 * (at your option) any later version.
12* 12 *
13* This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful,
14* but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16* GNU General Public License for more details. 16 * GNU General Public License for more details.
17* 17 *
18* You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
19* along with this program. If not, see <http://www.gnu.org/licenses/>. 19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20* 20 *
21* 21 *
22*****************************************************************************/ 22 *****************************************************************************/
23 23
24#ifndef NAGIOSPLUG_RUNCMD_H 24#ifndef NAGIOSPLUG_RUNCMD_H
25#define NAGIOSPLUG_RUNCMD_H 25#define NAGIOSPLUG_RUNCMD_H
@@ -29,8 +29,7 @@
29 29
30/** prototypes **/ 30/** prototypes **/
31int np_runcmd(const char *, output *, output *, int); 31int np_runcmd(const char *, output *, output *, int);
32void runcmd_timeout_alarm_handler(int) 32void runcmd_timeout_alarm_handler(int) __attribute__((__noreturn__));
33 __attribute__((__noreturn__));
34 33
35/* only multi-threaded plugins need to bother with this */ 34/* only multi-threaded plugins need to bother with this */
36void np_runcmd_init(void); 35void np_runcmd_init(void);
@@ -38,6 +37,6 @@ void np_runcmd_init(void);
38 37
39/* possible flags for np_runcmd()'s fourth argument */ 38/* possible flags for np_runcmd()'s fourth argument */
40#define RUNCMD_NO_ARRAYS 0x01 /* don't populate arrays at all */ 39#define RUNCMD_NO_ARRAYS 0x01 /* don't populate arrays at all */
41#define RUNCMD_NO_ASSOC 0x02 /* output.line won't point to buf */ 40#define RUNCMD_NO_ASSOC 0x02 /* output.line won't point to buf */
42 41
43#endif /* NAGIOSPLUG_RUNCMD_H */ 42#endif /* NAGIOSPLUG_RUNCMD_H */
diff --git a/plugins/sslutils.c b/plugins/sslutils.c
index 719de575..c58a35ab 100644
--- a/plugins/sslutils.c
+++ b/plugins/sslutils.c
@@ -26,10 +26,12 @@
26 * 26 *
27 *****************************************************************************/ 27 *****************************************************************************/
28 28
29#include "output.h"
29#define MAX_CN_LENGTH 256 30#define MAX_CN_LENGTH 256
30#include "common.h" 31#include "common.h"
31#include "netutils.h" 32#include "netutils.h"
32#include "../lib/monitoringplug.h" 33#include "../lib/monitoringplug.h"
34#include "states.h"
33 35
34#ifdef HAVE_SSL 36#ifdef HAVE_SSL
35static SSL_CTX *ctx = NULL; 37static SSL_CTX *ctx = NULL;
@@ -37,13 +39,16 @@ static SSL *s = NULL;
37 39
38int np_net_ssl_init(int sd) { return np_net_ssl_init_with_hostname(sd, NULL); } 40int np_net_ssl_init(int sd) { return np_net_ssl_init_with_hostname(sd, NULL); }
39 41
40int np_net_ssl_init_with_hostname(int sd, char *host_name) { return np_net_ssl_init_with_hostname_and_version(sd, host_name, 0); } 42int np_net_ssl_init_with_hostname(int sd, char *host_name) {
43 return np_net_ssl_init_with_hostname_and_version(sd, host_name, 0);
44}
41 45
42int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version) { 46int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version) {
43 return np_net_ssl_init_with_hostname_version_and_cert(sd, host_name, version, NULL, NULL); 47 return np_net_ssl_init_with_hostname_version_and_cert(sd, host_name, version, NULL, NULL);
44} 48}
45 49
46int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int version, char *cert, char *privkey) { 50int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int version, char *cert,
51 char *privkey) {
47 long options = 0; 52 long options = 0;
48 53
49 if ((ctx = SSL_CTX_new(TLS_client_method())) == NULL) { 54 if ((ctx = SSL_CTX_new(TLS_client_method())) == NULL) {
@@ -75,7 +80,8 @@ int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int
75# endif 80# endif
76 case MP_TLSv1_1: /* TLSv1.1 protocol */ 81 case MP_TLSv1_1: /* TLSv1.1 protocol */
77# if !defined(SSL_OP_NO_TLSv1_1) 82# if !defined(SSL_OP_NO_TLSv1_1)
78 printf("%s\n", _("UNKNOWN - TLS protocol version 1.1 is not supported by your SSL library.")); 83 printf("%s\n",
84 _("UNKNOWN - TLS protocol version 1.1 is not supported by your SSL library."));
79 return STATE_UNKNOWN; 85 return STATE_UNKNOWN;
80# else 86# else
81 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION); 87 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
@@ -84,7 +90,8 @@ int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int
84# endif 90# endif
85 case MP_TLSv1_2: /* TLSv1.2 protocol */ 91 case MP_TLSv1_2: /* TLSv1.2 protocol */
86# if !defined(SSL_OP_NO_TLSv1_2) 92# if !defined(SSL_OP_NO_TLSv1_2)
87 printf("%s\n", _("UNKNOWN - TLS protocol version 1.2 is not supported by your SSL library.")); 93 printf("%s\n",
94 _("UNKNOWN - TLS protocol version 1.2 is not supported by your SSL library."));
88 return STATE_UNKNOWN; 95 return STATE_UNKNOWN;
89# else 96# else
90 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); 97 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
@@ -145,8 +152,9 @@ int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int
145 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 152 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
146 if ((s = SSL_new(ctx)) != NULL) { 153 if ((s = SSL_new(ctx)) != NULL) {
147# ifdef SSL_set_tlsext_host_name 154# ifdef SSL_set_tlsext_host_name
148 if (host_name != NULL) 155 if (host_name != NULL) {
149 SSL_set_tlsext_host_name(s, host_name); 156 SSL_set_tlsext_host_name(s, host_name);
157 }
150# endif 158# endif
151 SSL_set_fd(s, sd); 159 SSL_set_fd(s, sd);
152 if (SSL_connect(s) == 1) { 160 if (SSL_connect(s) == 1) {
@@ -182,63 +190,54 @@ int np_net_ssl_write(const void *buf, int num) { return SSL_write(s, buf, num);
182 190
183int np_net_ssl_read(void *buf, int num) { return SSL_read(s, buf, num); } 191int np_net_ssl_read(void *buf, int num) { return SSL_read(s, buf, num); }
184 192
185int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit) { 193mp_state_enum np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn,
194 int days_till_exp_crit) {
186# ifdef USE_OPENSSL 195# ifdef USE_OPENSSL
187 X509_NAME *subj = NULL;
188 char timestamp[50] = "";
189 char cn[MAX_CN_LENGTH] = "";
190 char *tz;
191
192 int cnlen = -1;
193 int status = STATE_UNKNOWN;
194
195 ASN1_STRING *tm;
196 int offset;
197 struct tm stamp;
198 float time_left;
199 int days_left;
200 int time_remaining;
201 time_t tm_t;
202
203 if (!certificate) { 196 if (!certificate) {
204 printf("%s\n", _("CRITICAL - Cannot retrieve server certificate.")); 197 printf("%s\n", _("CRITICAL - No server certificate present to inspect."));
205 return STATE_CRITICAL; 198 return STATE_CRITICAL;
206 } 199 }
207 200
208 /* Extract CN from certificate subject */ 201 /* Extract CN from certificate subject */
209 subj = X509_get_subject_name(certificate); 202 X509_NAME *subj = X509_get_subject_name(certificate);
210 203
211 if (!subj) { 204 if (!subj) {
212 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject.")); 205 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject."));
213 return STATE_CRITICAL; 206 return STATE_CRITICAL;
214 } 207 }
215 cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn)); 208
216 if (cnlen == -1) 209 char cn[MAX_CN_LENGTH] = "";
210 int cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn));
211 if (cnlen == -1) {
217 strcpy(cn, _("Unknown CN")); 212 strcpy(cn, _("Unknown CN"));
213 }
218 214
219 /* Retrieve timestamp of certificate */ 215 /* Retrieve timestamp of certificate */
220 tm = X509_get_notAfter(certificate); 216 ASN1_STRING *tm = X509_get_notAfter(certificate);
221 217
218 int offset = 0;
219 struct tm stamp = {};
222 /* Generate tm structure to process timestamp */ 220 /* Generate tm structure to process timestamp */
223 if (tm->type == V_ASN1_UTCTIME) { 221 if (tm->type == V_ASN1_UTCTIME) {
224 if (tm->length < 10) { 222 if (tm->length < 10) {
225 printf("%s\n", _("CRITICAL - Wrong time format in certificate.")); 223 printf("%s\n", _("CRITICAL - Wrong time format in certificate."));
226 return STATE_CRITICAL; 224 return STATE_CRITICAL;
227 } else {
228 stamp.tm_year = (tm->data[0] - '0') * 10 + (tm->data[1] - '0');
229 if (stamp.tm_year < 50)
230 stamp.tm_year += 100;
231 offset = 0;
232 } 225 }
226 stamp.tm_year = (tm->data[0] - '0') * 10 + (tm->data[1] - '0');
227 if (stamp.tm_year < 50) {
228 stamp.tm_year += 100;
229 }
230 offset = 0;
231
233 } else { 232 } else {
234 if (tm->length < 12) { 233 if (tm->length < 12) {
235 printf("%s\n", _("CRITICAL - Wrong time format in certificate.")); 234 printf("%s\n", _("CRITICAL - Wrong time format in certificate."));
236 return STATE_CRITICAL; 235 return STATE_CRITICAL;
237 } else {
238 stamp.tm_year = (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 + (tm->data[2] - '0') * 10 + (tm->data[3] - '0');
239 stamp.tm_year -= 1900;
240 offset = 2;
241 } 236 }
237 stamp.tm_year = (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 +
238 (tm->data[2] - '0') * 10 + (tm->data[3] - '0');
239 stamp.tm_year -= 1900;
240 offset = 2;
242 } 241 }
243 stamp.tm_mon = (tm->data[2 + offset] - '0') * 10 + (tm->data[3 + offset] - '0') - 1; 242 stamp.tm_mon = (tm->data[2 + offset] - '0') * 10 + (tm->data[3 + offset] - '0') - 1;
244 stamp.tm_mday = (tm->data[4 + offset] - '0') * 10 + (tm->data[5 + offset] - '0'); 243 stamp.tm_mday = (tm->data[4 + offset] - '0') * 10 + (tm->data[5 + offset] - '0');
@@ -247,48 +246,60 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
247 stamp.tm_sec = (tm->data[10 + offset] - '0') * 10 + (tm->data[11 + offset] - '0'); 246 stamp.tm_sec = (tm->data[10 + offset] - '0') * 10 + (tm->data[11 + offset] - '0');
248 stamp.tm_isdst = -1; 247 stamp.tm_isdst = -1;
249 248
250 tm_t = timegm(&stamp); 249 time_t tm_t = timegm(&stamp);
251 time_left = difftime(tm_t, time(NULL)); 250 float time_left = difftime(tm_t, time(NULL));
252 days_left = time_left / 86400; 251 int days_left = time_left / 86400;
253 tz = getenv("TZ"); 252 char *tz = getenv("TZ");
254 setenv("TZ", "GMT", 1); 253 setenv("TZ", "GMT", 1);
255 tzset(); 254 tzset();
255
256 char timestamp[50] = "";
256 strftime(timestamp, 50, "%c %z", localtime(&tm_t)); 257 strftime(timestamp, 50, "%c %z", localtime(&tm_t));
257 if (tz) 258 if (tz) {
258 setenv("TZ", tz, 1); 259 setenv("TZ", tz, 1);
259 else 260 } else {
260 unsetenv("TZ"); 261 unsetenv("TZ");
262 }
263
261 tzset(); 264 tzset();
262 265
266 int time_remaining;
267 mp_state_enum status = STATE_UNKNOWN;
263 if (days_left > 0 && days_left <= days_till_exp_warn) { 268 if (days_left > 0 && days_left <= days_till_exp_warn) {
264 printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, 269 printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"),
265 days_left, timestamp); 270 (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, days_left, timestamp);
266 if (days_left > days_till_exp_crit) 271 if (days_left > days_till_exp_crit) {
267 status = STATE_WARNING; 272 status = STATE_WARNING;
268 else 273 } else {
269 status = STATE_CRITICAL; 274 status = STATE_CRITICAL;
275 }
270 } else if (days_left == 0 && time_left > 0) { 276 } else if (days_left == 0 && time_left > 0) {
271 if (time_left >= 3600) 277 if (time_left >= 3600) {
272 time_remaining = (int)time_left / 3600; 278 time_remaining = (int)time_left / 3600;
273 else 279 } else {
274 time_remaining = (int)time_left / 60; 280 time_remaining = (int)time_left / 60;
281 }
275 282
276 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, 283 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"),
277 time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp); 284 (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, time_remaining,
285 time_left >= 3600 ? "hours" : "minutes", timestamp);
278 286
279 if (days_left > days_till_exp_crit) 287 if (days_left > days_till_exp_crit) {
280 status = STATE_WARNING; 288 status = STATE_WARNING;
281 else 289 } else {
282 status = STATE_CRITICAL; 290 status = STATE_CRITICAL;
291 }
283 } else if (time_left < 0) { 292 } else if (time_left < 0) {
284 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), cn, timestamp); 293 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), cn, timestamp);
285 status = STATE_CRITICAL; 294 status = STATE_CRITICAL;
286 } else if (days_left == 0) { 295 } else if (days_left == 0) {
287 printf(_("%s - Certificate '%s' just expired (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, timestamp); 296 printf(_("%s - Certificate '%s' just expired (%s).\n"),
288 if (days_left > days_till_exp_crit) 297 (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, timestamp);
298 if (days_left > days_till_exp_crit) {
289 status = STATE_WARNING; 299 status = STATE_WARNING;
290 else 300 } else {
291 status = STATE_CRITICAL; 301 status = STATE_CRITICAL;
302 }
292 } else { 303 } else {
293 printf(_("OK - Certificate '%s' will expire on %s.\n"), cn, timestamp); 304 printf(_("OK - Certificate '%s' will expire on %s.\n"), cn, timestamp);
294 status = STATE_OK; 305 status = STATE_OK;
@@ -301,7 +312,139 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
301# endif /* USE_OPENSSL */ 312# endif /* USE_OPENSSL */
302} 313}
303 314
304int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit) { 315retrieve_expiration_time_result np_net_ssl_get_cert_expiration(X509 *certificate) {
316# ifdef USE_OPENSSL
317 retrieve_expiration_time_result result = {
318 .errors = ALL_OK,
319 .remaining_seconds = 0,
320 };
321
322 if (!certificate) {
323 // printf("%s\n", _("CRITICAL - No server certificate present to inspect."));
324 result.errors = NO_SERVER_CERTIFICATE_PRESENT;
325 return result;
326 }
327
328 /* Extract CN from certificate subject */
329 X509_NAME *subj = X509_get_subject_name(certificate);
330
331 if (!subj) {
332 // printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject."));
333 result.errors = UNABLE_TO_RETRIEVE_CERTIFICATE_SUBJECT;
334 return result;
335 }
336
337 char cn[MAX_CN_LENGTH] = "";
338 int cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn));
339 if (cnlen == -1) {
340 strcpy(cn, _("Unknown CN"));
341 }
342
343 /* Retrieve timestamp of certificate */
344 ASN1_STRING *expiration_timestamp = X509_get_notAfter(certificate);
345
346 int offset = 0;
347 struct tm stamp = {};
348 /* Generate tm structure to process timestamp */
349 if (expiration_timestamp->type == V_ASN1_UTCTIME) {
350 if (expiration_timestamp->length < 10) {
351 result.errors = WRONG_TIME_FORMAT_IN_CERTIFICATE;
352 return result;
353 }
354
355 stamp.tm_year =
356 (expiration_timestamp->data[0] - '0') * 10 + (expiration_timestamp->data[1] - '0');
357 if (stamp.tm_year < 50) {
358 stamp.tm_year += 100;
359 }
360 offset = 0;
361 } else {
362 if (expiration_timestamp->length < 12) {
363 result.errors = WRONG_TIME_FORMAT_IN_CERTIFICATE;
364 return result;
365 }
366
367 stamp.tm_year = (expiration_timestamp->data[0] - '0') * 1000 +
368 (expiration_timestamp->data[1] - '0') * 100 +
369 (expiration_timestamp->data[2] - '0') * 10 +
370 (expiration_timestamp->data[3] - '0');
371 stamp.tm_year -= 1900;
372 offset = 2;
373 }
374 stamp.tm_mon = (expiration_timestamp->data[2 + offset] - '0') * 10 +
375 (expiration_timestamp->data[3 + offset] - '0') - 1;
376 stamp.tm_mday = (expiration_timestamp->data[4 + offset] - '0') * 10 +
377 (expiration_timestamp->data[5 + offset] - '0');
378 stamp.tm_hour = (expiration_timestamp->data[6 + offset] - '0') * 10 +
379 (expiration_timestamp->data[7 + offset] - '0');
380 stamp.tm_min = (expiration_timestamp->data[8 + offset] - '0') * 10 +
381 (expiration_timestamp->data[9 + offset] - '0');
382 stamp.tm_sec = (expiration_timestamp->data[10 + offset] - '0') * 10 +
383 (expiration_timestamp->data[11 + offset] - '0');
384 stamp.tm_isdst = -1;
385
386 time_t tm_t = timegm(&stamp);
387 double time_left = difftime(tm_t, time(NULL));
388 result.remaining_seconds = time_left;
389
390 char *timezone = getenv("TZ");
391 setenv("TZ", "GMT", 1);
392 tzset();
393
394 char timestamp[50] = "";
395 strftime(timestamp, 50, "%c %z", localtime(&tm_t));
396 if (timezone) {
397 setenv("TZ", timezone, 1);
398 } else {
399 unsetenv("TZ");
400 }
401
402 tzset();
403
404 X509_free(certificate);
405
406 return result;
407# else /* ifndef USE_OPENSSL */
408 printf("%s\n", _("WARNING - Plugin does not support checking certificates."));
409 return STATE_WARNING;
410# endif /* USE_OPENSSL */
411}
412
413net_ssl_check_cert_result np_net_ssl_check_cert2(int days_till_exp_warn, int days_till_exp_crit) {
414# ifdef USE_OPENSSL
415 X509 *certificate = NULL;
416 certificate = SSL_get_peer_certificate(s);
417
418 retrieve_expiration_time_result expiration_date = np_net_ssl_get_cert_expiration(certificate);
419
420 net_ssl_check_cert_result result = {
421 .result_state = STATE_UNKNOWN,
422 .remaining_seconds = expiration_date.remaining_seconds,
423 .errors = expiration_date.errors,
424 };
425
426 if (expiration_date.errors == ALL_OK) {
427 // got a valid expiration date
428 unsigned int remaining_days = result.remaining_seconds / 86400;
429
430 if (remaining_days < days_till_exp_crit) {
431 result.result_state = STATE_CRITICAL;
432 } else if (remaining_days < days_till_exp_warn) {
433 result.result_state = STATE_WARNING;
434 } else {
435 result.result_state = STATE_OK;
436 }
437 }
438
439 return result;
440
441# else /* ifndef USE_OPENSSL */
442 printf("%s\n", _("WARNING - Plugin does not support checking certificates."));
443 return STATE_WARNING;
444# endif /* USE_OPENSSL */
445}
446
447mp_state_enum np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit) {
305# ifdef USE_OPENSSL 448# ifdef USE_OPENSSL
306 X509 *certificate = NULL; 449 X509 *certificate = NULL;
307 certificate = SSL_get_peer_certificate(s); 450 certificate = SSL_get_peer_certificate(s);
@@ -312,4 +455,136 @@ int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit) {
312# endif /* USE_OPENSSL */ 455# endif /* USE_OPENSSL */
313} 456}
314 457
458mp_subcheck mp_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn,
459 int days_till_exp_crit) {
460 mp_subcheck sc_cert = mp_subcheck_init();
461# ifdef USE_OPENSSL
462 if (!certificate) {
463 xasprintf(&sc_cert.output, _("No server certificate present to inspect"));
464 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
465 return sc_cert;
466 }
467
468 /* Extract CN from certificate subject */
469 X509_NAME *subj = X509_get_subject_name(certificate);
470
471 if (!subj) {
472 xasprintf(&sc_cert.output, _("Cannot retrieve certificate subject"));
473 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
474 return sc_cert;
475 }
476
477 char commonName[MAX_CN_LENGTH] = "";
478 int cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, commonName, sizeof(commonName));
479 if (cnlen == -1) {
480 strcpy(commonName, _("Unknown CN"));
481 }
482
483 /* Retrieve timestamp of certificate */
484 ASN1_STRING *expiry_timestamp = X509_get_notAfter(certificate);
485
486 int offset = 0;
487 struct tm stamp = {};
488 /* Generate tm structure to process timestamp */
489 if (expiry_timestamp->type == V_ASN1_UTCTIME) {
490 if (expiry_timestamp->length < 10) {
491 xasprintf(&sc_cert.output, _("Wrong time format in certificate"));
492 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
493 return sc_cert;
494 }
495
496 stamp.tm_year = (expiry_timestamp->data[0] - '0') * 10 + (expiry_timestamp->data[1] - '0');
497 if (stamp.tm_year < 50) {
498 stamp.tm_year += 100;
499 }
500
501 offset = 0;
502 } else {
503 if (expiry_timestamp->length < 12) {
504 xasprintf(&sc_cert.output, _("Wrong time format in certificate"));
505 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
506 return sc_cert;
507 }
508 stamp.tm_year = (expiry_timestamp->data[0] - '0') * 1000 +
509 (expiry_timestamp->data[1] - '0') * 100 +
510 (expiry_timestamp->data[2] - '0') * 10 + (expiry_timestamp->data[3] - '0');
511 stamp.tm_year -= 1900;
512 offset = 2;
513 }
514
515 stamp.tm_mon = (expiry_timestamp->data[2 + offset] - '0') * 10 +
516 (expiry_timestamp->data[3 + offset] - '0') - 1;
517 stamp.tm_mday = (expiry_timestamp->data[4 + offset] - '0') * 10 +
518 (expiry_timestamp->data[5 + offset] - '0');
519 stamp.tm_hour = (expiry_timestamp->data[6 + offset] - '0') * 10 +
520 (expiry_timestamp->data[7 + offset] - '0');
521 stamp.tm_min = (expiry_timestamp->data[8 + offset] - '0') * 10 +
522 (expiry_timestamp->data[9 + offset] - '0');
523 stamp.tm_sec = (expiry_timestamp->data[10 + offset] - '0') * 10 +
524 (expiry_timestamp->data[11 + offset] - '0');
525 stamp.tm_isdst = -1;
526
527 time_t tm_t = timegm(&stamp);
528 double time_left = difftime(tm_t, time(NULL));
529 int days_left = (int)(time_left / 86400);
530 char *timeZone = getenv("TZ");
531 setenv("TZ", "GMT", 1);
532 tzset();
533
534 char timestamp[50] = "";
535 strftime(timestamp, 50, "%c %z", localtime(&tm_t));
536 if (timeZone) {
537 setenv("TZ", timeZone, 1);
538 } else {
539 unsetenv("TZ");
540 }
541
542 tzset();
543
544 int time_remaining;
545 if (days_left > 0 && days_left <= days_till_exp_warn) {
546 xasprintf(&sc_cert.output, _("Certificate '%s' expires in %d day(s) (%s)"), commonName,
547 days_left, timestamp);
548 if (days_left > days_till_exp_crit) {
549 sc_cert = mp_set_subcheck_state(sc_cert, STATE_WARNING);
550 } else {
551 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
552 }
553 } else if (days_left == 0 && time_left > 0) {
554 if (time_left >= 3600) {
555 time_remaining = (int)time_left / 3600;
556 } else {
557 time_remaining = (int)time_left / 60;
558 }
559
560 xasprintf(&sc_cert.output, _("Certificate '%s' expires in %u %s (%s)"), commonName,
561 time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp);
562
563 if (days_left > days_till_exp_crit) {
564 sc_cert = mp_set_subcheck_state(sc_cert, STATE_WARNING);
565 } else {
566 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
567 }
568 } else if (time_left < 0) {
569 xasprintf(&sc_cert.output, _("Certificate '%s' expired on %s"), commonName, timestamp);
570 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
571 } else if (days_left == 0) {
572 xasprintf(&sc_cert.output, _("Certificate '%s' just expired (%s)"), commonName, timestamp);
573 if (days_left > days_till_exp_crit) {
574 sc_cert = mp_set_subcheck_state(sc_cert, STATE_WARNING);
575 } else {
576 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
577 }
578 } else {
579 xasprintf(&sc_cert.output, _("Certificate '%s' will expire on %s"), commonName, timestamp);
580 sc_cert = mp_set_subcheck_state(sc_cert, STATE_OK);
581 }
582 X509_free(certificate);
583 return sc_cert;
584# else /* ifndef USE_OPENSSL */
585 xasprintf(&sc_cert.output, _("Plugin does not support checking certificates"));
586 sc_cert = mp_set_subcheck_state(sc_cert, STATE_WARNING);
587 return sc_cert;
588# endif /* USE_OPENSSL */
589}
315#endif /* HAVE_SSL */ 590#endif /* HAVE_SSL */
diff --git a/plugins/t/check_apt.t b/plugins/t/check_apt.t
index 430eb53e..736bc2f2 100644
--- a/plugins/t/check_apt.t
+++ b/plugins/t/check_apt.t
@@ -5,6 +5,7 @@
5# 5#
6 6
7use strict; 7use strict;
8use warnings;
8use Test::More; 9use Test::More;
9use NPTest; 10use NPTest;
10 11
@@ -12,18 +13,18 @@ sub make_result_regexp {
12 my ($warning, $critical) = @_; 13 my ($warning, $critical) = @_;
13 my $status; 14 my $status;
14 if ($warning == 0 && $critical == 0) { 15 if ($warning == 0 && $critical == 0) {
15 $status = "OK"; 16 $status = "OK";
16 } elsif ($critical == 0) { 17 } elsif ($critical == 0) {
17 $status = "WARNING"; 18 $status = "WARNING";
18 } else { 19 } else {
19 $status = "CRITICAL"; 20 $status = "CRITICAL";
20 } 21 }
21 return sprintf('/^APT %s: %d packages available for upgrade \(%d critical updates\)\. |available_upgrades=%d;;;0 critical_updates=%d;;;0$/', 22 return sprintf('/.*[%s].*Updates available: %d.*Security updates available: %d.*\'available_upgrades\'=%d;;; \'critical_updates\'=%d;;; /s',
22 $status, $warning, $critical, $warning, $critical); 23 $status, $warning, $critical, $warning, $critical);
23} 24}
24 25
25if (-x "./check_apt") { 26if (-x "./check_apt") {
26 plan tests => 36; 27 plan tests => 35;
27} else { 28} else {
28 plan skip_all => "No check_apt compiled"; 29 plan skip_all => "No check_apt compiled";
29} 30}
@@ -42,7 +43,8 @@ like( $result->output, make_result_regexp(13, 0), "Output correct" );
42 43
43$result = NPTest->testCmd( sprintf($testfile_command, "-o", "debian2") ); 44$result = NPTest->testCmd( sprintf($testfile_command, "-o", "debian2") );
44is( $result->return_code, 0, "Debian apt output, no critical" ); 45is( $result->return_code, 0, "Debian apt output, no critical" );
45like( $result->output, make_result_regexp(13, 0), "Output correct" ); 46# this test does not work, since -o was given
47# like( $result->output, make_result_regexp(13, 0), "Output correct" );
46 48
47$result = NPTest->testCmd( sprintf($testfile_command, "", "debian3") ); 49$result = NPTest->testCmd( sprintf($testfile_command, "", "debian3") );
48is( $result->return_code, 2, "Debian apt output, some critical" ); 50is( $result->return_code, 2, "Debian apt output, some critical" );
diff --git a/plugins/t/check_by_ssh.t b/plugins/t/check_by_ssh.t
index b6479f1f..0ee310cd 100644
--- a/plugins/t/check_by_ssh.t
+++ b/plugins/t/check_by_ssh.t
@@ -16,7 +16,7 @@ my $ssh_conf = getTestParameter( "NP_SSH_CONFIGFILE", "A config file with ssh
16 16
17plan skip_all => "SSH_HOST and SSH_IDENTITY must be defined" unless ($ssh_service && $ssh_key); 17plan skip_all => "SSH_HOST and SSH_IDENTITY must be defined" unless ($ssh_service && $ssh_key);
18 18
19plan tests => 42; 19plan tests => 33;
20 20
21# Some random check strings/response 21# Some random check strings/response
22my @response = ('OK: Everything is fine', 22my @response = ('OK: Everything is fine',
@@ -47,70 +47,70 @@ for (my $i=0; $i<4; $i++) {
47 "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[$i]; exit $i'" 47 "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[$i]; exit $i'"
48 ); 48 );
49 cmp_ok($result->return_code, '==', $i, "Exit with return code $i"); 49 cmp_ok($result->return_code, '==', $i, "Exit with return code $i");
50 is($result->output, $response[$i], "Status text is correct for check $i"); 50 like($result->output, "/$response[$i]/", "Status text is correct for check $i");
51} 51}
52 52
53$result = NPTest->testCmd( 53$result = NPTest->testCmd(
54 "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 0'" 54 "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 0'"
55 ); 55 );
56cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)"); 56cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
57is($result->output, 'OK - check_by_ssh: Remote command \'exit 0\' returned status 0', "Status text if command returned none (OK)"); 57like($result->output, '/command \'exit 0\' returned status 0/', "Status text if command returned none (OK)");
58 58
59$result = NPTest->testCmd( 59$result = NPTest->testCmd(
60 "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 1'" 60 "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 1'"
61 ); 61 );
62cmp_ok($result->return_code, '==', 1, "Exit with return code 1 (WARNING)"); 62cmp_ok($result->return_code, '==', 1, "Exit with return code 1 (WARNING)");
63is($result->output, 'WARNING - check_by_ssh: Remote command \'exit 1\' returned status 1', "Status text if command returned none (WARNING)"); 63like($result->output, '/command \'exit 1\' returned status 1/', "Status text if command returned none (WARNING)");
64 64
65$result = NPTest->testCmd( 65$result = NPTest->testCmd(
66 "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 2'" 66 "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 2'"
67 ); 67 );
68cmp_ok($result->return_code, '==', 2, "Exit with return code 2 (CRITICAL)"); 68cmp_ok($result->return_code, '==', 2, "Exit with return code 2 (CRITICAL)");
69is($result->output, 'CRITICAL - check_by_ssh: Remote command \'exit 2\' returned status 2', "Status text if command returned none (CRITICAL)"); 69like($result->output, '/command \'exit 2\' returned status 2/', "Status text if command returned none (CRITICAL)");
70 70
71$result = NPTest->testCmd( 71$result = NPTest->testCmd(
72 "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 3'" 72 "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 3'"
73 ); 73 );
74cmp_ok($result->return_code, '==', 3, "Exit with return code 3 (UNKNOWN)"); 74cmp_ok($result->return_code, '==', 3, "Exit with return code 3 (UNKNOWN)");
75is($result->output, 'UNKNOWN - check_by_ssh: Remote command \'exit 3\' returned status 3', "Status text if command returned none (UNKNOWN)"); 75like($result->output, '/command \'exit 3\' returned status 3/', "Status text if command returned none (UNKNOWN)");
76 76
77$result = NPTest->testCmd( 77$result = NPTest->testCmd(
78 "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 7'" 78 "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 7'"
79 ); 79 );
80cmp_ok($result->return_code, '==', 7, "Exit with return code 7 (out of bounds)"); 80cmp_ok($result->return_code, '==', 3, "Exit with return code 3");
81is($result->output, 'UNKNOWN - check_by_ssh: Remote command \'exit 7\' returned status 7', "Status text if command returned none (out of bounds)"); 81like($result->output, '/command \'exit 7\' returned status 7/', "Status text if command returned none (out of bounds)");
82 82
83$result = NPTest->testCmd( 83$result = NPTest->testCmd(
84 "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[4]; exit 8'" 84 "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[4]; exit 8'"
85 ); 85 );
86cmp_ok($result->return_code, '==', 8, "Exit with return code 8 (out of bounds)"); 86cmp_ok($result->return_code, '==', 3, "Exit with return code 3");
87is($result->output, $response[4], "Return proper status text even with unknown status codes"); 87like($result->output, "/$response[4]/", "Return proper status text even with unknown status codes");
88 88
89$result = NPTest->testCmd( 89$result = NPTest->testCmd(
90 "./check_by_ssh -i $ssh_key -H $ssh_service -F $ssh_conf -C 'exit 0'" 90 "./check_by_ssh -i $ssh_key -H $ssh_service -F $ssh_conf -C 'exit 0'"
91 ); 91 );
92cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)"); 92cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
93is($result->output, 'OK - check_by_ssh: Remote command \'exit 0\' returned status 0', "Status text if command returned none (OK)"); 93like($result->output, '/command \'exit 0\' returned status 0/', "Status text if command returned none (OK)");
94 94
95# Multiple active checks 95# Multiple active checks
96$result = NPTest->testCmd( 96$result = NPTest->testCmd(
97 "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[1]; sh -c exit\\ 1' -C '$check[0]; sh -c exit\\ 0' -C '$check[3]; sh -c exit\\ 3' -C '$check[2]; sh -c exit\\ 2'" 97 "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[1]; sh -c exit\\ 1' -C '$check[0]; sh -c exit\\ 0' -C '$check[3]; sh -c exit\\ 3' -C '$check[2]; sh -c exit\\ 2'"
98 ); 98 );
99cmp_ok($result->return_code, '==', 0, "Multiple checks always return OK"); 99cmp_ok($result->return_code, '==', 0, "Multiple checks always return OK");
100my @lines = split(/\n/, $result->output); 100# my @lines = split(/\n/, $result->output);
101cmp_ok(scalar(@lines), '==', 8, "Correct number of output lines for multiple checks"); 101# cmp_ok(scalar(@lines), '==', 8, "Correct number of output lines for multiple checks");
102my %linemap = ( 102# my %linemap = (
103 '0' => '1', 103# '0' => '1',
104 '2' => '0', 104# '2' => '0',
105 '4' => '3', 105# '4' => '3',
106 '6' => '2', 106# '6' => '2',
107); 107# );
108foreach my $line (0, 2, 4, 6) { 108# foreach my $line (0, 2, 4, 6) {
109 my $code = $linemap{$line}; 109 # my $code = $linemap{$line};
110 my $statline = $line+1; 110 # my $statline = $line+1;
111 is($lines[$line], "$response[$code]", "multiple checks status text is correct for line $line"); 111 # is($lines[$line], "$response[$code]", "multiple checks status text is correct for line $line");
112 is($lines[$statline], "STATUS CODE: $code", "multiple check status code is correct for line $line"); 112 # is($lines[$statline], "STATUS CODE: $code", "multiple check status code is correct for line $line");
113} 113# }
114 114
115# Passive checks 115# Passive checks
116unlink("/tmp/check_by_ssh.$$"); 116unlink("/tmp/check_by_ssh.$$");
diff --git a/plugins/t/check_curl.t b/plugins/t/check_curl.t
index 7a930a4e..2c2fafde 100644
--- a/plugins/t/check_curl.t
+++ b/plugins/t/check_curl.t
@@ -13,12 +13,12 @@ use vars qw($tests $has_ipv6);
13BEGIN { 13BEGIN {
14 use NPTest; 14 use NPTest;
15 $has_ipv6 = NPTest::has_ipv6(); 15 $has_ipv6 = NPTest::has_ipv6();
16 $tests = $has_ipv6 ? 59 : 57; 16 $tests = $has_ipv6 ? 55 : 53;
17 plan tests => $tests; 17 plan tests => $tests;
18} 18}
19 19
20 20
21my $successOutput = '/OK.*HTTP.*second/'; 21my $successOutput = '/.*HTTP.*second/';
22 22
23my $res; 23my $res;
24my $plugin = 'check_http'; 24my $plugin = 'check_http';
@@ -63,7 +63,7 @@ $res = NPTest->testCmd(
63 ); 63 );
64cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" ); 64cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" );
65# was CRITICAL only, but both check_curl and check_http print HTTP CRITICAL (puzzle?!) 65# was CRITICAL only, but both check_curl and check_http print HTTP CRITICAL (puzzle?!)
66like( $res->output, "/HTTP CRITICAL - Invalid HTTP response received from host on port 80: cURL returned 28 - Connection timed out after/", "Output OK"); 66like( $res->output, "/cURL returned 28 - Connection timed out after/", "Output OK");
67 67
68$res = NPTest->testCmd( 68$res = NPTest->testCmd(
69 "./$plugin $hostname_invalid -wt 1 -ct 2" 69 "./$plugin $hostname_invalid -wt 1 -ct 2"
@@ -124,14 +124,14 @@ SKIP: {
124 124
125 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing'" ); 125 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing'" );
126 cmp_ok( $res->return_code, "==", 2, "Not got 'mONiTORing'"); 126 cmp_ok( $res->return_code, "==", 2, "Not got 'mONiTORing'");
127 like ( $res->output, "/pattern not found/", "Error message says 'pattern not found'"); 127 like ( $res->output, "/matched not/", "Error message says 'matched not'");
128 128
129 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -R 'mONiTORing'" ); 129 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -R 'mONiTORing'" );
130 cmp_ok( $res->return_code, "==", 0, "But case insensitive doesn't mind 'mONiTORing'"); 130 cmp_ok( $res->return_code, "==", 0, "But case insensitive doesn't mind 'mONiTORing'");
131 131
132 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'monitoring' --invert-regex" ); 132 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'monitoring' --invert-regex" );
133 cmp_ok( $res->return_code, "==", 2, "Invert results work when found"); 133 cmp_ok( $res->return_code, "==", 2, "Invert results work when found");
134 like ( $res->output, "/pattern found/", "Error message says 'pattern found'"); 134 like ( $res->output, "/matched/", "Error message says 'matched'");
135 135
136 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing' --invert-regex" ); 136 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing' --invert-regex" );
137 cmp_ok( $res->return_code, "==", 0, "And also when not found"); 137 cmp_ok( $res->return_code, "==", 0, "And also when not found");
@@ -151,63 +151,74 @@ SKIP: {
151 151
152 $res = NPTest->testCmd( "./$plugin -C 8000,1 --ssl $host_tls_http" ); 152 $res = NPTest->testCmd( "./$plugin -C 8000,1 --ssl $host_tls_http" );
153 cmp_ok( $res->return_code, '==', 1, "Checking certificate for $host_tls_http"); 153 cmp_ok( $res->return_code, '==', 1, "Checking certificate for $host_tls_http");
154 like ( $res->output, qr/WARNING - Certificate '$host_tls_cert' expires in \d+ day/, "Output Warning" ); 154 like ( $res->output, qr/Certificate '$host_tls_cert' expires in \d+ day/, "Output Warning" );
155 155
156 $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" ); 156 $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" );
157 is( $res->return_code, 0, "Old syntax for cert checking okay" ); 157 is( $res->return_code, 0, "Old syntax for cert checking okay" );
158 is( $res->output, $saved_cert_output, "Same output as new syntax" ); 158 # deactivated since different timings will change the output
159 # TODO compare without perfdata
160 # is( $res->output, $saved_cert_output, "Same output as new syntax" );
159 161
160 $res = NPTest->testCmd( "./$plugin -H $host_tls_http -C 1" ); 162 $res = NPTest->testCmd( "./$plugin -H $host_tls_http -C 1" );
161 is( $res->return_code, 0, "Updated syntax for cert checking okay" ); 163 is( $res->return_code, 0, "Updated syntax for cert checking okay" );
162 is( $res->output, $saved_cert_output, "Same output as new syntax" ); 164 # deactivated since different timings will change the output
165 # TODO compare without perfdata
166 # is( $res->output, $saved_cert_output, "Same output as new syntax" );
163 167
164 $res = NPTest->testCmd( "./$plugin -C 1 $host_tls_http" ); 168 $res = NPTest->testCmd( "./$plugin -C 1 $host_tls_http" );
165 cmp_ok( $res->output, 'eq', $saved_cert_output, "--ssl option automatically added"); 169 # deactivated since different timings will change the output
170 # TODO compare without perfdata
171 # cmp_ok( $res->output, 'eq', $saved_cert_output, "--ssl option automatically added");
166 172
167 $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" ); 173 $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" );
168 cmp_ok( $res->output, 'eq', $saved_cert_output, "Old syntax for cert checking still works"); 174 # deactivated since different timings will change the output
175 # TODO compare without perfdata
176 # cmp_ok( $res->output, 'eq', $saved_cert_output, "Old syntax for cert checking still works");
169 177
170 # run some certificate checks with faketime 178 # run some certificate checks with faketime
171 SKIP: { 179 SKIP: {
172 skip "No faketime binary found", 12 if !$faketime; 180 skip "No faketime binary found", 12 if !$faketime;
173 $res = NPTest->testCmd("LC_TIME=C TZ=UTC ./$plugin -C 1 $host_tls_http"); 181 $res = NPTest->testCmd("LC_TIME=C TZ=UTC ./$plugin -C 1 $host_tls_http");
174 like($res->output, qr/OK - Certificate '$host_tls_cert' will expire on/, "Catch cert output"); 182 like($res->output, qr/Certificate '$host_tls_cert' will expire on/, "Catch cert output");
175 is( $res->return_code, 0, "Catch cert output exit code" ); 183 is( $res->return_code, 0, "Catch cert output exit code" );
184
176 my($mon,$day,$hour,$min,$sec,$year) = ($res->output =~ /(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)/); 185 my($mon,$day,$hour,$min,$sec,$year) = ($res->output =~ /(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)/);
177 if(!defined $year) { 186 if(!defined $year) {
178 die("parsing date failed from: ".$res->output); 187 die("parsing date failed from: ".$res->output);
179 } 188 }
189
180 my $months = {'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11}; 190 my $months = {'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11};
181 my $ts = mktime($sec, $min, $hour, $day, $months->{$mon}, $year-1900); 191 my $ts = mktime($sec, $min, $hour, $day, $months->{$mon}, $year-1900);
182 my $time = strftime("%Y-%m-%d %H:%M:%S", localtime($ts)); 192 my $time = strftime("%Y-%m-%d %H:%M:%S", localtime($ts));
193
183 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./$plugin -C 1 $host_tls_http"); 194 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./$plugin -C 1 $host_tls_http");
184 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' just expired/, "Output on expire date"); 195 like($res->output, qr/Certificate '$host_tls_cert' just expired/, "Output on expire date");
185 is( $res->return_code, 2, "Output on expire date" ); 196 is( $res->return_code, 2, "Output on expire date" );
186 197
187 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-1))."' ./$plugin -C 1 $host_tls_http"); 198 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-1))."' ./$plugin -C 1 $host_tls_http");
188 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 0 minutes/, "cert expires in 1 second output"); 199 like($res->output, qr/Certificate '$host_tls_cert' expires in 0 minutes/, "cert expires in 1 second output");
189 is( $res->return_code, 2, "cert expires in 1 second exit code" ); 200 is( $res->return_code, 2, "cert expires in 1 second exit code" );
190 201
191 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-120))."' ./$plugin -C 1 $host_tls_http"); 202 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-120))."' ./$plugin -C 1 $host_tls_http");
192 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 minutes/, "cert expires in 2 minutes output"); 203 like($res->output, qr/Certificate '$host_tls_cert' expires in 2 minutes/, "cert expires in 2 minutes output");
193 is( $res->return_code, 2, "cert expires in 2 minutes exit code" ); 204 is( $res->return_code, 2, "cert expires in 2 minutes exit code" );
194 205
195 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-7200))."' ./$plugin -C 1 $host_tls_http"); 206 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-7200))."' ./$plugin -C 1 $host_tls_http");
196 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 hours/, "cert expires in 2 hours output"); 207 like($res->output, qr/Certificate '$host_tls_cert' expires in 2 hours/, "cert expires in 2 hours output");
197 is( $res->return_code, 2, "cert expires in 2 hours exit code" ); 208 is( $res->return_code, 2, "cert expires in 2 hours exit code" );
198 209
199 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./$plugin -C 1 $host_tls_http"); 210 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./$plugin -C 1 $host_tls_http");
200 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expired on/, "Certificate expired output"); 211 like($res->output, qr/Certificate '$host_tls_cert' expired on/, "Certificate expired output");
201 is( $res->return_code, 2, "Certificate expired exit code" ); 212 is( $res->return_code, 2, "Certificate expired exit code" );
202 }; 213 };
203 214
204 $res = NPTest->testCmd( "./$plugin --ssl $host_tls_http -E" ); 215 $res = NPTest->testCmd( "./$plugin --ssl $host_tls_http -E" );
205 like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' ); 216 like ( $res->output, '/\'time_connect\'=[\d\.]+/', 'Extended Performance Data Output OK' );
206 like ( $res->output, '/time_ssl=[\d\.]+/', 'Extended Performance Data SSL Output OK' ); 217 like ( $res->output, '/\'time_tls\'=[\d\.]+/', 'Extended Performance Data SSL Output OK' );
207 218
208 $res = NPTest->testCmd( "./$plugin -H monitoring-plugins.org -u /download.html -f follow" ); 219 $res = NPTest->testCmd( "./$plugin -H monitoring-plugins.org -u /download.html -f follow" );
209 is( $res->return_code, 0, "Redirection based on location is okay"); 220 is( $res->return_code, 0, "Redirection based on location is okay");
210 221
211 $res = NPTest->testCmd( "./$plugin -H monitoring-plugins.org --extended-perfdata" ); 222 $res = NPTest->testCmd( "./$plugin -H monitoring-plugins.org --extended-perfdata" );
212 like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' ); 223 like ( $res->output, '/\'time_connect\'=[\d\.]+/', 'Extended Performance Data Output OK' );
213} 224}
diff --git a/plugins/t/check_dbi.t b/plugins/t/check_dbi.t
index c24b5a8c..75444de4 100644
--- a/plugins/t/check_dbi.t
+++ b/plugins/t/check_dbi.t
@@ -21,12 +21,12 @@ plan tests => $tests;
21my $missing_driver_output = "failed to open DBI driver 'sqlite3'"; 21my $missing_driver_output = "failed to open DBI driver 'sqlite3'";
22 22
23my $bad_driver_output = "/failed to open DBI driver 'nodriver'/"; 23my $bad_driver_output = "/failed to open DBI driver 'nodriver'/";
24my $conn_time_output = "/OK - connection time: [0-9\.]+s \|/"; 24my $conn_time_output = "/connection time: [0-9\.]+s \|/";
25my $missing_query_output = "/Must specify a query to execute/"; 25my $missing_query_output = "/Must specify a query to execute/";
26my $no_rows_output = "/WARNING - no rows returned/"; 26my $no_rows_output = "/no rows returned/";
27my $not_numeric_output = "/CRITICAL - result value is not a numeric:/"; 27my $not_numeric_output = "/result value is not a numeric:/";
28my $query_time_output = "/OK - connection time: [0-9\.]+s, 'SELECT 1' returned 1.000000 in [0-9\.]+s \|/"; 28my $query_time_output = "/connection time: [0-9\.]+s, 'SELECT 1' returned 1.000000 in [0-9\.]+s \|/";
29my $syntax_error_output = "/CRITICAL - failed to execute query 'GET ALL FROM test': 1: near \"GET\": syntax error/"; 29my $syntax_error_output = "/1: near \"GET\": syntax error/";
30 30
31my $result; 31my $result;
32 32
diff --git a/plugins/t/check_disk.t b/plugins/t/check_disk.t
index 9eb77ce4..0f62fb2b 100644
--- a/plugins/t/check_disk.t
+++ b/plugins/t/check_disk.t
@@ -10,6 +10,7 @@ use strict;
10use Test::More; 10use Test::More;
11use NPTest; 11use NPTest;
12use POSIX qw(ceil floor); 12use POSIX qw(ceil floor);
13use Data::Dumper;
13 14
14my $successOutput = '/^DISK OK/'; 15my $successOutput = '/^DISK OK/';
15my $failureOutput = '/^DISK CRITICAL/'; 16my $failureOutput = '/^DISK CRITICAL/';
@@ -20,173 +21,216 @@ my $result;
20my $mountpoint_valid = getTestParameter( "NP_MOUNTPOINT_VALID", "Path to valid mountpoint", "/"); 21my $mountpoint_valid = getTestParameter( "NP_MOUNTPOINT_VALID", "Path to valid mountpoint", "/");
21my $mountpoint2_valid = getTestParameter( "NP_MOUNTPOINT2_VALID", "Path to another valid mountpoint. Must be different from 1st one", "/var"); 22my $mountpoint2_valid = getTestParameter( "NP_MOUNTPOINT2_VALID", "Path to another valid mountpoint. Must be different from 1st one", "/var");
22 23
24my $output_format = "--output-format mp-test-json";
25
23if ($mountpoint_valid eq "" or $mountpoint2_valid eq "") { 26if ($mountpoint_valid eq "" or $mountpoint2_valid eq "") {
24 plan skip_all => "Need 2 mountpoints to test"; 27 plan skip_all => "Need 2 mountpoints to test";
25} else { 28} else {
26 plan tests => 94; 29 plan tests => 97;
27} 30}
28 31
29$result = NPTest->testCmd( 32$result = NPTest->testCmd(
30 "./check_disk -w 1% -c 1% -p $mountpoint_valid -w 1% -c 1% -p $mountpoint2_valid" 33 "./check_disk -w 1% -c 1% -p $mountpoint_valid -w 1% -c 1% -P -p $mountpoint2_valid $output_format"
31 ); 34 );
32cmp_ok( $result->return_code, "==", 0, "Checking two mountpoints (must have at least 1% free in space and inodes)"); 35cmp_ok( $result->return_code, "==", 0, "Checking two mountpoints (must have at least 1% free in space and inodes)");
33my $c = 0;
34$_ = $result->output;
35$c++ while /\(/g; # counts number of "(" - should be two
36cmp_ok( $c, '==', 2, "Got two mountpoints in output");
37 36
37like($result->{'mp_test_result'}->{'state'}, "/OK/", "Main result is OK");
38like($result->{'mp_test_result'}->{'checks'}->[0]->{'state'}, "/OK/", "First sub result is OK");
39like($result->{'mp_test_result'}->{'checks'}->[1]->{'state'}, "/OK/", "Second sub result is OK");
40
41my $absolut_space_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'max'}->{'value'};
42# print("absolute space on mp1: ". $absolut_space_mp1 . "\n");
43
44my $free_percent_on_mp1 = ($result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'} / ($absolut_space_mp1/100));
45print("free percent on mp1: ". $free_percent_on_mp1 . "\n");
46
47my $absolut_space_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'max'}->{'value'};
48# print("absolute space on mp2: ". $absolut_space_mp2 . "\n");
49
50my $free_percent_on_mp2 = ($result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'}/ ($absolut_space_mp2/100));
51print("free percent on mp2: ". $free_percent_on_mp2 . "\n");
38 52
39# Get perf data 53my @perfdata;
40# Should use Monitoring::Plugin 54@perfdata[0] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0];
41my @perf_data = sort(split(/ /, $result->perf_output)); 55@perfdata[1] = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0];
42 56
57# Decrease precision of numbers since the the fs might be modified between the two runs
58$perfdata[0]->{'value'}->{'value'} = int($perfdata[0]->{'value'}->{'value'} / 1000000);
59$perfdata[1]->{'value'}->{'value'} = int($perfdata[1]->{'value'}->{'value'} / 1000000);
43 60
44# Calculate avg_free free on mountpoint1 and mountpoint2 61# Calculate avg_free free on mountpoint1 and mountpoint2
45# because if you check in the middle, you should get different errors 62# because if you check in the middle, you should get different errors
46$_ = $result->output; 63my $avg_free_percent = ceil(($free_percent_on_mp1+$free_percent_on_mp2)/2);
47my ($free_on_mp1, $free_on_mp2) = (m/\((\d+\.\d+)%.*\((\d+\.\d+)%/); 64# print("avg_free: " . $avg_free_percent . "\n");
48die "Cannot parse output: $_" unless ($free_on_mp1 && $free_on_mp2);
49my $avg_free = ceil(($free_on_mp1+$free_on_mp2)/2);
50my ($more_free, $less_free); 65my ($more_free, $less_free);
51if ($free_on_mp1 > $free_on_mp2) { 66if ($free_percent_on_mp1 > $free_percent_on_mp2) {
52 $more_free = $mountpoint_valid; 67 $more_free = $mountpoint_valid;
53 $less_free = $mountpoint2_valid; 68 $less_free = $mountpoint2_valid;
54} elsif ($free_on_mp1 < $free_on_mp2) { 69} elsif ($free_percent_on_mp1 < $free_percent_on_mp2) {
55 $more_free = $mountpoint2_valid; 70 $more_free = $mountpoint2_valid;
56 $less_free = $mountpoint_valid; 71 $less_free = $mountpoint_valid;
57} else { 72} else {
58 die "Two mountpoints are the same - cannot do rest of test"; 73 die "Two mountpoints are the same - cannot do rest of test";
59} 74}
60if($free_on_mp1 == $avg_free || $free_on_mp2 == $avg_free) { 75
76print("less free: " . $less_free . "\n");
77print("more free: " . $more_free . "\n");
78
79if($free_percent_on_mp1 == $avg_free_percent || $free_percent_on_mp2 == $avg_free_percent) {
61 die "One mountpoints has average space free - cannot do rest of test"; 80 die "One mountpoints has average space free - cannot do rest of test";
62} 81}
63 82
83my $free_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'};
84my $total_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'};
85my $free_inode_percentage_on_mp1 = $free_inodes_on_mp1 / ($total_inodes_on_mp1 / 100);
64 86
65# Do same for inodes 87my $free_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'};
66$_ = $result->output; 88my $total_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'};
67my ($free_inode_on_mp1, $free_inode_on_mp2) = (m/inode=(\d+)%.*inode=(\d+)%/); 89my $free_inode_percentage_on_mp2 = $free_inodes_on_mp2 / ($total_inodes_on_mp2 / 100);
68die "Cannot parse free inodes: $_" unless ($free_inode_on_mp1 && $free_inode_on_mp2); 90
69my $avg_inode_free = ceil(($free_inode_on_mp1 + $free_inode_on_mp2)/2); 91my $avg_inode_free_percentage = ceil(($free_inode_percentage_on_mp1 + $free_inode_percentage_on_mp2)/2);
70my ($more_inode_free, $less_inode_free); 92my ($more_inode_free, $less_inode_free);
71if ($free_inode_on_mp1 > $free_inode_on_mp2) { 93if ($free_inode_percentage_on_mp1 > $free_inode_percentage_on_mp2) {
72 $more_inode_free = $mountpoint_valid; 94 $more_inode_free = $mountpoint_valid;
73 $less_inode_free = $mountpoint2_valid; 95 $less_inode_free = $mountpoint2_valid;
74} elsif ($free_inode_on_mp1 < $free_inode_on_mp2) { 96} elsif ($free_inode_percentage_on_mp1 < $free_inode_percentage_on_mp2) {
75 $more_inode_free = $mountpoint2_valid; 97 $more_inode_free = $mountpoint2_valid;
76 $less_inode_free = $mountpoint_valid; 98 $less_inode_free = $mountpoint_valid;
77} else { 99} else {
78 die "Two mountpoints with same inodes free - cannot do rest of test"; 100 die "Two mountpoints with same inodes free - cannot do rest of test";
79} 101}
80if($free_inode_on_mp1 == $avg_inode_free || $free_inode_on_mp2 == $avg_inode_free) { 102if($free_inode_percentage_on_mp1 == $avg_inode_free_percentage || $free_inode_percentage_on_mp2 == $avg_inode_free_percentage) {
81 die "One mountpoints has average inodes free - cannot do rest of test"; 103 die "One mountpoints has average inodes free - cannot do rest of test";
82} 104}
83 105
84# Verify performance data 106# Verify performance data
85# First check absolute thresholds... 107# First check absolute thresholds...
86$result = NPTest->testCmd( 108$result = NPTest->testCmd(
87 "./check_disk -w 20 -c 10 -p $mountpoint_valid" 109 "./check_disk -w 20 -c 10 -p $mountpoint_valid $output_format"
88 ); 110 );
89$_ = $result->perf_output; 111
90my ($warn_absth_data, $crit_absth_data, $total_absth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/); 112cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
91# default unit is MiB, but perfdata is always bytes 113
92is ($warn_absth_data, $total_absth_data - (20 * (2 ** 20)), "Wrong warning in perf data using absolute thresholds"); 114my $warn_absth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'warn'}->{'end'}->{'value'};
93is ($crit_absth_data, $total_absth_data - (10 * (2 ** 20)), "Wrong critical in perf data using absolute thresholds"); 115my $crit_absth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'crit'}->{'end'}->{'value'};
116my $total_absth_data= $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'max'}->{'value'};
117
118# print("warn: " .$warn_absth_data . "\n");
119# print("crit: " .$crit_absth_data . "\n");
120# print("total: " .$total_absth_data . "\n");
121
122is ($warn_absth_data <=> (20 * (2 ** 20)), 0, "Wrong warning in perf data using absolute thresholds");
123is ($crit_absth_data <=> (10 * (2 ** 20)), 0, "Wrong critical in perf data using absolute thresholds");
94 124
95# Then check percent thresholds. 125# Then check percent thresholds.
96$result = NPTest->testCmd( 126$result = NPTest->testCmd(
97 "./check_disk -w 20% -c 10% -p $mountpoint_valid" 127 "./check_disk -w 20% -c 10% -p $mountpoint_valid $output_format"
98 ); 128 );
99$_ = $result->perf_output; 129
100my ($warn_percth_data, $crit_percth_data, $total_percth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/); 130cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
101is ($warn_percth_data, int((1-20/100)*$total_percth_data), "Wrong warning in perf data using percent thresholds"); 131
102is ($crit_percth_data, int((1-10/100)*$total_percth_data), "Wrong critical in perf data using percent thresholds"); 132my $warn_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'warn'}->{'end'}->{'value'};
133my $crit_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'crit'}->{'end'}->{'value'};
134my $total_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'max'}->{'value'};
135
136print("warn_percth_data: " . $warn_percth_data . "\n");
137print("crit_percth_data: " . $crit_percth_data . "\n");
138
139is (int($warn_percth_data), int((20/100)*$total_percth_data), "Wrong warning in perf data using percent thresholds. Got " . $warn_percth_data . " with total " . $total_percth_data);
140is (int($crit_percth_data), int((10/100)*$total_percth_data), "Wrong critical in perf data using percent thresholds. Got " . $crit_percth_data . " with total " . $total_percth_data);
103 141
104 142
105# Check when order of mount points are reversed, that perf data remains same 143# Check when order of mount points are reversed, that perf data remains same
106$result = NPTest->testCmd( 144$result = NPTest->testCmd(
107 "./check_disk -w 1% -c 1% -p $mountpoint2_valid -w 1% -c 1% -p $mountpoint_valid" 145 "./check_disk -w 1% -c 1% -p $mountpoint2_valid -w 1% -c 1% -p $mountpoint_valid $output_format"
108 ); 146 );
109@_ = sort(split(/ /, $result->perf_output)); 147cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
110is_deeply( \@perf_data, \@_, "perf data for both filesystems same when reversed");
111 148
149# write comparison set for perfdata here, but in reversed order, maybe there is a smarter way
150my @perfdata2;
151@perfdata2[0] = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0];
152@perfdata2[1] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0];
153# Decrease precision of numbers since the the fs might be modified between the two runs
154$perfdata2[0]->{'value'}->{'value'} = int($perfdata2[0]->{'value'}->{'value'} / 1000000);
155$perfdata2[1]->{'value'}->{'value'} = int($perfdata2[1]->{'value'}->{'value'} / 1000000);
156is_deeply(\@perfdata, \@perfdata2, "perf data for both filesystems same when reversed");
112 157
113# Basic filesystem checks for sizes 158# Basic filesystem checks for sizes
114$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free" ); 159$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free $output_format");
115cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free"); 160cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
116like ( $result->output, $successOutput, "OK output" ); 161like($result->{'mp_test_result'}->{'state'}, "/OK/", "At least 1 MB available on $more_free");
117like ( $result->only_output, qr/free space/, "Have free space text");
118like ( $result->only_output, qr/$more_free/, "Have disk name in text");
119 162
120$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free -p $less_free" ); 163$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free -p $less_free $output_format" );
121cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free and $less_free"); 164cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
165like($result->{'mp_test_result'}->{'state'}, "/OK/", "At least 1 MB available on $more_free and $less_free");
122 166
123$_ = $result->output; 167my $free_mb_on_mp1 =$result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'} / (1024 * 1024);
124 168my $free_mb_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'}/ (1024 * 1024);
125my ($free_mb_on_mp1, $free_mb_on_mp2) = (m/(\d+)MiB .* (\d+)MiB /g);
126die "Cannot parse output: $_" unless ($free_mb_on_mp1 && $free_mb_on_mp2); 169die "Cannot parse output: $_" unless ($free_mb_on_mp1 && $free_mb_on_mp2);
127 170
128my $free_mb_on_all = $free_mb_on_mp1 + $free_mb_on_mp2; 171my $free_mb_on_all = $free_mb_on_mp1 + $free_mb_on_mp2;
129 172
130 173
174$result = NPTest->testCmd( "./check_disk -e -w 1 -c 1 -p $more_free $output_format" );
175cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
131 176
132$result = NPTest->testCmd( "./check_disk -e -w 1 -c 1 -p $more_free" ); 177$result = NPTest->testCmd( "./check_disk 101 101 $more_free" );
133is( $result->only_output, "DISK OK", "No print out of disks with -e for OKs"); 178like($result->output, "/OK/", "OK in Output");
134 179cmp_ok( $result->return_code, '==', 0, "Old syntax okay, output was: ". $result->output . "\n" );
135$result = NPTest->testCmd( "./check_disk 100 100 $more_free" );
136cmp_ok( $result->return_code, '==', 0, "Old syntax okay" );
137 180
138$result = NPTest->testCmd( "./check_disk -w 1% -c 1% -p $more_free" ); 181$result = NPTest->testCmd( "./check_disk -w 1% -c 1% -p $more_free" );
139cmp_ok( $result->return_code, "==", 0, "At least 1% free" ); 182cmp_ok( $result->return_code, "==", 0, "At least 1% free" );
140 183
141$result = NPTest->testCmd( 184$result = NPTest->testCmd(
142 "./check_disk -w 1% -c 1% -p $more_free -w 100% -c 100% -p $less_free" 185 "./check_disk -w 1% -c 1% -p $more_free -w 100% -c 100% -p $less_free $output_format"
143 ); 186 );
144cmp_ok( $result->return_code, "==", 2, "Get critical on less_free mountpoint $less_free" ); 187cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
145like( $result->output, $failureOutput, "Right output" ); 188like($result->{'mp_test_result'}->{'state'}, "/CRITICAL/", "Get critical on less_free mountpoint $less_free");
146 189
147 190
148$result = NPTest->testCmd( 191$result = NPTest->testCmd(
149 "./check_disk -w $avg_free% -c 0% -p $less_free" 192 "./check_disk -w $avg_free_percent% -c 0% -p $less_free $output_format"
150 ); 193 );
151cmp_ok( $result->return_code, '==', 1, "Get warning on less_free mountpoint, when checking avg_free"); 194cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
195like($result->{'mp_test_result'}->{'state'}, "/WARNING/", "Get warning on less_free mountpoint, when checking avg_free");
152 196
153$result = NPTest->testCmd( 197$result = NPTest->testCmd(
154 "./check_disk -w $avg_free% -c $avg_free% -p $more_free" 198 "./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $more_free"
155 ); 199 );
156cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, when checking avg_free"); 200cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, when checking avg_free");
157 201
158$result = NPTest->testCmd( 202$result = NPTest->testCmd(
159 "./check_disk -w $avg_free% -c 0% -p $less_free -w $avg_free% -c $avg_free% -p $more_free" 203 "./check_disk -w $avg_free_percent% -c 0% -p $less_free -w $avg_free_percent% -c $avg_free_percent% -p $more_free"
160 ); 204 );
161cmp_ok( $result->return_code, "==", 1, "Combining above two tests, get warning"); 205cmp_ok( $result->return_code, "==", 1, "Combining above two tests, get warning");
162my $all_disks = $result->output; 206my $all_disks = $result->output;
163 207
164$result = NPTest->testCmd( 208$result = NPTest->testCmd(
165 "./check_disk -e -w $avg_free% -c 0% -p $less_free -w $avg_free% -c $avg_free% -p $more_free" 209 "./check_disk -e -w $avg_free_percent% -c 0% -p $less_free -w $avg_free_percent% -c $avg_free_percent% -p $more_free"
166 ); 210 );
167isnt( $result->output, $all_disks, "-e gives different output"); 211isnt( $result->output, $all_disks, "-e gives different output");
168 212
169# Need spaces around filesystem name in case less_free and more_free are nested 213# Need spaces around filesystem name in case less_free and more_free are nested
170like( $result->output, qr/ $less_free /, "Found problem $less_free"); 214like( $result->output, qr/ $less_free /, "Found problem $less_free");
171unlike( $result->only_output, qr/ $more_free /, "Has ignored $more_free as not a problem"); 215unlike( $result->only_output, qr/ $more_free /, "Has ignored $more_free as not a problem");
172like( $result->perf_output, qr/ $more_free=/, "But $more_free is still in perf data"); 216like( $result->perf_output, qr/'$more_free'=/, "But $more_free is still in perf data");
173 217
174$result = NPTest->testCmd( 218$result = NPTest->testCmd(
175 "./check_disk -w $avg_free% -c 0% -p $more_free" 219 "./check_disk -w $avg_free_percent% -c 0% -p $more_free"
176 ); 220 );
177cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, checking avg_free"); 221cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, checking avg_free");
178 222
179$result = NPTest->testCmd( 223$result = NPTest->testCmd(
180 "./check_disk -w $avg_free% -c $avg_free% -p $less_free" 224 "./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $less_free"
181 ); 225 );
182cmp_ok( $result->return_code, '==', 2, "Get critical on less_free, checking avg_free"); 226cmp_ok( $result->return_code, '==', 2, "Get critical on less_free, checking avg_free");
183$result = NPTest->testCmd( 227$result = NPTest->testCmd(
184 "./check_disk -w $avg_free% -c 0% -p $more_free -w $avg_free% -c $avg_free% -p $less_free" 228 "./check_disk -w $avg_free_percent% -c 0% -p $more_free -w $avg_free_percent% -c $avg_free_percent% -p $less_free"
185 ); 229 );
186cmp_ok( $result->return_code, '==', 2, "Combining above two tests, get critical"); 230cmp_ok( $result->return_code, '==', 2, "Combining above two tests, get critical");
187 231
188$result = NPTest->testCmd( 232$result = NPTest->testCmd(
189 "./check_disk -w $avg_free% -c $avg_free% -p $less_free -w $avg_free% -c 0% -p $more_free" 233 "./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $less_free -w $avg_free_percent% -c 0% -p $more_free"
190 ); 234 );
191cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference"); 235cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference");
192 236
@@ -203,32 +247,32 @@ is( $result->return_code, 2, "Critical requesting 100% free inodes for both moun
203$result = NPTest->testCmd( "./check_disk --iwarning 1% --icritical 1% -p $more_inode_free -K 100% -W 100% -p $less_inode_free" ); 247$result = NPTest->testCmd( "./check_disk --iwarning 1% --icritical 1% -p $more_inode_free -K 100% -W 100% -p $less_inode_free" );
204is( $result->return_code, 2, "Get critical on less_inode_free mountpoint $less_inode_free"); 248is( $result->return_code, 2, "Get critical on less_inode_free mountpoint $less_inode_free");
205 249
206$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $less_inode_free" ); 250$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $less_inode_free" );
207is( $result->return_code, 1, "Get warning on less_inode_free, when checking average"); 251is( $result->return_code, 1, "Get warning on less_inode_free, when checking average");
208 252
209$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free "); 253$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free ");
210is( $result->return_code, 0, "Get ok on more_inode_free when checking average"); 254is( $result->return_code, 0, "Get ok on more_inode_free when checking average");
211 255
212$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $less_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free" ); 256$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $less_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free" );
213is ($result->return_code, 1, "Combine above two tests, get warning"); 257is ($result->return_code, 1, "Combine above two tests, get warning");
214$all_disks = $result->output; 258$all_disks = $result->output;
215 259
216$result = NPTest->testCmd( "./check_disk -e -W $avg_inode_free% -K 0% -p $less_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free" ); 260$result = NPTest->testCmd( "./check_disk -e -W $avg_inode_free_percentage% -K 0% -p $less_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free" );
217isnt( $result->output, $all_disks, "-e gives different output"); 261isnt( $result->output, $all_disks, "-e gives different output");
218like( $result->output, qr/$less_inode_free/, "Found problem $less_inode_free"); 262like( $result->output, qr/$less_inode_free/, "Found problem $less_inode_free");
219unlike( $result->only_output, qr/$more_inode_free\s/, "Has ignored $more_inode_free as not a problem"); 263unlike( $result->only_output, qr/$more_inode_free\s/, "Has ignored $more_inode_free as not a problem");
220like( $result->perf_output, qr/$more_inode_free/, "But $more_inode_free is still in perf data"); 264like( $result->perf_output, qr/$more_inode_free/, "But $more_inode_free is still in perf data");
221 265
222$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $more_inode_free" ); 266$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $more_inode_free" );
223is( $result->return_code, 0, "Get ok on more_inode_free mountpoint, checking average"); 267is( $result->return_code, 0, "Get ok on more_inode_free mountpoint, checking average");
224 268
225$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free" ); 269$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free" );
226is( $result->return_code, 2, "Get critical on less_inode_free, checking average"); 270is( $result->return_code, 2, "Get critical on less_inode_free, checking average");
227 271
228$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $more_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free" ); 272$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $more_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free" );
229is( $result->return_code, 2, "Combining above two tests, get critical"); 273is( $result->return_code, 2, "Combining above two tests, get critical");
230 274
231$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free -W $avg_inode_free% -K 0% -p $more_inode_free" ); 275$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free -W $avg_inode_free_percentage% -K 0% -p $more_inode_free" );
232cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference"); 276cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference");
233 277
234 278
@@ -249,9 +293,9 @@ $result = NPTest->testCmd(
249 ); 293 );
250cmp_ok( $result->return_code, "==", 3, "Invalid options: -p must come after thresholds" ); 294cmp_ok( $result->return_code, "==", 3, "Invalid options: -p must come after thresholds" );
251 295
252$result = NPTest->testCmd( "./check_disk -w 100% -c 100% ".${mountpoint_valid} ); # 100% empty 296$result = NPTest->testCmd( "./check_disk -w 100% -c 100% $output_format ".${mountpoint_valid} ); # 100% empty
253cmp_ok( $result->return_code, "==", 2, "100% empty" ); 297cmp_ok( $result->return_code, "==", 0, "100% empty" );
254like( $result->output, $failureOutput, "Right output" ); 298like($result->{'mp_test_result'}->{'state'}, "/CRITICAL/", "100% empty");
255 299
256$result = NPTest->testCmd( "./check_disk -w 100000000 -c 100000000 $mountpoint_valid" ); 300$result = NPTest->testCmd( "./check_disk -w 100000000 -c 100000000 $mountpoint_valid" );
257cmp_ok( $result->return_code, '==', 2, "Check for 100TB free" ); 301cmp_ok( $result->return_code, '==', 2, "Check for 100TB free" );
@@ -263,7 +307,8 @@ cmp_ok( $result->return_code, "==", 2, "100 TB empty" );
263# Checking old syntax of check_disk warn crit [fs], with warn/crit at USED% thresholds 307# Checking old syntax of check_disk warn crit [fs], with warn/crit at USED% thresholds
264$result = NPTest->testCmd( "./check_disk 0 0 ".${mountpoint_valid} ); 308$result = NPTest->testCmd( "./check_disk 0 0 ".${mountpoint_valid} );
265cmp_ok( $result->return_code, "==", 2, "Old syntax: 0% used"); 309cmp_ok( $result->return_code, "==", 2, "Old syntax: 0% used");
266like ( $result->only_output, qr(^[^;]*;[^;]*$), "Select only one path with positional arguments"); 310# like ( $result->only_output, qr(^[^;]*;[^;]*$), "Select only one path with positional arguments");
311# TODO not sure what the above should test, taking it out
267 312
268$result = NPTest->testCmd( "./check_disk 100 100 $mountpoint_valid" ); 313$result = NPTest->testCmd( "./check_disk 100 100 $mountpoint_valid" );
269cmp_ok( $result->return_code, '==', 0, "Old syntax: 100% used" ); 314cmp_ok( $result->return_code, '==', 0, "Old syntax: 100% used" );
@@ -311,8 +356,9 @@ $result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p / -p /" );
311unlike( $result->output, '/ \/ .* \/ /', "Should not show same filesystem twice"); 356unlike( $result->output, '/ \/ .* \/ /', "Should not show same filesystem twice");
312 357
313# are partitions added if -C is given without path selection -p ? 358# are partitions added if -C is given without path selection -p ?
314$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -C -w 0% -c 0% -p $mountpoint_valid" ); 359$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -C -w 0% -c 0% -p $mountpoint_valid $output_format" );
315like( $result->output, '/;.*;\|/', "-C selects partitions if -p is not given"); 360cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
361cmp_ok(scalar $result->{'mp_test_result'}->{'checks'}, '>', 1, "-C invokes matchall logic again");
316 362
317# grouping: exit crit if the sum of free megs on mp1+mp2 is less than warn/crit 363# grouping: exit crit if the sum of free megs on mp1+mp2 is less than warn/crit
318$result = NPTest->testCmd( "./check_disk -w ". ($free_mb_on_all + 1) ." -c ". ($free_mb_on_all + 1) ." -g group -p $mountpoint_valid -p $mountpoint2_valid" ); 364$result = NPTest->testCmd( "./check_disk -w ". ($free_mb_on_all + 1) ." -c ". ($free_mb_on_all + 1) ." -g group -p $mountpoint_valid -p $mountpoint2_valid" );
@@ -359,39 +405,37 @@ like( $result->output, qr/$mountpoint2_valid/,"ignore: output data does have $mo
359# ignore-missing: exit okay, when fs is not accessible 405# ignore-missing: exit okay, when fs is not accessible
360$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p /bob"); 406$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p /bob");
361cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for not existing filesystem /bob"); 407cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for not existing filesystem /bob");
362like( $result->output, '/^DISK OK - No disks were found for provided parameters - ignored paths: /bob;.*$/', 'Output OK'); 408like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
363 409
364# ignore-missing: exit okay, when regex does not match 410# ignore-missing: exit okay, when regex does not match
365$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r /bob"); 411$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r /bob");
366cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 412cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
367like( $result->output, '/^DISK OK - No disks were found for provided parameters.*$/', 'Output OK'); 413like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
368 414
369# ignore-missing: exit okay, when fs with exact match (-E) is not found 415# ignore-missing: exit okay, when fs with exact match (-E) is not found
370$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -E -p /etc"); 416$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -E -p /etc");
371cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay when exact match does not find fs"); 417cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay when exact match does not find fs");
372like( $result->output, '/^DISK OK - No disks were found for provided parameters - ignored paths: /etc;.*$/', 'Output OK'); 418like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
373 419
374# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (regex) 420# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (regex)
375$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r '/bob' -r '^/\$'"); 421$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r '/bob' -r '^/\$'");
376cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 422cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
377like( $result->output, '/^DISK OK - free space: \/ .*$/', 'Output OK');
378 423
379# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (path) 424# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (path)
380$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p '/bob' -p '/'"); 425$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p '/bob' -p '/'");
381cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 426cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
382like( $result->output, '/^DISK OK - free space: / .*; - ignored paths: /bob;.*$/', 'Output OK'); 427# like( $result->output, '/^DISK OK - free space: / .*; - ignored paths: /bob;.*$/', 'Output OK');
383 428
384# ignore-missing: exit okay, when checking one non-existing fs (path) and one ignored 429# ignore-missing: exit okay, when checking one non-existing fs (path) and one ignored
385$result = NPTest->testCmd( "./check_disk -n -w 0% -c 0% -r /dummy -i /dummy2"); 430$result = NPTest->testCmd( "./check_disk -n -w 0% -c 0% -r /dummy -i /dummy2");
386cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 431cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
387like( $result->output, '/^DISK OK - No disks were found for provided parameters\|$/', 'Output OK'); 432like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
388 433
389# ignore-missing: exit okay, when regex match does not find anything 434# ignore-missing: exit okay, when regex match does not find anything
390$result = NPTest->testCmd( "./check_disk -n -e -l -w 10% -c 5% -W 10% -K 5% -r /dummy"); 435$result = NPTest->testCmd( "./check_disk -n -e -l -w 10% -c 5% -W 10% -K 5% -r /dummy");
391cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 436cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
392like( $result->output, '/^DISK OK\|$/', 'Output OK');
393 437
394# ignore-missing: exit okay, when regex match does not find anything 438# ignore-missing: exit okay, when regex match does not find anything
395$result = NPTest->testCmd( "./check_disk -n -l -w 10% -c 5% -W 10% -K 5% -r /dummy"); 439$result = NPTest->testCmd( "./check_disk -n -l -w 10% -c 5% -W 10% -K 5% -r /dummy");
396cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 440cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
397like( $result->output, '/^DISK OK - No disks were found for provided parameters\|$/', 'Output OK'); 441like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
diff --git a/plugins/t/check_ftp.t b/plugins/t/check_ftp.t
index 93a7d7c3..a2f79dca 100644
--- a/plugins/t/check_ftp.t
+++ b/plugins/t/check_ftp.t
@@ -15,7 +15,7 @@ my $host_tcp_ftp = getTestParameter("NP_HOST_TCP_FTP", "A host providing t
15my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1"); 15my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
16my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost"); 16my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
17 17
18my $successOutput = '/FTP OK -\s+[0-9]?\.?[0-9]+ second response time/'; 18my $successOutput = '/Connection time\s+[0-9]?\.?[0-9]+/';
19 19
20my $t; 20my $t;
21 21
diff --git a/plugins/t/check_jabber.t b/plugins/t/check_jabber.t
index 08cadcbd..dc46f4c3 100644
--- a/plugins/t/check_jabber.t
+++ b/plugins/t/check_jabber.t
@@ -15,11 +15,11 @@ my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname
15my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost"); 15my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
16 16
17 17
18my $jabberOK = '/JABBER OK\s-\s\d+\.\d+\ssecond response time on '.$host_tcp_jabber.' port 5222/'; 18my $jabberOK = '/Connection to '.$host_tcp_jabber.' on port 5222/';
19 19
20my $jabberUnresponsive = '/Socket timeout after\s\d+\sseconds/'; 20my $jabberUnresponsive = '/Socket timeout after\s\d+\sseconds/';
21 21
22my $jabberInvalid = '/JABBER CRITICAL - Invalid hostname, address or socket:\s.+/'; 22my $jabberInvalid = '/Invalid hostname, address or socket:\s.+/';
23 23
24my $r; 24my $r;
25 25
diff --git a/plugins/t/check_ldap.t b/plugins/t/check_ldap.t
index fcba0393..f3162ebb 100644
--- a/plugins/t/check_ldap.t
+++ b/plugins/t/check_ldap.t
@@ -32,7 +32,7 @@ SKIP: {
32 32
33 $result = NPTest->testCmd("$command -H $hostname_invalid -b ou=blah -t 5"); 33 $result = NPTest->testCmd("$command -H $hostname_invalid -b ou=blah -t 5");
34 is( $result->return_code, 2, "$command -H $hostname_invalid -b ou=blah -t 5" ); 34 is( $result->return_code, 2, "$command -H $hostname_invalid -b ou=blah -t 5" );
35 is( $result->output, 'Could not bind to the LDAP server', "output ok" ); 35 like( $result->output, '/could not bind to the LDAP server/', "output ok" );
36}; 36};
37 37
38SKIP: { 38SKIP: {
@@ -42,30 +42,30 @@ SKIP: {
42 $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3"; 42 $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3";
43 $result = NPTest->testCmd($cmd); 43 $result = NPTest->testCmd($cmd);
44 is( $result->return_code, 0, $cmd ); 44 is( $result->return_code, 0, $cmd );
45 like( $result->output, '/^LDAP OK - \d+.\d+ seconds response time\|time=\d+\.\d+s;2\.0+;3\.0+;0\.0+$/', "output ok" ); 45 like( $result->output, '/connection time \d+.\d+s/', "output ok" );
46 46
47 $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000 -C 10000001"; 47 $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000 -C 10000001";
48 $result = NPTest->testCmd($cmd); 48 $result = NPTest->testCmd($cmd);
49 is( $result->return_code, 0, $cmd ); 49 is( $result->return_code, 0, $cmd );
50 like( $result->output, '/^LDAP OK - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;10000000;10000001;0\.0+$/', "output ok" ); 50 like( $result->output, '/found \d+ entries/', "output ok" );
51 51
52 $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001:"; 52 $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001:";
53 $result = NPTest->testCmd($cmd); 53 $result = NPTest->testCmd($cmd);
54 is( $result->return_code, 2, $cmd ); 54 is( $result->return_code, 2, $cmd );
55 like( $result->output, '/^LDAP CRITICAL - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;10000000:;10000001:;0\.0+$/', "output ok" ); 55 like( $result->output, '/found \d+ entries/', "output ok" );
56 56
57 $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 0 -C 0"; 57 $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 0 -C 0";
58 $result = NPTest->testCmd($cmd); 58 $result = NPTest->testCmd($cmd);
59 is( $result->return_code, 2, $cmd ); 59 is( $result->return_code, 2, $cmd );
60 like( $result->output, '/^LDAP CRITICAL - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;0;0;0\.0+$/', "output ok" ); 60 like( $result->output, '/found \d+ entries/', "output ok" );
61 61
62 $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001"; 62 $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001";
63 $result = NPTest->testCmd($cmd); 63 $result = NPTest->testCmd($cmd);
64 is( $result->return_code, 1, $cmd ); 64 is( $result->return_code, 1, $cmd );
65 like( $result->output, '/^LDAP WARNING - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;10000000:;10000001;0\.0+$/', "output ok" ); 65 like( $result->output, '/found \d+ entries/', "output ok" );
66 66
67 $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -C 10000001"; 67 $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -C 10000001";
68 $result = NPTest->testCmd($cmd); 68 $result = NPTest->testCmd($cmd);
69 is( $result->return_code, 0, $cmd ); 69 is( $result->return_code, 0, $cmd );
70 like( $result->output, '/^LDAP OK - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;;10000001;0\.0+$/', "output ok" ); 70 like( $result->output, '/found \d+ entries/', "output ok" );
71}; 71};
diff --git a/plugins/t/check_load.t b/plugins/t/check_load.t
index bba8947c..fc26bb35 100644
--- a/plugins/t/check_load.t
+++ b/plugins/t/check_load.t
@@ -16,28 +16,28 @@ my $successScaledOutput = "/^LOAD OK - scaled load average: $loadValue, $loadVal
16my $failureOutput = "/^LOAD CRITICAL - total load average: $loadValue, $loadValue, $loadValue/"; 16my $failureOutput = "/^LOAD CRITICAL - total load average: $loadValue, $loadValue, $loadValue/";
17my $failurScaledOutput = "/^LOAD CRITICAL - scaled load average: $loadValue, $loadValue, $loadValue - total load average: $loadValue, $loadValue, $loadValue/"; 17my $failurScaledOutput = "/^LOAD CRITICAL - scaled load average: $loadValue, $loadValue, $loadValue - total load average: $loadValue, $loadValue, $loadValue/";
18 18
19plan tests => 13; 19plan tests => 8;
20 20
21$res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100" ); 21$res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100" );
22cmp_ok( $res->return_code, 'eq', 0, "load not over 100"); 22cmp_ok( $res->return_code, 'eq', 0, "load not over 100");
23like( $res->output, $successOutput, "Output OK"); 23# like( $res->output, $successOutput, "Output OK");
24 24
25$res = NPTest->testCmd( "./check_load -w 0,0,0 -c 0,0,0" ); 25$res = NPTest->testCmd( "./check_load -w 0,0,0 -c 0,0,0" );
26cmp_ok( $res->return_code, 'eq', 2, "Load over 0"); 26cmp_ok( $res->return_code, 'eq', 2, "Load over 0");
27like( $res->output, $failureOutput, "Output OK"); 27# like( $res->output, $failureOutput, "Output OK");
28 28
29$res = NPTest->testCmd( "./check_load -r -w 0,0,0 -c 0,0,0" ); 29$res = NPTest->testCmd( "./check_load -r -w 0,0,0 -c 0,0,0" );
30cmp_ok( $res->return_code, 'eq', 2, "Load over 0 with per cpu division"); 30cmp_ok( $res->return_code, 'eq', 2, "Load over 0 with per cpu division");
31like( $res->output, $failurScaledOutput, "Output OK"); 31# like( $res->output, $failurScaledOutput, "Output OK");
32 32
33$res = NPTest->testCmd( "./check_load -w 100 -c 100,110" ); 33$res = NPTest->testCmd( "./check_load -w 100 -c 100,110" );
34cmp_ok( $res->return_code, 'eq', 0, "Plugin can handle non-triplet-arguments"); 34cmp_ok( $res->return_code, 'eq', 0, "Plugin can handle non-triplet-arguments");
35like( $res->output, $successOutput, "Output OK"); 35# like( $res->output, $successOutput, "Output OK");
36like( $res->perf_output, "/load1=$loadValue;100.000;100.000/", "Test handling of non triplet thresholds (load1)"); 36like( $res->perf_output, "/'load1'=$loadValue;~:100.0+;~:100.0+/", "Test handling of non triplet thresholds (load1)");
37like( $res->perf_output, "/load5=$loadValue;100.000;110.000/", "Test handling of non triplet thresholds (load5)"); 37like( $res->perf_output, "/'load5'=$loadValue;~:100.0+;~:110.0+/", "Test handling of non triplet thresholds (load5)");
38like( $res->perf_output, "/load15=$loadValue;100.000;110.000/", "Test handling of non triplet thresholds (load15)"); 38like( $res->perf_output, "/'load15'=$loadValue;~:100.0+;~:110.0+/", "Test handling of non triplet thresholds (load15)");
39 39
40 40
41$res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100 -r" ); 41$res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100 -r" );
42cmp_ok( $res->return_code, 'eq', 0, "load not over 100"); 42cmp_ok( $res->return_code, 'eq', 0, "load not over 100");
43like( $res->output, $successScaledOutput, "Output OK"); 43# like( $res->output, $successScaledOutput, "Output OK");
diff --git a/plugins/t/check_mysql.t b/plugins/t/check_mysql.t
index a383bc99..9114cccc 100644
--- a/plugins/t/check_mysql.t
+++ b/plugins/t/check_mysql.t
@@ -11,6 +11,7 @@
11# mysql -u$user -p$password -h$host $db 11# mysql -u$user -p$password -h$host $db
12 12
13use strict; 13use strict;
14use warnings;
14use Test::More; 15use Test::More;
15use NPTest; 16use NPTest;
16 17
@@ -40,7 +41,7 @@ SKIP: {
40 41
41 $result = NPTest->testCmd("./check_mysql -S -H $mysqlserver $mysql_login_details"); 42 $result = NPTest->testCmd("./check_mysql -S -H $mysqlserver $mysql_login_details");
42 cmp_ok( $result->return_code, "==", 1, "No replicas defined" ); 43 cmp_ok( $result->return_code, "==", 1, "No replicas defined" );
43 like( $result->output, "/No replicas defined/", "Correct error message"); 44 like( $result->output, "/no replicas defined/", "Correct error message");
44} 45}
45 46
46SKIP: { 47SKIP: {
@@ -54,7 +55,7 @@ SKIP: {
54 55
55 $result = NPTest->testCmd("./check_mysql -S -s $mysqlsocket $mysql_login_details"); 56 $result = NPTest->testCmd("./check_mysql -S -s $mysqlsocket $mysql_login_details");
56 cmp_ok( $result->return_code, "==", 1, "No replicas defined" ); 57 cmp_ok( $result->return_code, "==", 1, "No replicas defined" );
57 like( $result->output, "/No replicas defined/", "Correct error message"); 58 like( $result->output, "/no replicas defined/", "Correct error message");
58} 59}
59 60
60SKIP: { 61SKIP: {
@@ -70,5 +71,5 @@ SKIP: {
70 71
71 $result = NPTest->testCmd("./check_mysql -S -H $with_replica $with_replica_login -w 60:"); 72 $result = NPTest->testCmd("./check_mysql -S -H $with_replica $with_replica_login -w 60:");
72 cmp_ok( $result->return_code, '==', 1, 'Alert warning if < 60 seconds behind'); 73 cmp_ok( $result->return_code, '==', 1, 'Alert warning if < 60 seconds behind');
73 like( $result->output, "/^SLOW_REPLICA WARNING:/", "Output okay"); 74 like( $result->output, "/^slow_replica/", "Output okay");
74} 75}
diff --git a/plugins/t/check_mysql_query.t b/plugins/t/check_mysql_query.t
index c30245b2..6de48bf6 100644
--- a/plugins/t/check_mysql_query.t
+++ b/plugins/t/check_mysql_query.t
@@ -54,5 +54,5 @@ like( $result->output, "/No rows returned/", "No rows error message");
54 54
55$result = NPTest->testCmd("./check_mysql_query -q 'SHOW VARIABLES' -H $mysqlserver $mysql_login_details"); 55$result = NPTest->testCmd("./check_mysql_query -q 'SHOW VARIABLES' -H $mysqlserver $mysql_login_details");
56cmp_ok( $result->return_code, '==', 2, "Data not numeric"); 56cmp_ok( $result->return_code, '==', 2, "Data not numeric");
57like( $result->output, "/Is not a numeric/", "Data not numeric error message"); 57like( $result->output, "/is not numeric/", "Data not numeric error message");
58 58
diff --git a/plugins/t/check_ntp.t b/plugins/t/check_ntp.t
index a8ac7bb8..7703bc3b 100644
--- a/plugins/t/check_ntp.t
+++ b/plugins/t/check_ntp.t
@@ -8,7 +8,7 @@ use strict;
8use Test::More; 8use Test::More;
9use NPTest; 9use NPTest;
10 10
11my @PLUGINS1 = ('check_ntp', 'check_ntp_peer', 'check_ntp_time'); 11my @PLUGINS1 = ('check_ntp_peer', 'check_ntp_time');
12my @PLUGINS2 = ('check_ntp_peer'); 12my @PLUGINS2 = ('check_ntp_peer');
13 13
14plan tests => (12 * scalar(@PLUGINS1)) + (6 * scalar(@PLUGINS2)); 14plan tests => (12 * scalar(@PLUGINS1)) + (6 * scalar(@PLUGINS2));
diff --git a/plugins/t/check_smtp.t b/plugins/t/check_smtp.t
index 73b4a1fd..c2f53c3d 100644
--- a/plugins/t/check_smtp.t
+++ b/plugins/t/check_smtp.t
@@ -5,6 +5,7 @@
5# 5#
6 6
7use strict; 7use strict;
8use warnings;
8use Test::More; 9use Test::More;
9use NPTest; 10use NPTest;
10 11
@@ -24,7 +25,7 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
24 "An invalid (not known to DNS) hostname", "nosuchhost" ); 25 "An invalid (not known to DNS) hostname", "nosuchhost" );
25my $res; 26my $res;
26 27
27plan tests => 15; 28plan tests => 13;
28 29
29SKIP: { 30SKIP: {
30 skip "No SMTP server defined", 4 unless $host_tcp_smtp; 31 skip "No SMTP server defined", 4 unless $host_tcp_smtp;
@@ -42,12 +43,11 @@ SKIP: {
42 43
43 TODO: { 44 TODO: {
44 local $TODO = "Output is over two lines"; 45 local $TODO = "Output is over two lines";
45 like ( $res->output, qr/^SMTP WARNING/, "Correct error message" );
46 } 46 }
47 47
48 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp --ssl -p 25" ); 48 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp --ssl -p 25" );
49 is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp with TLS on standard SMTP port" ); 49 is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp with TLS on standard SMTP port" );
50 like ($res->output, qr/^CRITICAL - Cannot make SSL connection\./, "Check output of connecting to $host_tcp_smtp with TLS on standard SMTP port"); 50 like ($res->output, qr/cannot create TLS context/, "Check output of connecting to $host_tcp_smtp with TLS on standard SMTP port");
51} 51}
52 52
53SKIP: { 53SKIP: {
@@ -68,7 +68,6 @@ SKIP: {
68 skip "No SMTP server with TLS defined", 1 unless $host_tcp_smtp_tls; 68 skip "No SMTP server with TLS defined", 1 unless $host_tcp_smtp_tls;
69 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls --ssl" ); 69 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls --ssl" );
70 is ($res->return_code, 0, "Check rc of connecting to $host_tcp_smtp_tls with TLS" ); 70 is ($res->return_code, 0, "Check rc of connecting to $host_tcp_smtp_tls with TLS" );
71 like ($res->output, qr/^SMTP OK - /, "Check output of connecting to $host_tcp_smtp_tls with TLS" );
72 71
73 my $unused_port = 4465; 72 my $unused_port = 4465;
74 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p $unused_port --ssl" ); 73 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p $unused_port --ssl" );
diff --git a/plugins/t/check_snmp.t b/plugins/t/check_snmp.t
index 576cc506..8d435df3 100644
--- a/plugins/t/check_snmp.t
+++ b/plugins/t/check_snmp.t
@@ -10,7 +10,7 @@ use NPTest;
10 10
11BEGIN { 11BEGIN {
12 plan skip_all => 'check_snmp is not compiled' unless -x "./check_snmp"; 12 plan skip_all => 'check_snmp is not compiled' unless -x "./check_snmp";
13 plan tests => 63; 13 plan tests => 62;
14} 14}
15 15
16my $res; 16my $res;
@@ -24,7 +24,7 @@ my $user_snmp = getTestParameter("NP_SNMP_USER", "An SNMP user", "auth_
24 24
25$res = NPTest->testCmd( "./check_snmp -t 1" ); 25$res = NPTest->testCmd( "./check_snmp -t 1" );
26is( $res->return_code, 3, "No host name" ); 26is( $res->return_code, 3, "No host name" );
27is( $res->output, "No host specified" ); 27is( $res->output, "No OIDs specified" );
28 28
29$res = NPTest->testCmd( "./check_snmp -H fakehostname --ignore-mib-parsing-errors" ); 29$res = NPTest->testCmd( "./check_snmp -H fakehostname --ignore-mib-parsing-errors" );
30is( $res->return_code, 3, "No OIDs specified" ); 30is( $res->return_code, 3, "No OIDs specified" );
@@ -32,145 +32,124 @@ is( $res->output, "No OIDs specified" );
32 32
33$res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3 -U not_a_user --seclevel=rubbish" ); 33$res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3 -U not_a_user --seclevel=rubbish" );
34is( $res->return_code, 3, "Invalid seclevel" ); 34is( $res->return_code, 3, "Invalid seclevel" );
35like( $res->output, "/check_snmp: Invalid seclevel - rubbish/" ); 35like( $res->output, "/invalid security level: rubbish/" );
36 36
37$res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3c" ); 37$res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3c" );
38is( $res->return_code, 3, "Invalid protocol" ); 38is( $res->return_code, 3, "Invalid protocol" );
39like( $res->output, "/check_snmp: Invalid SNMP version - 3c/" ); 39like( $res->output, "/invalid SNMP version/protocol: 3c/" );
40 40
41SKIP: { 41SKIP: {
42 skip "no snmp host defined", 50 if ( ! $host_snmp ); 42 skip "no snmp host defined", 50 if ( ! $host_snmp );
43 43
44 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -w 1: -c 1:"); 44 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -P 2c -C $snmp_community -o system.sysUpTime.0 -w 1: -c 1:");
45 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying uptime" ); 45 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying uptime" );
46 like($res->output, '/^SNMP OK - (\d+)/', "String contains SNMP OK"); 46 $res->output =~ /\|.*=(\d+);/;
47 $res->output =~ /^SNMP OK - (\d+)/;
48 my $value = $1; 47 my $value = $1;
49 cmp_ok( $value, ">", 0, "Got a time value" ); 48 cmp_ok( $value, ">", 0, "Got a time value" );
50 like($res->perf_output, "/sysUpTime.*$1/", "Got perfdata with value '$1' in it"); 49 like($res->perf_output, "/sysUpTime.*$1/", "Got perfdata with value '$1' in it");
51 50
52 51
53 # some more threshold tests 52 # some more threshold tests
54 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1"); 53 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1 -P 2c");
55 cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1" ); 54 cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1" );
56 55
57 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:"); 56 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1: -P 2c");
58 cmp_ok( $res->return_code, '==', 0, "Threshold test -c 1:" ); 57 cmp_ok( $res->return_code, '==', 0, "Threshold test -c 1:" );
59 58
60 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c ~:1"); 59 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c ~:1 -P 2c");
61 cmp_ok( $res->return_code, '==', 2, "Threshold test -c ~:1" ); 60 cmp_ok( $res->return_code, '==', 2, "Threshold test -c ~:1" );
62 61
63 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:10"); 62 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:10 -P 2c");
64 cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1:10" ); 63 cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1:10" );
65 64
66 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c \@1:10"); 65 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c \@1:10 -P 2c");
67 cmp_ok( $res->return_code, '==', 0, "Threshold test -c \@1:10" ); 66 cmp_ok( $res->return_code, '==', 0, "Threshold test -c \@1:10" );
68 67
69 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 10:1");
70 cmp_ok( $res->return_code, '==', 0, "Threshold test -c 10:1" );
71
72 68
73 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o .1.3.6.1.2.1.1.3.0 -w 1: -c 1:"); 69 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o .1.3.6.1.2.1.1.3.0 -w 1: -c 1: -P 2c");
74 cmp_ok( $res->return_code, '==', 0, "Test with numeric OID (no mibs loaded)" ); 70 cmp_ok( $res->return_code, '==', 0, "Test with numeric OID (no mibs loaded)" );
75 like($res->output, '/^SNMP OK - \d+/', "String contains SNMP OK");
76 71
77 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0"); 72 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0 -P 2c");
78 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying sysDescr" ); 73 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying sysDescr" );
79 unlike($res->perf_output, '/sysDescr/', "Perfdata doesn't contain string values"); 74 unlike($res->perf_output, '/sysDescr/', "Perfdata doesn't contain string values");
80 75
81 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0,system.sysDescr.0"); 76 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0,system.sysDescr.0 -P 2c");
82 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, comma-separated" ); 77 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, comma-separated" );
83 like($res->output, '/^SNMP OK - /', "String contains SNMP OK");
84 78
85 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0 -o system.sysDescr.0"); 79 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0 -o system.sysDescr.0 -P 2c");
86 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, repeated option" ); 80 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, repeated option" );
87 like($res->output, '/^SNMP OK - /', "String contains SNMP OK");
88 81
89 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 1:1 -c 1:1"); 82 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 1:1 -c 1:1 -P 2c");
90 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrSWRunIndex.1" ); 83 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrSWRunIndex.1" );
91 like($res->output, '/^SNMP OK - 1\s.*$/', "String fits SNMP OK and output format");
92 84
93 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 0 -c 1:"); 85 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 0 -c 1: -P 2c");
94 cmp_ok( $res->return_code, '==', 1, "Exit WARNING when querying hrSWRunIndex.1 and warn-th doesn't apply " ); 86 cmp_ok( $res->return_code, '==', 1, "Exit WARNING when querying hrSWRunIndex.1 and warn-th doesn't apply " );
95 like($res->output, '/^SNMP WARNING - \*1\*\s.*$/', "String matches SNMP WARNING and output format");
96 87
97 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w :0 -c 0"); 88 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w :0 -c 0 -P 2c");
98 cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL when querying hrSWRunIndex.1 and crit-th doesn't apply" ); 89 cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL when querying hrSWRunIndex.1 and crit-th doesn't apply" );
99 like($res->output, '/^SNMP CRITICAL - \*1\*\s.*$/', "String matches SNMP CRITICAL and output format");
100 90
101 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2 -c 1:2"); 91 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2 -c 1:2 -P 2c");
102 cmp_ok( $res->return_code, '==', 0, "Checking two OIDs at once" ); 92 cmp_ok( $res->return_code, '==', 0, "Checking two OIDs at once" );
103 like($res->output, "/^SNMP OK - 2 1/", "Got two values back" ); 93 like( $res->perf_output, "/ifIndex.2'?=2/", "Got 1st perf data" );
104 like( $res->perf_output, "/ifIndex.2=2/", "Got 1st perf data" ); 94 like( $res->perf_output, "/ifIndex.1'?=1/", "Got 2nd perf data" );
105 like( $res->perf_output, "/ifIndex.1=1/", "Got 2nd perf data" );
106 95
107 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2,1:2 -c 2:2,2:2"); 96 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2,1:2 -c 2:2,2:2 -P 2c");
108 cmp_ok( $res->return_code, '==', 2, "Checking critical threshold is passed if any one value crosses" ); 97 cmp_ok( $res->return_code, '==', 2, "Checking critical threshold is passed if any one value crosses" );
109 like($res->output, "/^SNMP CRITICAL - 2 *1*/", "Got two values back" ); 98 like( $res->perf_output, "/ifIndex.2'?=2/", "Got 1st perf data" );
110 like( $res->perf_output, "/ifIndex.2=2/", "Got 1st perf data" ); 99 like( $res->perf_output, "/ifIndex.1'?=1/", "Got 2nd perf data" );
111 like( $res->perf_output, "/ifIndex.1=1/", "Got 2nd perf data" );
112 100
113 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w 1:,1: -c 1:,1:"); 101 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w 1:,1: -c 1:,1: -P 2c");
114 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrMemorySize and hrSystemProcesses"); 102 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrMemorySize and hrSystemProcesses");
115 like($res->output, '/^SNMP OK - \d+ \d+/', "String contains hrMemorySize and hrSystemProcesses");
116 103
117 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w \@:0 -c \@0"); 104 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w \@:0 -c \@0 -P 2c");
118 cmp_ok( $res->return_code, '==', 0, "Exit OK with inside-range thresholds"); 105 cmp_ok( $res->return_code, '==', 0, "Exit OK with inside-range thresholds");
119 like($res->output, '/^SNMP OK - 1\s.*$/', "String matches SNMP OK and output format");
120 106
121 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoad.3"); 107 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoadInt.3 -P 2c");
122 $res->output =~ m/^SNMP OK - (\d+\.\d{2})\s.*$/; 108 $res->output =~ m/^.*Value: (\d+).*$/;
123 my $lower = $1 - 0.05; 109 my $lower = $1 - 0.05;
124 my $higher = $1 + 0.05; 110 my $higher = $1 + 0.05;
125 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoad.3 -w $lower -c $higher"); 111 # $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoadInt.3 -w $lower -c $higher -P 2c");
126 cmp_ok( $res->return_code, '==', 1, "Exit WARNING with fractionnal arguments"); 112 # cmp_ok( $res->return_code, '==', 1, "Exit WARNING with fractional arguments");
127 113
128 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0,host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w ,:0 -c ,:2"); 114 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0,host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w ,:0 -c ,:2 -P 2c");
129 cmp_ok( $res->return_code, '==', 1, "Exit WARNING on 2nd threshold"); 115 cmp_ok( $res->return_code, '==', 1, "Exit WARNING on 2nd threshold");
130 like($res->output, '/^SNMP WARNING - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s+\*1\*\s.*$/', "First OID returned as string, 2nd checked for thresholds");
131 116
132 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w '' -c ''"); 117 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w '' -c '' -P 2c");
133 cmp_ok( $res->return_code, '==', 0, "Empty thresholds doesn't crash"); 118 cmp_ok( $res->return_code, '==', 0, "Empty thresholds doesn't crash");
134 119
135 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,,1 -c ,,2"); 120 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,,1 -c ,,2 -P 2c");
136 cmp_ok( $res->return_code, '==', 0, "Skipping first two thresholds on 2 OID check"); 121 cmp_ok( $res->return_code, '==', 0, "Skipping first two thresholds on 2 OID check");
137 like($res->output, '/^SNMP OK - \d+ \w+ \d+\s.*$/', "Skipping first two thresholds, result printed rather than parsed");
138 122
139 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,, -c ,,"); 123 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,, -c ,, -P 2c");
140 cmp_ok( $res->return_code, '==', 0, "Skipping all thresholds"); 124 cmp_ok( $res->return_code, '==', 0, "Skipping all thresholds");
141 like($res->output, '/^SNMP OK - \d+ \w+ \d+\s.*$/', "Skipping all thresholds, result printed rather than parsed");
142 125
143 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1000000000000: -u '1/100 sec'"); 126 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1000000000000: -u '1/100 sec' -P 2c");
144 cmp_ok( $res->return_code, '==', 2, "Timetick used as a threshold"); 127 cmp_ok( $res->return_code, '==', 2, "Timetick used as a threshold");
145 like($res->output, '/^SNMP CRITICAL - \*\d+\* 1\/100 sec.*$/', "Timetick used as a threshold, parsed as numeric");
146 128
147 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0"); 129 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -P 2c");
148 cmp_ok( $res->return_code, '==', 0, "Timetick used as a string"); 130 cmp_ok( $res->return_code, '==', 0, "Timetick used as a string");
149 like($res->output, '/^SNMP OK - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s.*$/', "Timetick used as a string, result printed rather than parsed");
150 131
151 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o HOST-RESOURCES-MIB::hrSWRunName.1"); 132 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o HOST-RESOURCES-MIB::hrSWRunName.1 -P 2c");
152 cmp_ok( $res->return_code, '==', 0, "snmp response without datatype"); 133 cmp_ok( $res->return_code, '==', 0, "snmp response without datatype");
153 like( $res->output, '/^SNMP OK - "(systemd|init)" \| $/', "snmp response without datatype" );
154} 134}
155 135
156SKIP: { 136SKIP: {
157 skip "no SNMP user defined", 1 if ( ! $user_snmp ); 137 skip "no SNMP user defined", 1 if ( ! $user_snmp );
158 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -o HOST-RESOURCES-MIB::hrSystemUptime.0 -P 3 -U $user_snmp -L noAuthNoPriv"); 138 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -o HOST-RESOURCES-MIB::hrSystemUptime.0 -P 3 -U $user_snmp -L noAuthNoPriv");
159 like( $res->output, '/^SNMP OK - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s.*$/', "noAuthNoPriv security level works properly" );
160} 139}
161 140
162# These checks need a complete command line. An invalid community is used so 141# These checks need a complete command line. An invalid community is used so
163# the tests can run on hosts w/o snmp host/community in NPTest.cache. Execution will fail anyway 142# the tests can run on hosts w/o snmp host/community in NPTest.cache. Execution will fail anyway
164SKIP: { 143SKIP: {
165 skip "no non responsive host defined", 2 if ( ! $host_nonresponsive ); 144 skip "no non responsive host defined", 2 if ( ! $host_nonresponsive );
166 $res = NPTest->testCmd( "./check_snmp -H $host_nonresponsive --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1:"); 145 $res = NPTest->testCmd( "./check_snmp -H $host_nonresponsive --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1: -P 2c");
167 cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL with non responsive host" ); 146 cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL with non responsive host" );
168 like($res->output, '/Plugin timed out while executing system call/', "String matches timeout problem"); 147 # like($res->output, '/Plugin timed out while executing system call/', "String matches timeout problem");
169} 148}
170 149
171SKIP: { 150SKIP: {
172 skip "no non invalid host defined", 2 if ( ! $hostname_invalid ); 151 skip "no non invalid host defined", 2 if ( ! $hostname_invalid );
173 $res = NPTest->testCmd( "./check_snmp -H $hostname_invalid --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1:"); 152 $res = NPTest->testCmd( "./check_snmp -H $hostname_invalid --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1: -P 2c");
174 cmp_ok( $res->return_code, '==', 3, "Exit UNKNOWN with non responsive host" ); 153 cmp_ok( $res->return_code, '==', 3, "Exit UNKNOWN with non responsive host" );
175 like($res->output, '/External command error: .*(nosuchhost|Name or service not known|Unknown host).*/s', "String matches invalid host"); 154 like($res->output, '/.*Unknown host.*/s', "String matches invalid host");
176} 155}
diff --git a/plugins/t/check_tcp.t b/plugins/t/check_tcp.t
index cb4de53d..5c8fd0be 100644
--- a/plugins/t/check_tcp.t
+++ b/plugins/t/check_tcp.t
@@ -21,19 +21,19 @@ my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname
21my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost"); 21my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
22my $internet_access = getTestParameter("NP_INTERNET_ACCESS", "Is this system directly connected to the internet?", "yes"); 22my $internet_access = getTestParameter("NP_INTERNET_ACCESS", "Is this system directly connected to the internet?", "yes");
23 23
24my $successOutput = '/^TCP OK\s-\s+[0-9]?\.?[0-9]+ second response time on port [0-9]+/'; 24my $successOutput = '/Connection time\s+[0-9]?\.?[0-9]+s is within thresholds+/';
25 25
26my $failedExpect = '/^TCP WARNING\s-\sUnexpected response from host/socket on port [0-9]+/'; 26my $failedExpect = '/Answer failed to match/';
27 27
28my $t; 28my $t;
29 29
30$tests = $tests - 4 if $internet_access eq "no"; 30$tests = $tests - 4 if $internet_access eq "no";
31plan tests => $tests; 31plan tests => $tests;
32 32
33$t += checkCmd( "./check_tcp $host_tcp_http -p 80 -wt 300 -ct 600", 0, $successOutput ); 33$t += checkCmd( "./check_tcp $host_tcp_http -p 80 -w 300 -c 600", 0, $successOutput );
34$t += checkCmd( "./check_tcp $host_tcp_http -p 81 -wt 0 -ct 0 -to 1", 2 ); # use invalid port for this test 34$t += checkCmd( "./check_tcp $host_tcp_http -p 81 -w 0 -c 0 -t 1", 2 ); # use invalid port for this test
35$t += checkCmd( "./check_tcp $host_nonresponsive -p 80 -wt 0 -ct 0 -to 1", 2 ); 35$t += checkCmd( "./check_tcp $host_nonresponsive -p 80 -w 0 -c 0 -t 1", 2 );
36$t += checkCmd( "./check_tcp $hostname_invalid -p 80 -wt 0 -ct 0 -to 1", 2 ); 36$t += checkCmd( "./check_tcp $hostname_invalid -p 80 -w 0 -c 0 -t 1", 2 );
37if($internet_access ne "no") { 37if($internet_access ne "no") {
38 $t += checkCmd( "./check_tcp -S -D 1 -H $host_tls_http -p 443", 0 ); 38 $t += checkCmd( "./check_tcp -S -D 1 -H $host_tls_http -p 443", 0 );
39 $t += checkCmd( "./check_tcp -S -D 9000,1 -H $host_tls_http -p 443", 1 ); 39 $t += checkCmd( "./check_tcp -S -D 9000,1 -H $host_tls_http -p 443", 1 );
diff --git a/plugins/t/check_udp.t b/plugins/t/check_udp.t
index 6c47d095..5cb9e6dc 100644
--- a/plugins/t/check_udp.t
+++ b/plugins/t/check_udp.t
@@ -28,7 +28,7 @@ like ( $res->output, '/With UDP checks, a send/expect string must be specified.
28 28
29$res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s foo -e bar" ); 29$res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s foo -e bar" );
30cmp_ok( $res->return_code, '==', 2, "Errors correctly because no udp service running" ); 30cmp_ok( $res->return_code, '==', 2, "Errors correctly because no udp service running" );
31like ( $res->output, '/No data received from host/', "Output OK"); 31like ( $res->output, '/Received no data /', "Output OK");
32 32
33my $nc; 33my $nc;
34if(system("which nc.traditional >/dev/null 2>&1") == 0) { 34if(system("which nc.traditional >/dev/null 2>&1") == 0) {
@@ -48,7 +48,7 @@ SKIP: {
48 sleep 1; 48 sleep 1;
49 $res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s '' -e barbar -4" ); 49 $res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s '' -e barbar -4" );
50 cmp_ok( $res->return_code, '==', 0, "Got barbar response back" ); 50 cmp_ok( $res->return_code, '==', 0, "Got barbar response back" );
51 like ( $res->output, '/\[barbar\]/', "Output OK"); 51 like ( $res->output, '/answer of the server matched/', "Output OK");
52 close NC; 52 close NC;
53 53
54 # Start up a udp server listening on port 3333, quit after 3 seconds 54 # Start up a udp server listening on port 3333, quit after 3 seconds
diff --git a/plugins/t/check_users.t b/plugins/t/check_users.t
index 21c3e53d..446e0476 100644
--- a/plugins/t/check_users.t
+++ b/plugins/t/check_users.t
@@ -15,8 +15,8 @@ use NPTest;
15use vars qw($tests); 15use vars qw($tests);
16BEGIN {$tests = 12; plan tests => $tests} 16BEGIN {$tests = 12; plan tests => $tests}
17 17
18my $successOutput = '/^USERS OK - [0-9]+ users currently logged in/'; 18my $successOutput = '/[0-9]+ users currently logged in/';
19my $failureOutput = '/^USERS CRITICAL - [0-9]+ users currently logged in/'; 19my $failureOutput = '/[0-9]+ users currently logged in/';
20my $wrongOptionOutput = '/Usage:/'; 20my $wrongOptionOutput = '/Usage:/';
21 21
22my $t; 22my $t;
diff --git a/plugins/tests/check_curl.t b/plugins/tests/check_curl.t
index eaa9f518..248eb4c5 100755
--- a/plugins/tests/check_curl.t
+++ b/plugins/tests/check_curl.t
@@ -15,13 +15,19 @@
15# Email Address []:devel@monitoring-plugins.org 15# Email Address []:devel@monitoring-plugins.org
16 16
17use strict; 17use strict;
18use warnings;
18use Test::More; 19use Test::More;
19use NPTest; 20use NPTest;
20use FindBin qw($Bin); 21use FindBin qw($Bin);
21 22
23use URI;
24use URI::QueryParam;
25use HTTP::Daemon;
26use HTTP::Daemon::SSL;
27
22$ENV{'LC_TIME'} = "C"; 28$ENV{'LC_TIME'} = "C";
23 29
24my $common_tests = 75; 30my $common_tests = 95;
25my $ssl_only_tests = 8; 31my $ssl_only_tests = 8;
26# Check that all dependent modules are available 32# Check that all dependent modules are available
27eval "use HTTP::Daemon 6.01;"; 33eval "use HTTP::Daemon 6.01;";
@@ -185,6 +191,123 @@ sub run_server {
185 $c->send_response('moved to /redirect2'); 191 $c->send_response('moved to /redirect2');
186 } elsif ($r->url->path eq "/redir_timeout") { 192 } elsif ($r->url->path eq "/redir_timeout") {
187 $c->send_redirect( "/timeout" ); 193 $c->send_redirect( "/timeout" );
194 } elsif ($r->url->path =~ m{^/redirect_with_increment}) {
195 # <scheme>://<username>:<password>@<host>:<port>/<path>;<parameters>?<query>#<fragment>
196 # Find every parameter, query , and fragment keys and increment them
197
198 my $content = "";
199
200 # Use URI to help with query/fragment; parse path params manually.
201 my $original_url = $r->url->as_string;
202 $content .= " original_url: ${original_url}\n";
203 my $uri = URI->new($original_url);
204 $content .= " uri: ${uri}\n";
205
206 my $path = $uri->path // '';
207 my $query = $uri->query // '';
208 my $fragment = $uri->fragment // '';
209
210 $content .= " path: ${path}\n";
211 $content .= " query: ${query}\n";
212 $content .= " fragment: ${fragment}\n";
213
214 # split the URI part and parameters. URI package cannot do this
215 # group 1 is captured: anything without a semicolon: ([^;]*)
216 # group 2 is uncaptured: (?:;(.*))?
217 # (?: ... )? prevents capturing the parameter section
218 # inside group 2, ';' matches the first ever semicolon
219 # group3 is captured: any character string : (.*)
220 # \? matches an actual ? mark, which starts the query parameters
221 my ($before_params, $params) = $uri =~ m{^([^;]*)(?:;(.*))?\?};
222 $before_params //= '';
223 $params //= '';
224 $content .= " before_params: ${before_params}\n";
225 $content .= " params: ${params}\n";
226 my @parameter_pairs;
227 if (defined $params && length $params) {
228 for my $p (split /;/, $params) {
229 my ($key,$value) = split /=/, $p, 2;
230 $value //= '';
231 push @parameter_pairs, [ $key, $value ];
232 $content .= " parameter: ${key} -> ${value}\n";
233 }
234 }
235
236 # query parameters are offered directly from the library
237 my @query_form = $uri->query_form;
238 my @query_parameter_pairs;
239 while (@query_form) {
240 my $key = shift @query_form;
241 my $value = shift @query_form;
242 $value //= ''; # there can be valueless keys
243 push @query_parameter_pairs, [ $key, $value ];
244 $content .= " query: ${key} -> ${value}\n";
245 }
246
247 # helper to increment value
248 my $increment = sub {
249 my ($v) = @_;
250 return $v if !defined $v || $v eq '';
251 # numeric integer
252 if ($v =~ /^-?\d+$/) {
253 return $v + 1;
254 }
255 # otherwise -> increment as if its an ascii character
256 # sed replacement syntax, but the $& holds the matched character
257 if (length($v)) {
258 (my $new_v = $v) =~ s/./chr(ord($&) + 1)/ge;
259 return $new_v;
260 }
261 };
262
263 # increment values in pairs
264 for my $pair (@parameter_pairs) {
265 $pair->[1] = $increment->($pair->[1]);
266 $content .= " parameter new: " . $pair->[0] . " -> " . $pair->[1] . "\n";
267 }
268 for my $pair (@query_parameter_pairs) {
269 $pair->[1] = $increment->($pair->[1]);
270 $content .= " query parameter new: " . $pair->[0] . " -> " . $pair->[1] . "\n";
271 }
272
273 # rebuild strings
274 my $new_parameter_str = join(';', map { $_->[0] . '=' . $_->[1] } @parameter_pairs);
275 $content .= " new_parameter_str: ${new_parameter_str}\n";
276
277 # library can rebuild from an array
278 my @new_query_form;
279 for my $p (@query_parameter_pairs) { push @new_query_form, $p->[0], $p->[1] }
280
281 my $new_fragment_str = '';
282 for my $pair (@parameter_pairs) {
283 my $key = $pair->[0];
284 my $value = $pair->[1];
285 if ($key eq "fragment") {
286 $new_fragment_str = $value
287 }
288 }
289 $content .= " new_fragment_str: ${new_fragment_str}\n";
290
291 # construct new URI using the library
292 my $new_uri = URI->new('');
293 $new_uri->path( $before_params . ($new_parameter_str ? ';' . $new_parameter_str : '') );
294 $new_uri->query_form( \@new_query_form ) if @new_query_form;
295 $new_uri->fragment( $new_fragment_str ) if $new_fragment_str ne '';
296 $content .= " new_uri: ${new_uri}\n";
297
298 # Redirect until fail_count or redirect_count reaches 3
299 if ($new_uri =~ /fail_count=3/){
300 $c->send_error(HTTP::Status->RC_FORBIDDEN, "fail count reached 3, url path:" . $r->url->path );
301 } elsif ($new_uri =~ /redirect_count=3/){
302 $c->send_response(HTTP::Response->new( 200, 'OK', undef , $content ));
303 } elsif ($new_uri =~ /location_redirect_count=3/){
304 $c->send_basic_header(302);
305 $c->send_header("Location", "$new_uri" );
306 $c->send_crlf;
307 $c->send_response("$content \n moved to $new_uri");
308 } else {
309 $c->send_redirect( $new_uri->as_string, 301, $content );
310 }
188 } elsif ($r->url->path eq "/timeout") { 311 } elsif ($r->url->path eq "/timeout") {
189 # Keep $c from being destroyed, but prevent severe leaks 312 # Keep $c from being destroyed, but prevent severe leaks
190 unshift @persist, $c; 313 unshift @persist, $c;
@@ -214,7 +337,7 @@ sub run_server {
214 return($chunk); 337 return($chunk);
215 })); 338 }));
216 } else { 339 } else {
217 $c->send_error(HTTP::Status->RC_FORBIDDEN); 340 $c->send_error(HTTP::Status->RC_FORBIDDEN, "unknown url path:" . $r->url->path );
218 } 341 }
219 $c->close; 342 $c->close;
220 } 343 }
@@ -245,21 +368,21 @@ SKIP: {
245 368
246 $result = NPTest->testCmd( "$command -p $port_https -S -C 14" ); 369 $result = NPTest->testCmd( "$command -p $port_https -S -C 14" );
247 is( $result->return_code, 0, "$command -p $port_https -S -C 14" ); 370 is( $result->return_code, 0, "$command -p $port_https -S -C 14" );
248 is( $result->output, "OK - Certificate 'Monitoring Plugins' will expire on $expiry.", "output ok" ); 371 like( $result->output, '/.*Certificate \'Monitoring Plugins\' will expire on ' . quotemeta($expiry) . '.*/', "output ok" );
249 372
250 $result = NPTest->testCmd( "$command -p $port_https -S -C 14000" ); 373 $result = NPTest->testCmd( "$command -p $port_https -S -C 14000" );
251 is( $result->return_code, 1, "$command -p $port_https -S -C 14000" ); 374 is( $result->return_code, 1, "$command -p $port_https -S -C 14000" );
252 like( $result->output, '/WARNING - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" ); 375 like( $result->output, '/.*Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\).*/', "output ok" );
253 376
254 # Expired cert tests 377 # Expired cert tests
255 $result = NPTest->testCmd( "$command -p $port_https -S -C 13960,14000" ); 378 $result = NPTest->testCmd( "$command -p $port_https -S -C 13960,14000" );
256 is( $result->return_code, 2, "$command -p $port_https -S -C 13960,14000" ); 379 is( $result->return_code, 2, "$command -p $port_https -S -C 13960,14000" );
257 like( $result->output, '/CRITICAL - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" ); 380 like( $result->output, '/.*Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\).*/', "output ok" );
258 381
259 $result = NPTest->testCmd( "$command -p $port_https_expired -S -C 7" ); 382 $result = NPTest->testCmd( "$command -p $port_https_expired -S -C 7" );
260 is( $result->return_code, 2, "$command -p $port_https_expired -S -C 7" ); 383 is( $result->return_code, 2, "$command -p $port_https_expired -S -C 7" );
261 is( $result->output, 384 like( $result->output,
262 'CRITICAL - Certificate \'Monitoring Plugins\' expired on Wed Jan 2 12:00:00 2008 +0000.', 385 '/.*Certificate \'Monitoring Plugins\' expired on Wed Jan\s+2 12:00:00 2008 \+0000.*/',
263 "output ok" ); 386 "output ok" );
264 387
265} 388}
@@ -274,19 +397,19 @@ SKIP: {
274 $cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$port_http\$"; 397 $cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$port_http\$";
275 $result = NPTest->testCmd( $cmd ); 398 $result = NPTest->testCmd( $cmd );
276 is( $result->return_code, 0, $cmd); 399 is( $result->return_code, 0, $cmd);
277 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 400 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
278 401
279 # http with virtual port (!= 80) 402 # http with virtual port (!= 80)
280 $cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$virtual_port\$"; 403 $cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$virtual_port\$";
281 $result = NPTest->testCmd( $cmd ); 404 $result = NPTest->testCmd( $cmd );
282 is( $result->return_code, 0, $cmd); 405 is( $result->return_code, 0, $cmd);
283 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 406 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
284 407
285 # http with virtual port (80) 408 # http with virtual port (80)
286 $cmd = "./$plugin -H $virtual_host:80 -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host\$"; 409 $cmd = "./$plugin -H $virtual_host:80 -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host\$";
287 $result = NPTest->testCmd( $cmd ); 410 $result = NPTest->testCmd( $cmd );
288 is( $result->return_code, 0, $cmd); 411 is( $result->return_code, 0, $cmd);
289 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 412 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
290} 413}
291 414
292# and the same for SSL 415# and the same for SSL
@@ -296,19 +419,19 @@ SKIP: {
296 $cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$port_https\$"; 419 $cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$port_https\$";
297 $result = NPTest->testCmd( $cmd ); 420 $result = NPTest->testCmd( $cmd );
298 is( $result->return_code, 0, $cmd); 421 is( $result->return_code, 0, $cmd);
299 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 422 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
300 423
301 # https with virtual port (!= 443) 424 # https with virtual port (!= 443)
302 $cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$virtual_port\$"; 425 $cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$virtual_port\$";
303 $result = NPTest->testCmd( $cmd ); 426 $result = NPTest->testCmd( $cmd );
304 is( $result->return_code, 0, $cmd); 427 is( $result->return_code, 0, $cmd);
305 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 428 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
306 429
307 # https with virtual port (443) 430 # https with virtual port (443)
308 $cmd = "./$plugin -H $virtual_host:443 -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host\$"; 431 $cmd = "./$plugin -H $virtual_host:443 -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host\$";
309 $result = NPTest->testCmd( $cmd ); 432 $result = NPTest->testCmd( $cmd );
310 is( $result->return_code, 0, $cmd); 433 is( $result->return_code, 0, $cmd);
311 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 434 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
312} 435}
313 436
314 437
@@ -321,165 +444,223 @@ sub run_common_tests {
321 444
322 $result = NPTest->testCmd( "$command -u /file/root" ); 445 $result = NPTest->testCmd( "$command -u /file/root" );
323 is( $result->return_code, 0, "/file/root"); 446 is( $result->return_code, 0, "/file/root");
324 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second/', "Output correct" ); 447 like( $result->output, '/.*HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second.*/', "Output correct" );
325 448
326 $result = NPTest->testCmd( "$command -u /file/root -s Root" ); 449 $result = NPTest->testCmd( "$command -u /file/root -s Root" );
327 is( $result->return_code, 0, "/file/root search for string"); 450 is( $result->return_code, 0, "/file/root search for string");
328 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second/', "Output correct" ); 451 like( $result->output, '/.*HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second.*/', "Output correct" );
329 452
330 $result = NPTest->testCmd( "$command -u /file/root -s NonRoot" ); 453 $result = NPTest->testCmd( "$command -u /file/root -s NonRoot" );
331 is( $result->return_code, 2, "Missing string check"); 454 is( $result->return_code, 2, "Missing string check");
332 like( $result->output, qr%^HTTP CRITICAL: HTTP/1\.1 200 OK - string 'NonRoot' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location"); 455 like( $result->output, qr%string 'NonRoot' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location");
333 456
334 $result = NPTest->testCmd( "$command -u /file/root -s NonRootWithOver30charsAndMoreFunThanAWetFish" ); 457 $result = NPTest->testCmd( "$command -u /file/root -s NonRootWithOver30charsAndMoreFunThanAWetFish" );
335 is( $result->return_code, 2, "Missing string check"); 458 is( $result->return_code, 2, "Missing string check");
336 like( $result->output, qr%HTTP CRITICAL: HTTP/1\.1 200 OK - string 'NonRootWithOver30charsAndM...' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location"); 459 like( $result->output, qr%string 'NonRootWithOver30charsAndM...' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location");
337 460
338 $result = NPTest->testCmd( "$command -u /header_check -d foo" ); 461 $result = NPTest->testCmd( "$command -u /header_check -d foo" );
339 is( $result->return_code, 0, "header_check search for string"); 462 is( $result->return_code, 0, "header_check search for string");
340 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 96 bytes in [\d\.]+ second/', "Output correct" ); 463 like( $result->output, '/.*HTTP/1.1 200 OK - 96 bytes in [\d\.]+ second.*/', "Output correct" );
341 464
342 $result = NPTest->testCmd( "$command -u /header_check -d bar" ); 465 $result = NPTest->testCmd( "$command -u /header_check -d bar" );
343 is( $result->return_code, 2, "Missing header string check"); 466 is( $result->return_code, 2, "Missing header string check");
344 like( $result->output, qr%^HTTP CRITICAL: HTTP/1\.1 200 OK - header 'bar' not found on 'https?://127\.0\.0\.1:\d+/header_check'%, "Shows search string and location"); 467 like( $result->output, qr%header 'bar' not found on 'https?://127\.0\.0\.1:\d+/header_check'%, "Shows search string and location");
345 468
346 $result = NPTest->testCmd( "$command -u /header_broken_check" ); 469 $result = NPTest->testCmd( "$command -u /header_broken_check" );
347 is( $result->return_code, 0, "header_check search for string"); 470 is( $result->return_code, 0, "header_check search for string");
348 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 138 bytes in [\d\.]+ second/', "Output correct" ); 471 like( $result->output, '/.*HTTP/1.1 200 OK - 138 bytes in [\d\.]+ second.*/', "Output correct" );
349 472
350 my $cmd; 473 my $cmd;
351 $cmd = "$command -u /slow"; 474 $cmd = "$command -u /slow";
352 $result = NPTest->testCmd( $cmd ); 475 $result = NPTest->testCmd( $cmd );
353 is( $result->return_code, 0, "$cmd"); 476 is( $result->return_code, 0, "$cmd");
354 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 477 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
355 $result->output =~ /in ([\d\.]+) second/; 478 $result->output =~ /in ([\d\.]+) second/;
356 cmp_ok( $1, ">", 1, "Time is > 1 second" ); 479 cmp_ok( $1, ">", 1, "Time is > 1 second" );
357 480
358 $cmd = "$command -u /statuscode/200"; 481 $cmd = "$command -u /statuscode/200";
359 $result = NPTest->testCmd( $cmd ); 482 $result = NPTest->testCmd( $cmd );
360 is( $result->return_code, 0, $cmd); 483 is( $result->return_code, 0, $cmd);
361 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 484 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
362 485
363 $cmd = "$command -u /statuscode/200 -e 200"; 486 $cmd = "$command -u /statuscode/200 -e 200";
364 $result = NPTest->testCmd( $cmd ); 487 $result = NPTest->testCmd( $cmd );
365 is( $result->return_code, 0, $cmd); 488 is( $result->return_code, 0, $cmd);
366 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - Status line output matched "200" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 489 like( $result->output, '/.*Status line output matched "200".*/', "Output correct: ".$result->output );
367 490
368 $cmd = "$command -u /statuscode/201"; 491 $cmd = "$command -u /statuscode/201";
369 $result = NPTest->testCmd( $cmd ); 492 $result = NPTest->testCmd( $cmd );
370 is( $result->return_code, 0, $cmd); 493 is( $result->return_code, 0, $cmd);
371 like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output ); 494 like( $result->output, '/.*HTTP/1.1 201 Created - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
372 495
373 $cmd = "$command -u /statuscode/201 -e 201"; 496 $cmd = "$command -u /statuscode/201 -e 201";
374 $result = NPTest->testCmd( $cmd ); 497 $result = NPTest->testCmd( $cmd );
375 is( $result->return_code, 0, $cmd); 498 is( $result->return_code, 0, $cmd);
376 like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - Status line output matched "201" - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output ); 499 like( $result->output, '/.*Status line output matched "201".*/', "Output correct: ".$result->output );
377 500
378 $cmd = "$command -u /statuscode/201 -e 200"; 501 $cmd = "$command -u /statuscode/201 -e 200";
379 $result = NPTest->testCmd( $cmd ); 502 $result = NPTest->testCmd( $cmd );
380 is( $result->return_code, 2, $cmd); 503 is( $result->return_code, 2, $cmd);
381 like( $result->output, '/^HTTP CRITICAL - Invalid HTTP response received from host on port \d+: HTTP/1.1 201 Created/', "Output correct: ".$result->output ); 504 like( $result->output, '/.*Invalid HTTP response received from host on port \d+: HTTP/1.1 201 Created.*/', "Output correct: ".$result->output );
382 505
383 $cmd = "$command -u /statuscode/200 -e 200,201,202"; 506 $cmd = "$command -u /statuscode/200 -e 200,201,202";
384 $result = NPTest->testCmd( $cmd ); 507 $result = NPTest->testCmd( $cmd );
385 is( $result->return_code, 0, $cmd); 508 is( $result->return_code, 0, $cmd);
386 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 509 like( $result->output, '/.*Status line output matched "200,201,202".*/', "Output correct: ".$result->output );
387 510
388 $cmd = "$command -u /statuscode/201 -e 200,201,202"; 511 $cmd = "$command -u /statuscode/201 -e 200,201,202";
389 $result = NPTest->testCmd( $cmd ); 512 $result = NPTest->testCmd( $cmd );
390 is( $result->return_code, 0, $cmd); 513 is( $result->return_code, 0, $cmd);
391 like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 514 like( $result->output, '/.*Status line output matched "200,201,202".*/', "Output correct: ".$result->output );
392 515
393 $cmd = "$command -u /statuscode/203 -e 200,201,202"; 516 $cmd = "$command -u /statuscode/203 -e 200,201,202";
394 $result = NPTest->testCmd( $cmd ); 517 $result = NPTest->testCmd( $cmd );
395 is( $result->return_code, 2, $cmd); 518 is( $result->return_code, 2, $cmd);
396 like( $result->output, '/^HTTP CRITICAL - Invalid HTTP response received from host on port (\d+): HTTP/1.1 203 Non-Authoritative Information/', "Output correct: ".$result->output ); 519 like( $result->output, '/.*Invalid HTTP response received from host on port (\d+): HTTP/1.1 203 Non-Authoritative Information.*/', "Output correct: ".$result->output );
397 520
398 $cmd = "$command -j HEAD -u /method"; 521 $cmd = "$command -j HEAD -u /method";
399 $result = NPTest->testCmd( $cmd ); 522 $result = NPTest->testCmd( $cmd );
400 is( $result->return_code, 0, $cmd); 523 is( $result->return_code, 0, $cmd);
401 like( $result->output, '/^HTTP OK: HTTP/1.1 200 HEAD - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 524 like( $result->output, '/.*HTTP/1.1 200 HEAD - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
402 525
403 $cmd = "$command -j POST -u /method"; 526 $cmd = "$command -j POST -u /method";
404 $result = NPTest->testCmd( $cmd ); 527 $result = NPTest->testCmd( $cmd );
405 is( $result->return_code, 0, $cmd); 528 is( $result->return_code, 0, $cmd);
406 like( $result->output, '/^HTTP OK: HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 529 like( $result->output, '/.*HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
407 530
408 $cmd = "$command -j GET -u /method"; 531 $cmd = "$command -j GET -u /method";
409 $result = NPTest->testCmd( $cmd ); 532 $result = NPTest->testCmd( $cmd );
410 is( $result->return_code, 0, $cmd); 533 is( $result->return_code, 0, $cmd);
411 like( $result->output, '/^HTTP OK: HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 534 like( $result->output, '/.*HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
412 535
413 $cmd = "$command -u /method"; 536 $cmd = "$command -u /method";
414 $result = NPTest->testCmd( $cmd ); 537 $result = NPTest->testCmd( $cmd );
415 is( $result->return_code, 0, $cmd); 538 is( $result->return_code, 0, $cmd);
416 like( $result->output, '/^HTTP OK: HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 539 like( $result->output, '/.*HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
417 540
418 $cmd = "$command -P foo -u /method"; 541 $cmd = "$command -P foo -u /method";
419 $result = NPTest->testCmd( $cmd ); 542 $result = NPTest->testCmd( $cmd );
420 is( $result->return_code, 0, $cmd); 543 is( $result->return_code, 0, $cmd);
421 like( $result->output, '/^HTTP OK: HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 544 like( $result->output, '/.*HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
422 545
423 $cmd = "$command -j DELETE -u /method"; 546 $cmd = "$command -j DELETE -u /method";
424 $result = NPTest->testCmd( $cmd ); 547 $result = NPTest->testCmd( $cmd );
425 is( $result->return_code, 1, $cmd); 548 is( $result->return_code, 1, $cmd);
426 like( $result->output, '/^HTTP WARNING: HTTP/1.1 405 Method Not Allowed/', "Output correct: ".$result->output ); 549 like( $result->output, '/.*HTTP/1.1 405 Method Not Allowed.*/', "Output correct: ".$result->output );
427 550
428 $cmd = "$command -j foo -u /method"; 551 $cmd = "$command -j foo -u /method";
429 $result = NPTest->testCmd( $cmd ); 552 $result = NPTest->testCmd( $cmd );
430 is( $result->return_code, 2, $cmd); 553 is( $result->return_code, 2, $cmd);
431 like( $result->output, '/^HTTP CRITICAL: HTTP/1.1 501 Not Implemented/', "Output correct: ".$result->output ); 554 like( $result->output, '/.*HTTP/1.1 501 Not Implemented.*/', "Output correct: ".$result->output );
432 555
433 $cmd = "$command -P stufftoinclude -u /postdata -s POST:stufftoinclude"; 556 $cmd = "$command -P stufftoinclude -u /postdata -s POST:stufftoinclude";
434 $result = NPTest->testCmd( $cmd ); 557 $result = NPTest->testCmd( $cmd );
435 is( $result->return_code, 0, $cmd); 558 is( $result->return_code, 0, $cmd);
436 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 559 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
437 560
438 $cmd = "$command -j PUT -P stufftoinclude -u /postdata -s PUT:stufftoinclude"; 561 $cmd = "$command -j PUT -P stufftoinclude -u /postdata -s PUT:stufftoinclude";
439 $result = NPTest->testCmd( $cmd ); 562 $result = NPTest->testCmd( $cmd );
440 is( $result->return_code, 0, $cmd); 563 is( $result->return_code, 0, $cmd);
441 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 564 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
442 565
443 # To confirm that the free doesn't segfault 566 # To confirm that the free doesn't segfault
444 $cmd = "$command -P stufftoinclude -j PUT -u /postdata -s PUT:stufftoinclude"; 567 $cmd = "$command -P stufftoinclude -j PUT -u /postdata -s PUT:stufftoinclude";
445 $result = NPTest->testCmd( $cmd ); 568 $result = NPTest->testCmd( $cmd );
446 is( $result->return_code, 0, $cmd); 569 is( $result->return_code, 0, $cmd);
447 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 570 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
448 571
449 $cmd = "$command -u /redirect"; 572 $cmd = "$command -u /redirect";
450 $result = NPTest->testCmd( $cmd ); 573 $result = NPTest->testCmd( $cmd );
451 is( $result->return_code, 0, $cmd); 574 is( $result->return_code, 0, $cmd);
452 like( $result->output, '/^HTTP OK: HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 575 like( $result->output, '/.*HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
453 576
454 $cmd = "$command -f follow -u /redirect"; 577 $cmd = "$command -f follow -u /redirect";
455 $result = NPTest->testCmd( $cmd ); 578 $result = NPTest->testCmd( $cmd );
456 is( $result->return_code, 0, $cmd); 579 is( $result->return_code, 0, $cmd);
457 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 580 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
458 581
459 $cmd = "$command -u /redirect -k 'follow: me'"; 582 $cmd = "$command -u /redirect -k 'follow: me'";
460 $result = NPTest->testCmd( $cmd ); 583 $result = NPTest->testCmd( $cmd );
461 is( $result->return_code, 0, $cmd); 584 is( $result->return_code, 0, $cmd);
462 like( $result->output, '/^HTTP OK: HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 585 like( $result->output, '/.*HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
463 586
464 $cmd = "$command -f follow -u /redirect -k 'follow: me'"; 587 $cmd = "$command -f follow -u /redirect -k 'follow: me'";
465 $result = NPTest->testCmd( $cmd ); 588 $result = NPTest->testCmd( $cmd );
466 is( $result->return_code, 0, $cmd); 589 is( $result->return_code, 0, $cmd);
467 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 590 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
468 591
469 $cmd = "$command -f sticky -u /redirect -k 'follow: me'"; 592 $cmd = "$command -f sticky -u /redirect -k 'follow: me'";
470 $result = NPTest->testCmd( $cmd ); 593 $result = NPTest->testCmd( $cmd );
471 is( $result->return_code, 0, $cmd); 594 is( $result->return_code, 0, $cmd);
472 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 595 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
473 596
474 $cmd = "$command -f stickyport -u /redirect -k 'follow: me'"; 597 $cmd = "$command -f stickyport -u /redirect -k 'follow: me'";
475 $result = NPTest->testCmd( $cmd ); 598 $result = NPTest->testCmd( $cmd );
476 is( $result->return_code, 0, $cmd); 599 is( $result->return_code, 0, $cmd);
477 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 600 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
478 601
479 $cmd = "$command -f follow -u /redirect_rel -s redirected"; 602 $cmd = "$command -f follow -u /redirect_rel -s redirected";
480 $result = NPTest->testCmd( $cmd ); 603 $result = NPTest->testCmd( $cmd );
481 is( $result->return_code, 0, $cmd); 604 is( $result->return_code, 0, $cmd);
482 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 605 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
606
607 # Redirect with increment tests. These are for checking if the url parameters, query parameters and fragment are parsed.
608 # The server at this point has dynamic redirection. It tries to increment values that it sees in these fields, then redirects.
609 # It also appends some debug log and writes it into HTTP content, pass the -vvv parameter to see them.
610
611 $cmd = "$command -u '/redirect_with_increment/path1/path2/path3/path4' --onredirect=follow -vvv";
612 $result = NPTest->testCmd( "$cmd" );
613 is( $result->return_code, 1, $cmd);
614 like( $result->output, '/.*HTTP/1.1 403 Forbidden - \d+ bytes in [\d\.]+ second.*/', "Output correct, redirect_count was not present, got redirected to / : ".$result->output );
615
616 # redirect_count=0 is parsed as a parameter and incremented. When it goes up to 3, the redirection returns HTTP OK
617 $cmd = "$command -u '/redirect_with_increment/path1/path2;redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv";
618 $result = NPTest->testCmd( "$cmd" );
619 is( $result->return_code, 0, $cmd);
620 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, redirect_count went up to 3, and returned OK: ".$result->output );
621
622 # location_redirect_count=0 goes up to 3, which uses the HTTP 302 style of redirection with 'Location' header
623 $cmd = "$command -u '/redirect_with_increment/path1/path2;location_redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv";
624 $result = NPTest->testCmd( "$cmd" );
625 is( $result->return_code, 0, $cmd);
626 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output );
627
628 # fail_count parameter may also go up to 3, which returns a HTTP 403
629 $cmd = "$command -u '/redirect_with_increment/path1/path2;redirect_count=0;fail_count=2' --onredirect=follow -vvv";
630 $result = NPTest->testCmd( "$cmd" );
631 is( $result->return_code, 1, $cmd);
632 like( $result->output, '/.*HTTP/1.1 403 Forbidden - \d+ bytes in [\d\.]+ second.*/', "Output correct, early due to fail_count reaching 3: ".$result->output );
633
634 # redirect_count=0, p1=1 , p2=ab => redirect_count=1, p1=2 , p2=bc => redirect_count=2, p1=3 , p2=cd => redirect_count=3 , p1=4 , p2=de
635 # Last visited URI returns HTTP OK instead of redirect, and the one before that contains the new_uri in its content
636 $cmd = "$command -u '/redirect_with_increment/path1/path2;redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv";
637 $result = NPTest->testCmd( "$cmd" );
638 is( $result->return_code, 0, $cmd);
639 like( $result->output, '/.*redirect_count=3;p1=4;p2=de\?*/', "Output correct, parsed and incremented both parameters p1 and p2 : ".$result->output );
640 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output );
641
642 # Same incrementation as before, uses the query parameters that come after the first '?' : qp1 and qp2
643 $cmd = "$command -u '/redirect_with_increment/path1/path2;redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv";
644 $result = NPTest->testCmd( "$cmd" );
645 is( $result->return_code, 0, $cmd);
646 like( $result->output, '/.*\?qp1=13&qp2=no*/', "Output correct, parsed and incremented both query parameters qp1 and qp2 : ".$result->output );
647 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output );
648
649 # Check if the query parameter order is kept intact
650 $cmd = "$command -u '/redirect_with_increment;redirect_count=0;?qp0=0&qp1=1&qp2=2&qp3=3&qp4=4&qp5=5' --onredirect=follow -vvv";
651 $result = NPTest->testCmd( "$cmd" );
652 is( $result->return_code, 0, $cmd);
653 like( $result->output, '/.*\?qp0=3&qp1=4&qp2=5&qp3=6&qp4=7&qp5=8*/', "Output correct, parsed and incremented query parameters qp1,qp2,qp3,qp4,qp5 in order : ".$result->output );
654 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output );
655
656 # The fragment is passed as another parameter.
657 # During the server redirects the fragment will be set to its value, if such a key is present.
658 # 'ebiil' => 'fcjjm' => 'gdkkn' => 'hello'
659 $cmd = "$command -u '/redirect_with_increment/path1/path2;redirect_count=0;fragment=ebiil?qp1=0' --onredirect=follow -vvv";
660 $result = NPTest->testCmd( "$cmd" );
661 is( $result->return_code, 0, $cmd);
662 like( $result->output, '/.*redirect_count=3;fragment=hello\?qp1=3#hello*/', "Output correct, fragments are specified by server and followed by check_curl: ".$result->output );
663 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output );
483 664
484 # These tests may block 665 # These tests may block
485 # stickyport - on full urlS port is set back to 80 otherwise 666 # stickyport - on full urlS port is set back to 80 otherwise
diff --git a/plugins/tests/check_nt.t b/plugins/tests/check_nt.t
deleted file mode 100755
index 223d4933..00000000
--- a/plugins/tests/check_nt.t
+++ /dev/null
@@ -1,80 +0,0 @@
1#! /usr/bin/perl -w -I ..
2#
3# Test check_nt by having a stub check_nt daemon
4#
5
6use strict;
7use Test::More;
8use NPTest;
9use FindBin qw($Bin);
10
11use IO::Socket;
12use IO::Select;
13use POSIX;
14
15my $port = 50000 + int(rand(1000));
16
17my $pid = fork();
18if ($pid) {
19 # Parent
20 #print "parent\n";
21 # give our webserver some time to startup
22 sleep(1);
23} else {
24 # Child
25 #print "child\n";
26
27 my $server = IO::Socket::INET->new(
28 LocalPort => $port,
29 Type => SOCK_STREAM,
30 Reuse => 1,
31 Proto => "tcp",
32 Listen => 10,
33 ) or die "Cannot be a tcp server on port $port: $@";
34
35 $server->autoflush(1);
36
37 print "Please contact me at port $port\n";
38 while (my $client = $server->accept ) {
39 my $data = "";
40 my $rv = $client->recv($data, POSIX::BUFSIZ, 0);
41
42 my ($password, $command, $arg) = split('&', $data);
43
44 if ($command eq "4") {
45 if ($arg eq "c") {
46 print $client "930000000&1000000000";
47 } elsif ($arg eq "d") {
48 print $client "UNKNOWN: Drive is not a fixed drive";
49 }
50 }
51 }
52 exit;
53}
54
55END { if ($pid) { print "Killing $pid\n"; kill "INT", $pid } };
56
57if ($ARGV[0] && $ARGV[0] eq "-d") {
58 sleep 1000;
59}
60
61if (-x "./check_nt") {
62 plan tests => 5;
63} else {
64 plan skip_all => "No check_nt compiled";
65}
66
67my $result;
68my $command = "./check_nt -H 127.0.0.1 -p $port";
69
70$result = NPTest->testCmd( "$command -v USEDDISKSPACE -l c" );
71is( $result->return_code, 0, "USEDDISKSPACE c");
72is( $result->output, q{c:\ - total: 0.93 Gb - used: 0.07 Gb (7%) - free 0.87 Gb (93%) | 'c:\ Used Space'=0.07Gb;0.00;0.00;0.00;0.93}, "Output right" );
73
74$result = NPTest->testCmd( "$command -v USEDDISKSPACE -l d" );
75is( $result->return_code, 3, "USEDDISKSPACE d - invalid");
76is( $result->output, "Free disk space : Invalid drive", "Output right" );
77
78$result = NPTest->testCmd( "./check_nt -v USEDDISKSPACE -l d" );
79is( $result->return_code, 3, "Fail if -H missing");
80
diff --git a/plugins/tests/check_snmp.t b/plugins/tests/check_snmp.t
index bfe42e16..26d67898 100755
--- a/plugins/tests/check_snmp.t
+++ b/plugins/tests/check_snmp.t
@@ -4,12 +4,13 @@
4# 4#
5 5
6use strict; 6use strict;
7use warnings;
7use Test::More; 8use Test::More;
8use NPTest; 9use NPTest;
9use FindBin qw($Bin); 10use FindBin qw($Bin);
10use POSIX qw/strftime/; 11use POSIX qw/strftime/;
11 12
12my $tests = 81; 13my $tests = 75;
13# Check that all dependent modules are available 14# Check that all dependent modules are available
14eval { 15eval {
15 require NetSNMP::OID; 16 require NetSNMP::OID;
@@ -76,49 +77,36 @@ my $res;
76 77
77$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.0"); 78$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.0");
78cmp_ok( $res->return_code, '==', 0, "Exit OK when querying a multi-line string" ); 79cmp_ok( $res->return_code, '==', 0, "Exit OK when querying a multi-line string" );
79like($res->output, '/^SNMP OK - /', "String contains SNMP OK"); 80like($res->output, '/.*Cisco Internetwork Operating System Software.*/m', "String contains all lines");
80like($res->output, '/'.quotemeta('SNMP OK - Cisco Internetwork Operating System Software |
81.1.3.6.1.4.1.8072.3.2.67.0:
82"Cisco Internetwork Operating System Software
83IOS (tm) Catalyst 4000 \"L3\" Switch Software (cat4000-I9K91S-M), Version
8412.2(20)EWA, RELEASE SOFTWARE (fc1)
85Technical Support: http://www.cisco.com/techsupport
86Copyright (c) 1986-2004 by cisco Systems, Inc.
87"').'/m', "String contains all lines");
88 81
89# sysContact.0 is "Alice" (from our snmpd.conf) 82# sysContact.0 is "Alice" (from our snmpd.conf)
90$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.0 -o sysContact.0 -o .1.3.6.1.4.1.8072.3.2.67.1"); 83$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.0 -o sysContact.0 -o .1.3.6.1.4.1.8072.3.2.67.1");
91cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" ); 84cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" );
92like($res->output, '/^SNMP OK - /', "String contains SNMP OK"); 85# like($res->output, '/^SNMP OK - /', "String contains SNMP OK");
93like($res->output, '/'.quotemeta('SNMP OK - Cisco Internetwork Operating System Software ').'"?Alice"?'.quotemeta(' Kisco Outernetwork Oserating Gystem Totware | 86like($res->output, '/.*Cisco Internetwork Operating System Software.*/m', "String contains all lines with multiple OIDs");
94.1.3.6.1.4.1.8072.3.2.67.0: 87like($res->output, '/.*Alice.*/m', "String contains all lines with multiple OIDs");
95"Cisco Internetwork Operating System Software 88like($res->output, '/.*Kisco Outernetwork Oserating Gystem Totware.*/m', "String contains all lines with multiple OIDs");
96IOS (tm) Catalyst 4000 \"L3\" Switch Software (cat4000-I9K91S-M), Version
9712.2(20)EWA, RELEASE SOFTWARE (fc1)
98Technical Support: http://www.cisco.com/techsupport
99Copyright (c) 1986-2004 by cisco Systems, Inc.
100"
101.1.3.6.1.4.1.8072.3.2.67.1:
102"Kisco Outernetwork Oserating Gystem Totware
103Copyleft (c) 2400-2689 by kisco Systrems, Inc."').'/m', "String contains all lines with multiple OIDs");
104 89
105$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.2"); 90$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.2");
106like($res->output, '/'.quotemeta('SNMP OK - This should not confuse check_snmp \"parser\" | 91cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" );
107.1.3.6.1.4.1.8072.3.2.67.2: 92# like($res->output, '/'.quotemeta('This should not confuse check_snmp \"parser\" |
108"This should not confuse check_snmp \"parser\" 93# .1.3.6.1.4.1.8072.3.2.67.2:
109into thinking there is no 2nd line"').'/m', "Attempt to confuse parser No.1"); 94# "This should not confuse check_snmp \"parser\"
95# into thinking there is no 2nd line"').'/m', "Attempt to confuse parser No.1");
110 96
111$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.3"); 97$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.3");
112like($res->output, '/'.quotemeta('SNMP OK - It\'s getting even harder if the line | 98cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" );
113.1.3.6.1.4.1.8072.3.2.67.3: 99# like($res->output, '/'.quotemeta('It\'s getting even harder if the line |
114"It\'s getting even harder if the line 100# .1.3.6.1.4.1.8072.3.2.67.3:
115ends with with this: C:\\\\"').'/m', "Attempt to confuse parser No.2"); 101# "It\'s getting even harder if the line
102# ends with with this: C:\\\\"').'/m', "Attempt to confuse parser No.2");
116 103
117$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.4"); 104$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.4");
118like($res->output, '/'.quotemeta('SNMP OK - And now have fun with with this: \"C:\\\\\" | 105cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" );
119.1.3.6.1.4.1.8072.3.2.67.4: 106# like($res->output, '/'.quotemeta('And now have fun with with this: \"C:\\\\\" |
120"And now have fun with with this: \"C:\\\\\" 107# .1.3.6.1.4.1.8072.3.2.67.4:
121because we\'re not done yet!"').'/m', "Attempt to confuse parser No.3"); 108# "And now have fun with with this: \"C:\\\\\"
109# because we\'re not done yet!"').'/m', "Attempt to confuse parser No.3");
122 110
123system("rm -f ".$ENV{'MP_STATE_PATH'}."/*/check_snmp/*"); 111system("rm -f ".$ENV{'MP_STATE_PATH'}."/*/check_snmp/*");
124 112
@@ -131,156 +119,159 @@ SKIP: {
131 my $ts = time(); 119 my $ts = time();
132 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); 120 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" );
133 is($res->return_code, 0, "Returns OK"); 121 is($res->return_code, 0, "Returns OK");
134 is($res->output, "No previous data to calculate rate - assume okay"); 122 like($res->output, "/.*No previous data to calculate rate - assume okay.*/");
135 123
136 # test rate 1 second later 124 # test rate 1 second later
137 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); 125 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" );
138 is($res->return_code, 1, "WARNING - due to going above rate calculation" ); 126 is($res->return_code, 1, "WARNING - due to going above rate calculation" );
139 is($res->output, "SNMP RATE WARNING - *666* | iso.3.6.1.4.1.8072.3.2.67.10=666;600 "); 127 like($res->output, "/.*=666.*/");
140 128
141 # test rate with same time 129 # test rate with same time
142 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); 130 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" );
143 is($res->return_code, 3, "UNKNOWN - basically the divide by zero error" ); 131 is($res->return_code, 3, "UNKNOWN - basically the divide by zero error" );
144 is($res->output, "Time duration between plugin calls is invalid"); 132 like($res->output, "/.*Time duration between plugin calls is invalid.*/");
145 133
146 134
147 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); 135 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" );
148 is($res->return_code, 0, "OK for first call" ); 136 is($res->return_code, 0, "OK for first call" );
149 is($res->output, "No previous data to calculate rate - assume okay" ); 137 like($res->output, "/.*No previous data to calculate rate - assume okay.*/" );
150 138
151 # test rate 1 second later 139 # test rate 1 second later
152 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); 140 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" );
153 is($res->return_code, 0, "OK as no thresholds" ); 141 is($res->return_code, 0, "OK as no thresholds" );
154 is($res->output, "SNMP RATE OK - inoctets 666 | inoctets=666 ", "Check label"); 142 like($res->output, "/.*inoctets.*=666.*/m", "Check label");
155 143
156 # test rate 3 seconds later 144 # test rate 3 seconds later
157 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+3))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); 145 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+3))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" );
158 is($res->return_code, 0, "OK as no thresholds" ); 146 is($res->return_code, 0, "OK as no thresholds" );
159 is($res->output, "SNMP RATE OK - inoctets 333 | inoctets=333 ", "Check rate decreases due to longer interval"); 147 like($res->output, "/.*inoctets.*333.*/", "Check rate decreases due to longer interval");
160 148
161 149
162 # label performance data check 150 # label performance data check
163 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test" ); 151 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test" );
164 is($res->return_code, 0, "OK as no thresholds" ); 152 is($res->return_code, 0, "OK as no thresholds" );
165 is($res->output, "SNMP OK - test 67996 | test=67996c ", "Check label"); 153 like($res->output, "/.*test.?=67996c/", "Check label");
166 154
167 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l \"test'test\"" ); 155 # following test is deactivated since it was not valid due to the guidelines (no single quote in label allowed)
168 is($res->return_code, 0, "OK as no thresholds" ); 156 # $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l \"test'test\"" );
169 is($res->output, "SNMP OK - test'test 68662 | \"test'test\"=68662c ", "Check label"); 157 # is($res->return_code, 0, "OK as no thresholds" );
158 # is($res->output, "test'test 68662 | \"test'test\"=68662c ", "Check label");
170 159
171 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test\"test'" ); 160 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test\"test'" );
172 is($res->return_code, 0, "OK as no thresholds" ); 161 is($res->return_code, 0, "OK as no thresholds" );
173 is($res->output, "SNMP OK - test\"test 69328 | 'test\"test'=69328c ", "Check label"); 162 like($res->output, "/.*'test\"test'=68662c.*/", "Check label");
174 163
175 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test -O" ); 164 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test -O" );
176 is($res->return_code, 0, "OK as no thresholds" ); 165 is($res->return_code, 0, "OK as no thresholds" );
177 is($res->output, "SNMP OK - test 69994 | iso.3.6.1.4.1.8072.3.2.67.10=69994c ", "Check label"); 166 like($res->output, "/.*.67.10.?=69328c.*/", "Check label");
178 167
179 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10" ); 168 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10" );
180 is($res->return_code, 0, "OK as no thresholds" ); 169 is($res->return_code, 0, "OK as no thresholds" );
181 is($res->output, "SNMP OK - 70660 | iso.3.6.1.4.1.8072.3.2.67.10=70660c ", "Check label"); 170 like($res->output, "/.*8072.3.2.67.10.?=69994c.*/", "Check label");
182 171
183 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test test'" ); 172 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test test'" );
184 is($res->return_code, 0, "OK as no thresholds" ); 173 is($res->return_code, 0, "OK as no thresholds" );
185 is($res->output, "SNMP OK - test test 71326 | 'test test'=71326c ", "Check label"); 174 like($res->output, "/.*'test test'=70660c/", "Check label");
186 175
187 176
188 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" ); 177 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" );
189 is($res->return_code, 0, "OK for first call" ); 178 is($res->return_code, 0, "OK for first call" );
190 is($res->output, "No previous data to calculate rate - assume okay" ); 179 like($res->output, "/.*No previous data to calculate rate - assume okay.*/" );
191 180
192 # test 1 second later 181 # test 1 second later
193 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" ); 182 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" );
194 is($res->return_code, 0, "OK as no thresholds" ); 183 is($res->return_code, 0, "OK as no thresholds" );
195 is($res->output, "SNMP RATE OK - inoctets_per_minute 39960 | inoctets_per_minute=39960 ", "Checking multiplier"); 184 like($res->output, "/.*inoctets_per_minute.*=39960/", "Checking multiplier");
196}; 185};
197 186
198 187
199 188
200$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s '\"stringtests\"'" ); 189$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s 'stringtests'" );
201is($res->return_code, 0, "OK as string matches" ); 190is($res->return_code, 0, "OK as string matches" );
202is($res->output, 'SNMP OK - "stringtests" | ', "Good string match" ); 191like($res->output, '/.*stringtests.*/', "Good string match" );
203 192
204$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s ring" ); 193$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s ring" );
205is($res->return_code, 2, "CRITICAL as string doesn't match (though is a substring)" ); 194is($res->return_code, 2, "CRITICAL as string doesn't match (though is a substring)" );
206is($res->output, 'SNMP CRITICAL - *"stringtests"* | ', "Failed string match" ); 195like($res->output, '/.*stringtests.*/', "Failed string match" );
207 196
208$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 --invert-search -s '\"stringtests\"'" ); 197$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 --invert-search -s 'stringtests'" );
209is($res->return_code, 2, "CRITICAL as string matches but inverted" ); 198is($res->return_code, 2, "CRITICAL as string matches but inverted" );
210is($res->output, 'SNMP CRITICAL - *"stringtests"* | ', "Inverted string match" ); 199like($res->output, '/.*"stringtests".*/', "Inverted string match" );
211 200
212$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 --invert-search -s ring" ); 201$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 --invert-search -s ring" );
213is($res->return_code, 0, "OK as string doesn't match but inverted" ); 202is($res->return_code, 0, "OK as string doesn't match but inverted" );
214is($res->output, 'SNMP OK - "stringtests" | ', "OK as inverted string no match" ); 203like($res->output, '/.*"stringtests".*/', "OK as inverted string no match" );
215 204
216$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.12 -w 4:5" ); 205$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.12 -w 4:5" );
217is($res->return_code, 1, "Numeric in string test" ); 206# a string is a string and not a number
218is($res->output, 'SNMP WARNING - *3.5* | iso.3.6.1.4.1.8072.3.2.67.12=3.5;4:5 ', "WARNING threshold checks for string masquerading as number" ); 207is($res->return_code, 0, "Numeric in string test" );
208like($res->output, '/.*3.5.*| iso.3.6.1.4.1.8072.3.2.67.12=3.5;4:5/', "WARNING threshold checks for string masquerading as number" );
219 209
220$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.13" ); 210$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.13" );
221is($res->return_code, 0, "Not really numeric test" ); 211is($res->return_code, 0, "Not really numeric test" );
222is($res->output, 'SNMP OK - "87.4startswithnumberbutshouldbestring" | ', "Check string with numeric start is still string" ); 212like($res->output, '/.*"87.4startswithnumberbutshouldbestring".*/', "Check string with numeric start is still string" );
223 213
224$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.14" ); 214$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.14" );
225is($res->return_code, 0, "Not really numeric test (trying best to fool it)" ); 215is($res->return_code, 0, "Not really numeric test (trying best to fool it)" );
226is($res->output, 'SNMP OK - "555\"I said\"" | ', "Check string with a double quote following is still a string (looks like the perl routine will always escape though)" ); 216like($res->output, '/.*\'555"I said"\'.*/', "Check string with a double quote following is still a string (looks like the perl routine will always escape though)" );
227 217
228$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.15 -r 'CUSTOM CHECK OK'" ); 218$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.15 -r 'CUSTOM CHECK OK'" );
229is($res->return_code, 0, "String check should check whole string, not a parsed number" ); 219is($res->return_code, 0, "String check should check whole string, not a parsed number" );
230is($res->output, 'SNMP OK - "CUSTOM CHECK OK: foo is 12345" | ', "String check with numbers returns whole string"); 220like($res->output, '/.*CUSTOM CHECK OK: foo is 12345.*/', "String check with numbers returns whole string");
231 221
232$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" ); 222$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" );
233is($res->return_code, 0, "Negative integer check OK" ); 223is($res->return_code, 0, "Negative integer check OK" );
234is($res->output, 'SNMP OK - -2 | iso.3.6.1.4.1.8072.3.2.67.16=-2;-2:;-3: ', "Negative integer check OK output" ); 224like($res->output, '/.*-2.*| iso.3.6.1.4.1.8072.3.2.67.16=-2;-2:;-3:/', "Negative integer check OK output" );
235 225
236$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" ); 226$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" );
237is($res->return_code, 1, "Negative integer check WARNING" ); 227is($res->return_code, 1, "Negative integer check WARNING" );
238is($res->output, 'SNMP WARNING - *-3* | iso.3.6.1.4.1.8072.3.2.67.16=-3;-2:;-3: ', "Negative integer check WARNING output" ); 228like($res->output, '/.*-3.*| iso.3.6.1.4.1.8072.3.2.67.16=-3;-2:;-3:/', "Negative integer check WARNING output" );
239 229
240$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" ); 230$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" );
241is($res->return_code, 2, "Negative integer check CRITICAL" ); 231is($res->return_code, 2, "Negative integer check CRITICAL" );
242is($res->output, 'SNMP CRITICAL - *-4* | iso.3.6.1.4.1.8072.3.2.67.16=-4;-2:;-3: ', "Negative integer check CRITICAL output" ); 232like($res->output, '/.*-4.*| iso.3.6.1.4.1.8072.3.2.67.16=-4;-2:;-3:/', "Negative integer check CRITICAL output" );
243 233
244$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.17 -w -3: -c -6:" ); 234$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.17 -w -3: -c -6:" );
245is($res->return_code, 1, "Negative integer as string, WARNING" ); 235is($res->return_code, 1, "Negative integer as string, WARNING" );
246is($res->output, 'SNMP WARNING - *-4* | iso.3.6.1.4.1.8072.3.2.67.17=-4;-3:;-6: ', "Negative integer as string, WARNING output" ); 236like($res->output, '/.*-4.*| iso.3.6.1.4.1.8072.3.2.67.17=-4;-3:;-6:/', "Negative integer as string, WARNING output" );
247 237
248$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.17 -w -2: -c -3:" ); 238$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.17 -w -2: -c -3:" );
249is($res->return_code, 2, "Negative integer as string, CRITICAL" ); 239is($res->return_code, 2, "Negative integer as string, CRITICAL" );
250is($res->output, 'SNMP CRITICAL - *-4* | iso.3.6.1.4.1.8072.3.2.67.17=-4;-2:;-3: ', "Negative integer as string, CRITICAL output" ); 240like($res->output, '/.*-4.*| iso.3.6.1.4.1.8072.3.2.67.17=-4;-2:;-3:/', "Negative integer as string, CRITICAL output" );
251 241
252$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.18 -c '~:-6.5'" ); 242# deactivated since the perl agent api of snmpd really does not allow floats
253is($res->return_code, 0, "Negative float OK" ); 243# $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.18 -c '~:-6.5'" );
254is($res->output, 'SNMP OK - -6.6 | iso.3.6.1.4.1.8072.3.2.67.18=-6.6;;@-6.5:~ ', "Negative float OK output" ); 244# is($res->return_code, 0, "Negative float OK" );
245# is($res->output, '-6.6 | iso.3.6.1.4.1.8072.3.2.67.18=-6.6;;@-6.5:~ ', "Negative float OK output" );
255 246
256$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.18 -w '~:-6.65' -c '~:-6.55'" ); 247# $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.18 -w '~:-6.65' -c '~:-6.55'" );
257is($res->return_code, 1, "Negative float WARNING" ); 248# is($res->return_code, 1, "Negative float WARNING" );
258is($res->output, 'SNMP WARNING - *-6.6* | iso.3.6.1.4.1.8072.3.2.67.18=-6.6;@-6.65:~;@-6.55:~ ', "Negative float WARNING output" ); 249# like($res->output, '/-6.6.*| .*67.18=-6.6;@-6.65:~;@-6.55:~/', "Negative float WARNING output" );
259 250
260$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w '1:100000,-10:20' -c '2:200000,-20:30'" ); 251$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w '1:100000,-10:20' -c '2:200000,-20:30'" );
261is($res->return_code, 0, "Multiple OIDs with thresholds" ); 252is($res->return_code, 0, "Multiple OIDs with thresholds" );
262like($res->output, '/SNMP OK - \d+ -4 | iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1:100000;2:200000 iso.3.6.1.4.1.8072.3.2.67.17=-4;-10:20;-20:30/', "Multiple OIDs with thresholds output" ); 253like($res->output, '/-4.*| .*67.10=\d+c;1:100000;2:200000 .*67.17=-4;-10:20;-20:30/', "Multiple OIDs with thresholds output" );
263 254
264$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w '1:100000,-1:2' -c '2:200000,-20:30'" ); 255$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w '1:100000,-1:2' -c '2:200000,-20:30'" );
265is($res->return_code, 1, "Multiple OIDs with thresholds" ); 256is($res->return_code, 1, "Multiple OIDs with thresholds" );
266like($res->output, '/SNMP WARNING - \d+ \*-4\* | iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1:100000;2:200000 iso.3.6.1.4.1.8072.3.2.67.17=-4;-10:20;-20:30/', "Multiple OIDs with thresholds output" ); 257like($res->output, '/-4.*| iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1:100000;2:200000 iso.3.6.1.4.1.8072.3.2.67.17=-4;-10:20;-20:30/', "Multiple OIDs with thresholds output" );
267 258
268$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w 1,2 -c 1" ); 259$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w 1,2 -c 1 -O" );
269is($res->return_code, 2, "Multiple OIDs with some thresholds" ); 260is($res->return_code, 2, "Multiple OIDs with some thresholds" );
270like($res->output, '/SNMP CRITICAL - \*\d+\* \*-4\* | iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1;2 iso.3.6.1.4.1.8072.3.2.67.17=-4;;/', "Multiple OIDs with thresholds output" ); 261like($res->output, '/.*-4.*| iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1;2 iso.3.6.1.4.1.8072.3.2.67.17=-4;;/', "Multiple OIDs with thresholds output" );
271 262
272$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19"); 263$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19");
273is($res->return_code, 0, "Test plain .1.3.6.1.4.1.8072.3.2.67.6 RC" ); 264is($res->return_code, 0, "Test plain .1.3.6.1.4.1.8072.3.2.67.6 RC" );
274is($res->output,'SNMP OK - 42 | iso.3.6.1.4.1.8072.3.2.67.19=42 ', "Test plain value of .1.3.6.1.4.1.8072.3.2.67.1" ); 265like($res->output,'/.*42.*| iso.3.6.1.4.1.8072.3.2.67.19=42/', "Test plain value of .1.3.6.1.4.1.8072.3.2.67.1" );
275 266
276$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 -M .1"); 267$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 -M .1");
277is($res->return_code, 0, "Test multiply RC" ); 268is($res->return_code, 0, "Test multiply RC" );
278is($res->output,'SNMP OK - 4.200000 | iso.3.6.1.4.1.8072.3.2.67.19=4.200000 ' , "Test multiply .1 output" ); 269like($res->output,'/.*4.200000.*| iso.3.6.1.4.1.8072.3.2.67.19=4.200000/' , "Test multiply .1 output" );
279 270
280$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 --multiplier=.1 -f '%.2f' "); 271$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 --multiplier=.1");
281is($res->return_code, 0, "Test multiply RC + format" ); 272is($res->return_code, 0, "Test multiply RC" );
282is($res->output, 'SNMP OK - 4.20 | iso.3.6.1.4.1.8072.3.2.67.19=4.20 ', "Test multiply .1 output + format" ); 273like($res->output, '/.*4.20.*| iso.3.6.1.4.1.8072.3.2.67.19=4.20/', "Test multiply .1 output" );
283 274
284$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 --multiplier=.1 -f '%.2f' -w 1"); 275$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 --multiplier=.1 -w 1");
285is($res->return_code, 1, "Test multiply RC + format + thresholds" ); 276is($res->return_code, 1, "Test multiply RC + thresholds" );
286is($res->output, 'SNMP WARNING - *4.20* | iso.3.6.1.4.1.8072.3.2.67.19=4.20;1 ', "Test multiply .1 output + format + thresholds" ); 277like($res->output, '/.*4.20.* | iso.3.6.1.4.1.8072.3.2.67.19=4.20+;1/', "Test multiply .1 output + thresholds" );
diff --git a/plugins/tests/check_snmp_agent.pl b/plugins/tests/check_snmp_agent.pl
index 38912e98..608b6f92 100644
--- a/plugins/tests/check_snmp_agent.pl
+++ b/plugins/tests/check_snmp_agent.pl
@@ -4,9 +4,10 @@
4# 4#
5 5
6#use strict; # Doesn't work 6#use strict; # Doesn't work
7use warnings;
7use NetSNMP::OID qw(:all); 8use NetSNMP::OID qw(:all);
8use NetSNMP::agent; 9use NetSNMP::agent;
9use NetSNMP::ASN qw(ASN_OCTET_STR ASN_COUNTER ASN_COUNTER64 ASN_INTEGER ASN_INTEGER64 ASN_UNSIGNED ASN_UNSIGNED64); 10use NetSNMP::ASN qw(ASN_OCTET_STR ASN_COUNTER ASN_COUNTER64 ASN_INTEGER ASN_INTEGER64 ASN_UNSIGNED ASN_UNSIGNED64 ASN_FLOAT);
10#use Math::Int64 qw(uint64); # Skip that module while we don't need it 11#use Math::Int64 qw(uint64); # Skip that module while we don't need it
11sub uint64 { return $_ } 12sub uint64 { return $_ }
12 13
@@ -22,21 +23,82 @@ IOS (tm) Catalyst 4000 "L3" Switch Software (cat4000-I9K91S-M), Version
22Technical Support: http://www.cisco.com/techsupport 23Technical Support: http://www.cisco.com/techsupport
23Copyright (c) 1986-2004 by cisco Systems, Inc. 24Copyright (c) 1986-2004 by cisco Systems, Inc.
24'; 25';
25my $multilin2 = "Kisco Outernetwork Oserating Gystem Totware 26my $multiline2 = "Kisco Outernetwork Oserating Gystem Totware
26Copyleft (c) 2400-2689 by kisco Systrems, Inc."; 27Copyleft (c) 2400-2689 by kisco Systrems, Inc.";
27my $multilin3 = 'This should not confuse check_snmp "parser" 28my $multiline3 = 'This should not confuse check_snmp "parser"
28into thinking there is no 2nd line'; 29into thinking there is no 2nd line';
29my $multilin4 = 'It\'s getting even harder if the line 30my $multiline4 = 'It\'s getting even harder if the line
30ends with with this: C:\\'; 31ends with with this: C:\\';
31my $multilin5 = 'And now have fun with with this: "C:\\" 32my $multiline5 = 'And now have fun with with this: "C:\\"
32because we\'re not done yet!'; 33because we\'re not done yet!';
33 34
34# Next are arrays of indexes (Type, initial value and increments) 35# Next are arrays of indexes (Type, initial value and increments)
35# 0..19 <---- please update comment when adding/removing fields 36# 0..19 <---- please update comment when adding/removing fields
36my @fields = (ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_UNSIGNED, ASN_UNSIGNED, ASN_COUNTER, ASN_COUNTER64, ASN_UNSIGNED, ASN_COUNTER, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_INTEGER, ASN_OCTET_STR, ASN_OCTET_STR, ASN_INTEGER ); 37my @fields = (ASN_OCTET_STR, # 0
37my @values = ($multiline, $multilin2, $multilin3, $multilin4, $multilin5, 4294965296, 1000, 4294965296, uint64("18446744073709351616"), int(rand(2**32)), 64000, "stringtests", "3.5", "87.4startswithnumberbutshouldbestring", '555"I said"', 'CUSTOM CHECK OK: foo is 12345', -2, '-4', '-6.6', 42 ); 38 ASN_OCTET_STR, # 1
39 ASN_OCTET_STR, # 2
40 ASN_OCTET_STR, # 3
41 ASN_OCTET_STR, # 4
42 ASN_UNSIGNED, # 5
43 ASN_UNSIGNED, # 6
44 ASN_COUNTER, # 7
45 ASN_COUNTER64, # 8
46 ASN_UNSIGNED, # 9
47 ASN_COUNTER, # 10
48 ASN_OCTET_STR, # 11
49 ASN_OCTET_STR, # 12
50 ASN_OCTET_STR, # 13
51 ASN_OCTET_STR, # 14
52 ASN_OCTET_STR, # 15
53 ASN_INTEGER, # 16
54 ASN_INTEGER, # 17
55 ASN_FLOAT, # 18
56 ASN_INTEGER # 19
57 );
58my @values = ($multiline, # 0
59 $multiline2, # 1
60 $multiline3, # 2
61 $multiline4, # 3
62 $multiline5, # 4
63 4294965296, # 5
64 1000, # 6
65 4294965296, # 7
66 uint64("18446744073709351616"), # 8
67 int(rand(2**32)), # 9
68 64000, # 10
69 "stringtests", # 11
70 "3.5", # 12
71 "87.4startswithnumberbutshouldbestring", # 13
72 '555"I said"', # 14
73 'CUSTOM CHECK OK: foo is 12345', # 15
74 '-2', # 16
75 '-4', # 17
76 '-6.6', # 18
77 42 # 19
78 );
38# undef increments are randomized 79# undef increments are randomized
39my @incrts = (undef, undef, undef, undef, undef, 1000, -500, 1000, 100000, undef, 666, undef, undef, undef, undef, undef, -1, undef, undef, 0 ); 80my @incrts = (
81 undef, # 0
82 undef, # 1
83 undef, # 2
84 undef, # 3
85 undef, # 4
86 1000, # 5
87 -500, # 6
88 1000, # 7
89 100000, # 8
90 undef, # 9
91 666, # 10
92 undef, # 11
93 undef, # 12
94 undef, # 13
95 undef, # 14
96 undef, # 15
97 -1, # 16
98 0, # 17
99 undef, # 18
100 0 # 19
101 );
40 102
41# Number of elements in our OID 103# Number of elements in our OID
42my $oidelts; 104my $oidelts;
diff --git a/plugins/tests/conf/snmpd.conf b/plugins/tests/conf/snmpd.conf
index eff5b0b3..1724c027 100644
--- a/plugins/tests/conf/snmpd.conf
+++ b/plugins/tests/conf/snmpd.conf
@@ -19,5 +19,5 @@ syscontact Alice
19# Embedded Subagents 19# Embedded Subagents
20############################################################################### 20###############################################################################
21 21
22perl do "tests/check_snmp_agent.pl"; 22perl do "./tests/check_snmp_agent.pl";
23 23
diff --git a/lib/tests/test_disk.c b/plugins/tests/test_check_disk.c
index c18db7a4..32b46c2d 100644
--- a/lib/tests/test_disk.c
+++ b/plugins/tests/test_check_disk.c
@@ -17,28 +17,17 @@
17 *****************************************************************************/ 17 *****************************************************************************/
18 18
19#include "common.h" 19#include "common.h"
20#include "utils_disk.h" 20#include "../check_disk.d/utils_disk.h"
21#include "tap.h" 21#include "../../tap/tap.h"
22#include "regex.h" 22#include "regex.h"
23 23
24void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc); 24void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags,
25 int expect, char *desc);
25 26
26int main(int argc, char **argv) { 27int main(int argc, char **argv) {
27 struct name_list *exclude_filesystem = NULL; 28 plan_tests(35);
28 struct name_list *exclude_fstype = NULL;
29 struct name_list *dummy_mountlist = NULL;
30 struct name_list *temp_name;
31 struct parameter_list *paths = NULL;
32 struct parameter_list *p, *prev = NULL, *last = NULL;
33
34 struct mount_entry *dummy_mount_list;
35 struct mount_entry *me;
36 struct mount_entry **mtail = &dummy_mount_list;
37 int cflags = REG_NOSUB | REG_EXTENDED;
38 int found = 0, count = 0;
39
40 plan_tests(33);
41 29
30 struct name_list *exclude_filesystem = NULL;
42 ok(np_find_name(exclude_filesystem, "/var/log") == false, "/var/log not in list"); 31 ok(np_find_name(exclude_filesystem, "/var/log") == false, "/var/log not in list");
43 np_add_name(&exclude_filesystem, "/var/log"); 32 np_add_name(&exclude_filesystem, "/var/log");
44 ok(np_find_name(exclude_filesystem, "/var/log") == true, "is in list now"); 33 ok(np_find_name(exclude_filesystem, "/var/log") == true, "is in list now");
@@ -47,6 +36,7 @@ int main(int argc, char **argv) {
47 ok(np_find_name(exclude_filesystem, "/home") == true, "is in list now"); 36 ok(np_find_name(exclude_filesystem, "/home") == true, "is in list now");
48 ok(np_find_name(exclude_filesystem, "/var/log") == true, "/var/log still in list"); 37 ok(np_find_name(exclude_filesystem, "/var/log") == true, "/var/log still in list");
49 38
39 struct name_list *exclude_fstype = NULL;
50 ok(np_find_name(exclude_fstype, "iso9660") == false, "iso9660 not in list"); 40 ok(np_find_name(exclude_fstype, "iso9660") == false, "iso9660 not in list");
51 np_add_name(&exclude_fstype, "iso9660"); 41 np_add_name(&exclude_fstype, "iso9660");
52 ok(np_find_name(exclude_fstype, "iso9660") == true, "is in list now"); 42 ok(np_find_name(exclude_fstype, "iso9660") == true, "is in list now");
@@ -59,7 +49,9 @@ int main(int argc, char **argv) {
59 } 49 }
60 */ 50 */
61 51
62 me = (struct mount_entry *)malloc(sizeof *me); 52 struct mount_entry *dummy_mount_list;
53 struct mount_entry **mtail = &dummy_mount_list;
54 struct mount_entry *me = (struct mount_entry *)malloc(sizeof *me);
63 me->me_devname = strdup("/dev/c0t0d0s0"); 55 me->me_devname = strdup("/dev/c0t0d0s0");
64 me->me_mountdir = strdup("/"); 56 me->me_mountdir = strdup("/");
65 *mtail = me; 57 *mtail = me;
@@ -77,50 +69,70 @@ int main(int argc, char **argv) {
77 *mtail = me; 69 *mtail = me;
78 mtail = &me->me_next; 70 mtail = &me->me_next;
79 71
72 int cflags = REG_NOSUB | REG_EXTENDED;
80 np_test_mount_entry_regex(dummy_mount_list, strdup("/"), cflags, 3, strdup("a")); 73 np_test_mount_entry_regex(dummy_mount_list, strdup("/"), cflags, 3, strdup("a"));
81 np_test_mount_entry_regex(dummy_mount_list, strdup("/dev"), cflags, 3, strdup("regex on dev names:")); 74 np_test_mount_entry_regex(dummy_mount_list, strdup("/dev"), cflags, 3,
82 np_test_mount_entry_regex(dummy_mount_list, strdup("/foo"), cflags, 0, strdup("regex on non existent dev/path:")); 75 strdup("regex on dev names:"));
83 np_test_mount_entry_regex(dummy_mount_list, strdup("/Foo"), cflags | REG_ICASE, 0, strdup("regi on non existent dev/path:")); 76 np_test_mount_entry_regex(dummy_mount_list, strdup("/foo"), cflags, 0,
84 np_test_mount_entry_regex(dummy_mount_list, strdup("/c.t0"), cflags, 3, strdup("partial devname regex match:")); 77 strdup("regex on non existent dev/path:"));
85 np_test_mount_entry_regex(dummy_mount_list, strdup("c0t0"), cflags, 1, strdup("partial devname regex match:")); 78 np_test_mount_entry_regex(dummy_mount_list, strdup("/Foo"), cflags | REG_ICASE, 0,
86 np_test_mount_entry_regex(dummy_mount_list, strdup("C0t0"), cflags | REG_ICASE, 1, strdup("partial devname regi match:")); 79 strdup("regi on non existent dev/path:"));
87 np_test_mount_entry_regex(dummy_mount_list, strdup("home"), cflags, 1, strdup("partial pathname regex match:")); 80 np_test_mount_entry_regex(dummy_mount_list, strdup("/c.t0"), cflags, 3,
88 np_test_mount_entry_regex(dummy_mount_list, strdup("hOme"), cflags | REG_ICASE, 1, strdup("partial pathname regi match:")); 81 strdup("partial devname regex match:"));
89 np_test_mount_entry_regex(dummy_mount_list, strdup("(/home)|(/var)"), cflags, 2, strdup("grouped regex pathname match:")); 82 np_test_mount_entry_regex(dummy_mount_list, strdup("c0t0"), cflags, 1,
90 np_test_mount_entry_regex(dummy_mount_list, strdup("(/homE)|(/Var)"), cflags | REG_ICASE, 2, strdup("grouped regi pathname match:")); 83 strdup("partial devname regex match:"));
91 84 np_test_mount_entry_regex(dummy_mount_list, strdup("C0t0"), cflags | REG_ICASE, 1,
92 np_add_parameter(&paths, "/home/groups"); 85 strdup("partial devname regi match:"));
93 np_add_parameter(&paths, "/var"); 86 np_test_mount_entry_regex(dummy_mount_list, strdup("home"), cflags, 1,
94 np_add_parameter(&paths, "/tmp"); 87 strdup("partial pathname regex match:"));
95 np_add_parameter(&paths, "/home/tonvoon"); 88 np_test_mount_entry_regex(dummy_mount_list, strdup("hOme"), cflags | REG_ICASE, 1,
96 np_add_parameter(&paths, "/dev/c2t0d0s0"); 89 strdup("partial pathname regi match:"));
97 90 np_test_mount_entry_regex(dummy_mount_list, strdup("(/home)|(/var)"), cflags, 2,
98 np_set_best_match(paths, dummy_mount_list, false); 91 strdup("grouped regex pathname match:"));
99 for (p = paths; p; p = p->name_next) { 92 np_test_mount_entry_regex(dummy_mount_list, strdup("(/homE)|(/Var)"), cflags | REG_ICASE, 2,
93 strdup("grouped regi pathname match:"));
94
95 filesystem_list test_paths = filesystem_list_init();
96 mp_int_fs_list_append(&test_paths, "/home/groups");
97 mp_int_fs_list_append(&test_paths, "/var");
98 mp_int_fs_list_append(&test_paths, "/tmp");
99 mp_int_fs_list_append(&test_paths, "/home/tonvoon");
100 mp_int_fs_list_append(&test_paths, "/dev/c2t0d0s0");
101 ok(test_paths.length == 5, "List counter works correctly with appends");
102
103 mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, false);
104 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
100 struct mount_entry *temp_me; 105 struct mount_entry *temp_me;
101 temp_me = p->best_match; 106 temp_me = p->best_match;
102 if (!strcmp(p->name, "/home/groups")) { 107 if (!strcmp(p->name, "/home/groups")) {
103 ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/groups got right best match: /home"); 108 ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"),
109 "/home/groups got right best match: /home");
104 } else if (!strcmp(p->name, "/var")) { 110 } else if (!strcmp(p->name, "/var")) {
105 ok(temp_me && !strcmp(temp_me->me_mountdir, "/var"), "/var got right best match: /var"); 111 ok(temp_me && !strcmp(temp_me->me_mountdir, "/var"), "/var got right best match: /var");
106 } else if (!strcmp(p->name, "/tmp")) { 112 } else if (!strcmp(p->name, "/tmp")) {
107 ok(temp_me && !strcmp(temp_me->me_mountdir, "/"), "/tmp got right best match: /"); 113 ok(temp_me && !strcmp(temp_me->me_mountdir, "/"), "/tmp got right best match: /");
108 } else if (!strcmp(p->name, "/home/tonvoon")) { 114 } else if (!strcmp(p->name, "/home/tonvoon")) {
109 ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/tonvoon got right best match: /home"); 115 ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"),
116 "/home/tonvoon got right best match: /home");
110 } else if (!strcmp(p->name, "/dev/c2t0d0s0")) { 117 } else if (!strcmp(p->name, "/dev/c2t0d0s0")) {
111 ok(temp_me && !strcmp(temp_me->me_devname, "/dev/c2t0d0s0"), "/dev/c2t0d0s0 got right best match: /dev/c2t0d0s0"); 118 ok(temp_me && !strcmp(temp_me->me_devname, "/dev/c2t0d0s0"),
119 "/dev/c2t0d0s0 got right best match: /dev/c2t0d0s0");
112 } 120 }
113 } 121 }
114 122
115 paths = NULL; /* Bad boy - should free, but this is a test suite */ 123 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
116 np_add_parameter(&paths, "/home/groups"); 124 mp_int_fs_list_del(&test_paths, p);
117 np_add_parameter(&paths, "/var"); 125 }
118 np_add_parameter(&paths, "/tmp"); 126 ok(test_paths.length == 0, "List delete sets counter properly");
119 np_add_parameter(&paths, "/home/tonvoon");
120 np_add_parameter(&paths, "/home");
121 127
122 np_set_best_match(paths, dummy_mount_list, true); 128 mp_int_fs_list_append(&test_paths, "/home/groups");
123 for (p = paths; p; p = p->name_next) { 129 mp_int_fs_list_append(&test_paths, "/var");
130 mp_int_fs_list_append(&test_paths, "/tmp");
131 mp_int_fs_list_append(&test_paths, "/home/tonvoon");
132 mp_int_fs_list_append(&test_paths, "/home");
133
134 mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, true);
135 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
124 if (!strcmp(p->name, "/home/groups")) { 136 if (!strcmp(p->name, "/home/groups")) {
125 ok(!p->best_match, "/home/groups correctly not found"); 137 ok(!p->best_match, "/home/groups correctly not found");
126 } else if (!strcmp(p->name, "/var")) { 138 } else if (!strcmp(p->name, "/var")) {
@@ -134,59 +146,68 @@ int main(int argc, char **argv) {
134 } 146 }
135 } 147 }
136 148
149 bool found = false;
137 /* test deleting first element in paths */ 150 /* test deleting first element in paths */
138 paths = np_del_parameter(paths, NULL); 151 mp_int_fs_list_del(&test_paths, NULL);
139 for (p = paths; p; p = p->name_next) { 152 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
140 if (!strcmp(p->name, "/home/groups")) 153 if (!strcmp(p->name, "/home/groups")) {
141 found = 1; 154 found = true;
155 }
142 } 156 }
143 ok(found == 0, "first element successfully deleted"); 157 ok(!found, "first element successfully deleted");
144 found = 0; 158 found = false;
145 159
146 p = paths; 160 parameter_list_elem *prev = NULL;
147 while (p) { 161 parameter_list_elem *p = NULL;
148 if (!strcmp(p->name, "/tmp")) 162 for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) {
149 p = np_del_parameter(p, prev); 163 if (!strcmp(path->name, "/tmp")) {
150 else { 164 mp_int_fs_list_del(&test_paths, path);
151 prev = p;
152 p = p->name_next;
153 } 165 }
166 p = path;
154 } 167 }
155 168
156 for (p = paths; p; p = p->name_next) { 169 parameter_list_elem *last = NULL;
157 if (!strcmp(p->name, "/tmp")) 170 for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) {
158 found = 1; 171 if (!strcmp(path->name, "/tmp")) {
159 if (p->name_next) 172 found = true;
160 prev = p; 173 }
161 else 174 if (path->next) {
162 last = p; 175 prev = path;
176 } else {
177 last = path;
178 }
163 } 179 }
164 ok(found == 0, "/tmp element successfully deleted"); 180 ok(!found, "/tmp element successfully deleted");
165 181
166 p = np_del_parameter(last, prev); 182 int count = 0;
167 for (p = paths; p; p = p->name_next) { 183 mp_int_fs_list_del(&test_paths, p);
168 if (!strcmp(p->name, "/home")) 184 for (p = test_paths.first; p; p = p->next) {
169 found = 1; 185 if (!strcmp(p->name, "/home")) {
186 found = true;
187 }
170 last = p; 188 last = p;
171 count++; 189 count++;
172 } 190 }
173 ok(found == 0, "last (/home) element successfully deleted"); 191 ok(!found, "last (/home) element successfully deleted");
174 ok(count == 2, "two elements remaining"); 192 ok(count == 2, "two elements remaining");
175 193
176 return exit_status(); 194 return exit_status();
177} 195}
178 196
179void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc) { 197void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags,
180 int matches = 0; 198 int expect, char *desc) {
181 regex_t re; 199 regex_t regex;
182 struct mount_entry *me; 200 if (regcomp(&regex, regstr, cflags) == 0) {
183 if (regcomp(&re, regstr, cflags) == 0) { 201 int matches = 0;
184 for (me = dummy_mount_list; me; me = me->me_next) { 202 for (struct mount_entry *me = dummy_mount_list; me; me = me->me_next) {
185 if (np_regex_match_mount_entry(me, &re)) 203 if (np_regex_match_mount_entry(me, &regex)) {
186 matches++; 204 matches++;
205 }
187 } 206 }
188 ok(matches == expect, "%s '%s' matched %i/3 entries. ok: %i/3", desc, regstr, expect, matches); 207 ok(matches == expect, "%s '%s' matched %i/3 entries. ok: %i/3", desc, regstr, expect,
208 matches);
189 209
190 } else 210 } else {
191 ok(false, "regex '%s' not compilable", regstr); 211 ok(false, "regex '%s' not compilable", regstr);
212 }
192} 213}
diff --git a/plugins/tests/test_check_disk.t b/plugins/tests/test_check_disk.t
new file mode 100755
index 00000000..56354650
--- /dev/null
+++ b/plugins/tests/test_check_disk.t
@@ -0,0 +1,6 @@
1#!/usr/bin/perl
2use Test::More;
3if (! -e "./test_check_disk") {
4 plan skip_all => "./test_check_disk not compiled - please enable libtap library to test";
5}
6exec "./test_check_disk";
diff --git a/plugins/tests/test_check_snmp.c b/plugins/tests/test_check_snmp.c
new file mode 100644
index 00000000..d71706d0
--- /dev/null
+++ b/plugins/tests/test_check_snmp.c
@@ -0,0 +1,175 @@
1/*****************************************************************************
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 *
17 *****************************************************************************/
18
19#include "tap.h"
20#include "../../config.h"
21
22#include <unistd.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25
26#include "utils_base.c"
27#include "../check_snmp.d/check_snmp_helpers.h"
28
29char *_np_state_generate_key(int argc, char **argv);
30char *_np_state_calculate_location_prefix(void);
31
32int main(int argc, char **argv) {
33 char *temp_string = (char *)_np_state_generate_key(argc, argv);
34 ok(!strcmp(temp_string, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"),
35 "Got hash with exe and no parameters") ||
36 diag("You are probably running in wrong directory. Must run as ./test_utils");
37
38 int fake_argc = 4;
39 char *fake_argv[] = {
40 "./test_utils",
41 "here",
42 "--and",
43 "now",
44 };
45 temp_string = (char *)_np_state_generate_key(fake_argc, fake_argv);
46 ok(!strcmp(temp_string, "bd72da9f78ff1419fad921ea5e43ce56508aef6c"),
47 "Got based on expected argv");
48
49 unsetenv("MP_STATE_PATH");
50 temp_string = (char *)_np_state_calculate_location_prefix();
51 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory");
52
53 setenv("MP_STATE_PATH", "", 1);
54 temp_string = (char *)_np_state_calculate_location_prefix();
55 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory even with empty string");
56
57 setenv("MP_STATE_PATH", "/usr/local/nagios/var", 1);
58 temp_string = (char *)_np_state_calculate_location_prefix();
59 ok(!strcmp(temp_string, "/usr/local/nagios/var"), "Got default directory");
60
61 fake_argc = 1;
62 fake_argv[0] = "./test_utils";
63 state_key temp_state_key1 = np_enable_state(NULL, 51, "check_test", fake_argc, fake_argv);
64 ok(!strcmp(temp_state_key1.plugin_name, "check_test"), "Got plugin name");
65 ok(!strcmp(temp_state_key1.name, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"),
66 "Got generated filename");
67
68 state_key temp_state_key2 =
69 np_enable_state("allowedchars_in_keyname", 77, "check_snmp", fake_argc, fake_argv);
70
71 char state_path[1024];
72 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/allowedchars_in_keyname",
73 (unsigned long)geteuid());
74 ok(!strcmp(temp_state_key2.plugin_name, "check_test"), "Got plugin name");
75 ok(!strcmp(temp_state_key2.name, "allowedchars_in_keyname"), "Got key name with valid chars");
76 ok(!strcmp(temp_state_key2._filename, state_path), "Got internal filename");
77
78 /* Don't do this test just yet. Will die */
79 /*
80 np_enable_state("bad^chars$in@here", 77);
81 temp_state_key = this_monitoring_plugin->state;
82 ok( !strcmp(temp_state_key->name, "bad_chars_in_here"), "Got key name with bad chars replaced"
83 );
84 */
85
86 state_key temp_state_key3 =
87 np_enable_state("funnykeyname", 54, "check_snmp", fake_argc, fake_argv);
88 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/funnykeyname",
89 (unsigned long)geteuid());
90 ok(!strcmp(temp_state_key3.plugin_name, "check_test"), "Got plugin name");
91 ok(!strcmp(temp_state_key3.name, "funnykeyname"), "Got key name");
92
93 ok(!strcmp(temp_state_key3._filename, state_path), "Got internal filename");
94 ok(temp_state_key3.data_version == 54, "Version set");
95
96 state_data *temp_state_data = np_state_read(temp_state_key3);
97 ok(temp_state_data == NULL, "Got no state data as file does not exist");
98
99 /*
100 temp_fp = fopen("var/statefile", "r");
101 if (temp_fp==NULL)
102 printf("Error opening. errno=%d\n", errno);
103 printf("temp_fp=%s\n", temp_fp);
104 ok( _np_state_read_file(temp_fp) == true, "Can read state file" );
105 fclose(temp_fp);
106 */
107
108 temp_state_key3._filename = "var/statefile";
109 temp_state_data = np_state_read(temp_state_key3);
110 ok(temp_state_data != NULL, "Got state data now") ||
111 diag("Are you running in right directory? Will get coredump next if not");
112 ok(temp_state_data->time == 1234567890, "Got time");
113 ok(!strcmp((char *)temp_state_data->data, "String to read"), "Data as expected");
114
115 temp_state_key3.data_version = 53;
116 temp_state_data = np_state_read(temp_state_key3);
117 ok(temp_state_data == NULL, "Older data version gives NULL");
118 temp_state_key3.data_version = 54;
119
120 temp_state_key3._filename = "var/nonexistent";
121 temp_state_data = np_state_read(temp_state_key3);
122 ok(temp_state_data == NULL, "Missing file gives NULL");
123
124 temp_state_key3._filename = "var/oldformat";
125 temp_state_data = np_state_read(temp_state_key3);
126 ok(temp_state_data == NULL, "Old file format gives NULL");
127
128 temp_state_key3._filename = "var/baddate";
129 temp_state_data = np_state_read(temp_state_key3);
130 ok(temp_state_data == NULL, "Bad date gives NULL");
131
132 temp_state_key3._filename = "var/missingdataline";
133 temp_state_data = np_state_read(temp_state_key3);
134 ok(temp_state_data == NULL, "Missing data line gives NULL");
135
136 unlink("var/generated");
137 temp_state_key3._filename = "var/generated";
138
139 time_t current_time = 1234567890;
140 np_state_write_string(temp_state_key3, current_time, "String to read");
141 ok(system("cmp var/generated var/statefile") == 0, "Generated file same as expected");
142
143 unlink("var/generated_directory/statefile");
144 unlink("var/generated_directory");
145 temp_state_key3._filename = "var/generated_directory/statefile";
146 current_time = 1234567890;
147 np_state_write_string(temp_state_key3, current_time, "String to read");
148 ok(system("cmp var/generated_directory/statefile var/statefile") == 0,
149 "Have created directory");
150
151 /* This test to check cannot write to dir - can't automate yet */
152 /*
153 unlink("var/generated_bad_dir");
154 mkdir("var/generated_bad_dir", S_IRUSR);
155 np_state_write_string(current_time, "String to read");
156 */
157
158 temp_state_key3._filename = "var/generated";
159 time(&current_time);
160 np_state_write_string(temp_state_key3, 0, "String to read");
161 temp_state_data = np_state_read(temp_state_key3);
162 /* Check time is set to current_time */
163 ok(system("cmp var/generated var/statefile > /dev/null") != 0,
164 "Generated file should be different this time");
165 ok(temp_state_data->time - current_time <= 1, "Has time generated from current time");
166
167 /* Don't know how to automatically test this. Need to be able to redefine die and catch the
168 * error */
169 /*
170 temp_state_key->_filename="/dev/do/not/expect/to/be/able/to/write";
171 np_state_write_string(0, "Bad file");
172 */
173
174 np_cleanup();
175}
diff --git a/plugins/tests/test_check_snmp.t b/plugins/tests/test_check_snmp.t
new file mode 100755
index 00000000..967633e9
--- /dev/null
+++ b/plugins/tests/test_check_snmp.t
@@ -0,0 +1,6 @@
1#!/usr/bin/perl
2use Test::More;
3if (! -e "./test_check_snmp") {
4 plan skip_all => "./test_check_snmp not compiled - please enable libtap library to test";
5}
6exec "./test_check_snmp";
diff --git a/plugins/tests/test_check_swap.c b/plugins/tests/test_check_swap.c
index b85fb4ad..94d56ce7 100644
--- a/plugins/tests/test_check_swap.c
+++ b/plugins/tests/test_check_swap.c
@@ -5,9 +5,7 @@
5int verbose = 0; 5int verbose = 0;
6 6
7void print_usage(void) {} 7void print_usage(void) {}
8void print_help(swap_config config) { 8void print_help(swap_config config) { (void)config; }
9 (void) config;
10}
11 9
12const char *progname = "test_check_swap"; 10const char *progname = "test_check_swap";
13 11
diff --git a/plugins/urlize.c b/plugins/urlize.c
index 1aa4e425..a8590fae 100644
--- a/plugins/urlize.c
+++ b/plugins/urlize.c
@@ -53,8 +53,10 @@ int main(int argc, char **argv) {
53 53
54 int c; 54 int c;
55 int option = 0; 55 int option = 0;
56 static struct option longopts[] = { 56 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
57 {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"url", required_argument, 0, 'u'}, {0, 0, 0, 0}}; 57 {"version", no_argument, 0, 'V'},
58 {"url", required_argument, 0, 'u'},
59 {0, 0, 0, 0}};
58 60
59 setlocale(LC_ALL, ""); 61 setlocale(LC_ALL, "");
60 bindtextdomain(PACKAGE, LOCALEDIR); 62 bindtextdomain(PACKAGE, LOCALEDIR);
@@ -69,8 +71,9 @@ int main(int argc, char **argv) {
69 while (1) { 71 while (1) {
70 c = getopt_long(argc, argv, "+hVu:", longopts, &option); 72 c = getopt_long(argc, argv, "+hVu:", longopts, &option);
71 73
72 if (c == -1 || c == EOF) 74 if (c == -1 || c == EOF) {
73 break; 75 break;
76 }
74 77
75 switch (c) { 78 switch (c) {
76 case 'h': /* help */ 79 case 'h': /* help */
@@ -90,8 +93,9 @@ int main(int argc, char **argv) {
90 } 93 }
91 } 94 }
92 95
93 if (url == NULL) 96 if (url == NULL) {
94 url = strdup(argv[optind++]); 97 url = strdup(argv[optind++]);
98 }
95 99
96 cmd = strdup(argv[optind++]); 100 cmd = strdup(argv[optind++]);
97 for (c = optind; c < argc; c++) { 101 for (c = optind; c < argc; c++) {
@@ -118,27 +122,32 @@ int main(int argc, char **argv) {
118 strcat(tstr, buf); 122 strcat(tstr, buf);
119 } 123 }
120 124
121 if (!found) 125 if (!found) {
122 die(STATE_UNKNOWN, _("%s UNKNOWN - No data received from host\nCMD: %s</A>\n"), argv[0], cmd); 126 die(STATE_UNKNOWN, _("%s UNKNOWN - No data received from host\nCMD: %s</A>\n"), argv[0],
127 cmd);
128 }
123 129
124 /* chop the newline character */ 130 /* chop the newline character */
125 if ((nstr = strchr(tstr, NEWLINE_CHARACTER)) != NULL) 131 if ((nstr = strchr(tstr, NEWLINE_CHARACTER)) != NULL) {
126 *nstr = '\0'; 132 *nstr = '\0';
133 }
127 134
128 /* tokenize the string for Perfdata if there is some */ 135 /* tokenize the string for Perfdata if there is some */
129 nstr = strtok(tstr, PERF_CHARACTER); 136 nstr = strtok(tstr, PERF_CHARACTER);
130 printf("%s", nstr); 137 printf("%s", nstr);
131 printf("</A>"); 138 printf("</A>");
132 nstr = strtok(NULL, PERF_CHARACTER); 139 nstr = strtok(NULL, PERF_CHARACTER);
133 if (nstr != NULL) 140 if (nstr != NULL) {
134 printf(" | %s", nstr); 141 printf(" | %s", nstr);
142 }
135 143
136 /* close the pipe */ 144 /* close the pipe */
137 result = spclose(child_process); 145 result = spclose(child_process);
138 146
139 /* WARNING if output found on stderr */ 147 /* WARNING if output found on stderr */
140 if (fgets(buf, MAX_INPUT_BUFFER - 1, child_stderr)) 148 if (fgets(buf, MAX_INPUT_BUFFER - 1, child_stderr)) {
141 result = max_state(result, STATE_WARNING); 149 result = max_state(result, STATE_WARNING);
150 }
142 151
143 /* close stderr */ 152 /* close stderr */
144 (void)fclose(child_stderr); 153 (void)fclose(child_stderr);
@@ -153,8 +162,10 @@ void print_help(void) {
153 printf(COPYRIGHT, copyright, email); 162 printf(COPYRIGHT, copyright, email);
154 163
155 printf("%s\n", _("This plugin wraps the text output of another command (plugin) in HTML <A>")); 164 printf("%s\n", _("This plugin wraps the text output of another command (plugin) in HTML <A>"));
156 printf("%s\n", _("tags, thus displaying the child plugin's output as a clickable link in compatible")); 165 printf("%s\n",
157 printf("%s\n", _("monitoring status screen. This plugin returns the status of the invoked plugin.")); 166 _("tags, thus displaying the child plugin's output as a clickable link in compatible"));
167 printf("%s\n",
168 _("monitoring status screen. This plugin returns the status of the invoked plugin."));
158 169
159 printf("\n\n"); 170 printf("\n\n");
160 171
@@ -164,7 +175,8 @@ void print_help(void) {
164 175
165 printf("\n"); 176 printf("\n");
166 printf("%s\n", _("Examples:")); 177 printf("%s\n", _("Examples:"));
167 printf("%s\n", _("Pay close attention to quoting to ensure that the shell passes the expected")); 178 printf("%s\n",
179 _("Pay close attention to quoting to ensure that the shell passes the expected"));
168 printf("%s\n\n", _("data to the plugin. For example, in:")); 180 printf("%s\n\n", _("data to the plugin. For example, in:"));
169 printf(" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r 'two words'")); 181 printf(" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r 'two words'"));
170 printf(" %s\n", _("the shell will remove the single quotes and urlize will see:")); 182 printf(" %s\n", _("the shell will remove the single quotes and urlize will see:"));
diff --git a/plugins/utils.c b/plugins/utils.c
index 34335c89..41fe5fcf 100644
--- a/plugins/utils.c
+++ b/plugins/utils.c
@@ -285,7 +285,8 @@ double delta_time(struct timeval tv) {
285 struct timeval now; 285 struct timeval now;
286 286
287 gettimeofday(&now, NULL); 287 gettimeofday(&now, NULL);
288 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000); 288 return ((double)(now.tv_sec - tv.tv_sec) +
289 (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
289} 290}
290 291
291long deltime(struct timeval tv) { 292long deltime(struct timeval tv) {
@@ -507,8 +508,8 @@ int xasprintf(char **strp, const char *fmt, ...) {
507 * 508 *
508 ******************************************************************************/ 509 ******************************************************************************/
509 510
510char *perfdata(const char *label, long int val, const char *uom, bool warnp, long int warn, bool critp, long int crit, bool minp, 511char *perfdata(const char *label, long int val, const char *uom, bool warnp, long int warn,
511 long int minv, bool maxp, long int maxv) { 512 bool critp, long int crit, bool minp, long int minv, bool maxp, long int maxv) {
512 char *data = NULL; 513 char *data = NULL;
513 514
514 if (strpbrk(label, "'= ")) { 515 if (strpbrk(label, "'= ")) {
@@ -542,10 +543,11 @@ char *perfdata(const char *label, long int val, const char *uom, bool warnp, lon
542 return data; 543 return data;
543} 544}
544 545
545char *perfdata_uint64(const char *label, uint64_t val, const char *uom, bool warnp, /* Warning present */ 546char *perfdata_uint64(const char *label, uint64_t val, const char *uom,
546 uint64_t warn, bool critp, /* Critical present */ 547 bool warnp, /* Warning present */
547 uint64_t crit, bool minp, /* Minimum present */ 548 uint64_t warn, bool critp, /* Critical present */
548 uint64_t minv, bool maxp, /* Maximum present */ 549 uint64_t crit, bool minp, /* Minimum present */
550 uint64_t minv, bool maxp, /* Maximum present */
549 uint64_t maxv) { 551 uint64_t maxv) {
550 char *data = NULL; 552 char *data = NULL;
551 553
@@ -580,10 +582,11 @@ char *perfdata_uint64(const char *label, uint64_t val, const char *uom, bool war
580 return data; 582 return data;
581} 583}
582 584
583char *perfdata_int64(const char *label, int64_t val, const char *uom, bool warnp, /* Warning present */ 585char *perfdata_int64(const char *label, int64_t val, const char *uom,
584 int64_t warn, bool critp, /* Critical present */ 586 bool warnp, /* Warning present */
585 int64_t crit, bool minp, /* Minimum present */ 587 int64_t warn, bool critp, /* Critical present */
586 int64_t minv, bool maxp, /* Maximum present */ 588 int64_t crit, bool minp, /* Minimum present */
589 int64_t minv, bool maxp, /* Maximum present */
587 int64_t maxv) { 590 int64_t maxv) {
588 char *data = NULL; 591 char *data = NULL;
589 592
@@ -618,8 +621,8 @@ char *perfdata_int64(const char *label, int64_t val, const char *uom, bool warnp
618 return data; 621 return data;
619} 622}
620 623
621char *fperfdata(const char *label, double val, const char *uom, bool warnp, double warn, bool critp, double crit, bool minp, double minv, 624char *fperfdata(const char *label, double val, const char *uom, bool warnp, double warn, bool critp,
622 bool maxp, double maxv) { 625 double crit, bool minp, double minv, bool maxp, double maxv) {
623 char *data = NULL; 626 char *data = NULL;
624 627
625 if (strpbrk(label, "'= ")) { 628 if (strpbrk(label, "'= ")) {
@@ -655,7 +658,8 @@ char *fperfdata(const char *label, double val, const char *uom, bool warnp, doub
655 return data; 658 return data;
656} 659}
657 660
658char *sperfdata(const char *label, double val, const char *uom, char *warn, char *crit, bool minp, double minv, bool maxp, double maxv) { 661char *sperfdata(const char *label, double val, const char *uom, char *warn, char *crit, bool minp,
662 double minv, bool maxp, double maxv) {
659 char *data = NULL; 663 char *data = NULL;
660 if (strpbrk(label, "'= ")) { 664 if (strpbrk(label, "'= ")) {
661 xasprintf(&data, "'%s'=", label); 665 xasprintf(&data, "'%s'=", label);
@@ -690,7 +694,8 @@ char *sperfdata(const char *label, double val, const char *uom, char *warn, char
690 return data; 694 return data;
691} 695}
692 696
693char *sperfdata_int(const char *label, int val, const char *uom, char *warn, char *crit, bool minp, int minv, bool maxp, int maxv) { 697char *sperfdata_int(const char *label, int val, const char *uom, char *warn, char *crit, bool minp,
698 int minv, bool maxp, int maxv) {
694 char *data = NULL; 699 char *data = NULL;
695 if (strpbrk(label, "'= ")) { 700 if (strpbrk(label, "'= ")) {
696 xasprintf(&data, "'%s'=", label); 701 xasprintf(&data, "'%s'=", label);
diff --git a/plugins/utils.h b/plugins/utils.h
index 92a6c115..1f0e021b 100644
--- a/plugins/utils.h
+++ b/plugins/utils.h
@@ -76,7 +76,7 @@ char *strnl(char *);
76char *strpcpy(char *, const char *, const char *); 76char *strpcpy(char *, const char *, const char *);
77char *strpcat(char *, const char *, const char *); 77char *strpcat(char *, const char *, const char *);
78int xvasprintf(char **strp, const char *fmt, va_list ap); 78int xvasprintf(char **strp, const char *fmt, va_list ap);
79int xasprintf(char **strp, const char *fmt, ...); 79int xasprintf(char **strp, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
80 80
81void usage(const char *) __attribute__((noreturn)); 81void usage(const char *) __attribute__((noreturn));
82void usage2(const char *, const char *) __attribute__((noreturn)); 82void usage2(const char *, const char *) __attribute__((noreturn));
@@ -88,13 +88,17 @@ void usage_va(const char *fmt, ...) __attribute__((noreturn));
88#define max(a, b) (((a) > (b)) ? (a) : (b)) 88#define max(a, b) (((a) > (b)) ? (a) : (b))
89#define min(a, b) (((a) < (b)) ? (a) : (b)) 89#define min(a, b) (((a) < (b)) ? (a) : (b))
90 90
91char *perfdata(const char *, long int, const char *, bool, long int, bool, long int, bool, long int, bool, long int); 91char *perfdata(const char *, long int, const char *, bool, long int, bool, long int, bool, long int,
92 bool, long int);
92 93
93char *perfdata_uint64(const char *, uint64_t, const char *, bool, uint64_t, bool, uint64_t, bool, uint64_t, bool, uint64_t); 94char *perfdata_uint64(const char *, uint64_t, const char *, bool, uint64_t, bool, uint64_t, bool,
95 uint64_t, bool, uint64_t);
94 96
95char *perfdata_int64(const char *, int64_t, const char *, bool, int64_t, bool, int64_t, bool, int64_t, bool, int64_t); 97char *perfdata_int64(const char *, int64_t, const char *, bool, int64_t, bool, int64_t, bool,
98 int64_t, bool, int64_t);
96 99
97char *fperfdata(const char *, double, const char *, bool, double, bool, double, bool, double, bool, double); 100char *fperfdata(const char *, double, const char *, bool, double, bool, double, bool, double, bool,
101 double);
98 102
99char *sperfdata(const char *, double, const char *, char *, char *, bool, double, bool, double); 103char *sperfdata(const char *, double, const char *, char *, char *, bool, double, bool, double);
100 104
@@ -104,21 +108,22 @@ char *sperfdata_int(const char *, int, const char *, char *, char *, bool, int,
104 most will or should. Therefore, for consistency, these very common 108 most will or should. Therefore, for consistency, these very common
105 options should have only these meanings throughout the overall suite */ 109 options should have only these meanings throughout the overall suite */
106 110
107#define STD_LONG_OPTS \ 111#define STD_LONG_OPTS \
108 {"version", no_argument, 0, 'V'}, {"verbose", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, \ 112 {"version", no_argument, 0, 'V'}, {"verbose", no_argument, 0, 'v'}, \
109 {"timeout", required_argument, 0, 't'}, {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'}, \ 113 {"help", no_argument, 0, 'h'}, {"timeout", required_argument, 0, 't'}, \
114 {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'}, \
110 {"hostname", required_argument, 0, 'H'} 115 {"hostname", required_argument, 0, 'H'}
111 116
112#define COPYRIGHT \ 117#define COPYRIGHT \
113 "Copyright (c) %s Monitoring Plugins Development Team\n\ 118 "Copyright (c) %s Monitoring Plugins Development Team\n\
114\t<%s>\n\n" 119\t<%s>\n\n"
115 120
116#define UT_HLP_VRS \ 121#define UT_HLP_VRS \
117 _("\ 122 _("\
118 %s (-h | --help) for detailed help\n\ 123 %s (-h | --help) for detailed help\n\
119 %s (-V | --version) for version information\n") 124 %s (-V | --version) for version information\n")
120 125
121#define UT_HELP_VRSN \ 126#define UT_HELP_VRSN \
122 _("\ 127 _("\
123\nOptions:\n\ 128\nOptions:\n\
124 -h, --help\n\ 129 -h, --help\n\
@@ -126,52 +131,52 @@ char *sperfdata_int(const char *, int, const char *, char *, char *, bool, int,
126 -V, --version\n\ 131 -V, --version\n\
127 Print version information\n") 132 Print version information\n")
128 133
129#define UT_HOST_PORT \ 134#define UT_HOST_PORT \
130 _("\ 135 _("\
131 -H, --hostname=ADDRESS\n\ 136 -H, --hostname=ADDRESS\n\
132 Host name, IP Address, or unix socket (must be an absolute path)\n\ 137 Host name, IP Address, or unix socket (must be an absolute path)\n\
133 -%c, --port=INTEGER\n\ 138 -%c, --port=INTEGER\n\
134 Port number (default: %s)\n") 139 Port number (default: %s)\n")
135 140
136#define UT_IPv46 \ 141#define UT_IPv46 \
137 _("\ 142 _("\
138 -4, --use-ipv4\n\ 143 -4, --use-ipv4\n\
139 Use IPv4 connection\n\ 144 Use IPv4 connection\n\
140 -6, --use-ipv6\n\ 145 -6, --use-ipv6\n\
141 Use IPv6 connection\n") 146 Use IPv6 connection\n")
142 147
143#define UT_VERBOSE \ 148#define UT_VERBOSE \
144 _("\ 149 _("\
145 -v, --verbose\n\ 150 -v, --verbose\n\
146 Show details for command-line debugging (output may be truncated by\n\ 151 Show details for command-line debugging (output may be truncated by\n\
147 the monitoring system)\n") 152 the monitoring system)\n")
148 153
149#define UT_WARN_CRIT \ 154#define UT_WARN_CRIT \
150 _("\ 155 _("\
151 -w, --warning=DOUBLE\n\ 156 -w, --warning=DOUBLE\n\
152 Response time to result in warning status (seconds)\n\ 157 Response time to result in warning status (seconds)\n\
153 -c, --critical=DOUBLE\n\ 158 -c, --critical=DOUBLE\n\
154 Response time to result in critical status (seconds)\n") 159 Response time to result in critical status (seconds)\n")
155 160
156#define UT_WARN_CRIT_RANGE \ 161#define UT_WARN_CRIT_RANGE \
157 _("\ 162 _("\
158 -w, --warning=RANGE\n\ 163 -w, --warning=RANGE\n\
159 Warning range (format: start:end). Alert if outside this range\n\ 164 Warning range (format: start:end). Alert if outside this range\n\
160 -c, --critical=RANGE\n\ 165 -c, --critical=RANGE\n\
161 Critical range\n") 166 Critical range\n")
162 167
163#define UT_CONN_TIMEOUT \ 168#define UT_CONN_TIMEOUT \
164 _("\ 169 _("\
165 -t, --timeout=INTEGER\n\ 170 -t, --timeout=INTEGER\n\
166 Seconds before connection times out (default: %d)\n") 171 Seconds before connection times out (default: %d)\n")
167 172
168#define UT_PLUG_TIMEOUT \ 173#define UT_PLUG_TIMEOUT \
169 _("\ 174 _("\
170 -t, --timeout=INTEGER\n\ 175 -t, --timeout=INTEGER\n\
171 Seconds before plugin times out (default: %d)\n") 176 Seconds before plugin times out (default: %d)\n")
172 177
173#ifdef NP_EXTRA_OPTS 178#ifdef NP_EXTRA_OPTS
174# define UT_EXTRA_OPTS \ 179# define UT_EXTRA_OPTS \
175 _("\ 180 _("\
176 --extra-opts=[section][@file]\n\ 181 --extra-opts=[section][@file]\n\
177 Read options from an ini file. See\n\ 182 Read options from an ini file. See\n\
@@ -181,25 +186,25 @@ char *sperfdata_int(const char *, int, const char *, char *, char *, bool, int,
181# define UT_EXTRA_OPTS " \b" 186# define UT_EXTRA_OPTS " \b"
182#endif 187#endif
183 188
184#define UT_THRESHOLDS_NOTES \ 189#define UT_THRESHOLDS_NOTES \
185 _("\ 190 _("\
186 See:\n\ 191 See:\n\
187 https://www.monitoring-plugins.org/doc/guidelines.html#THRESHOLDFORMAT\n\ 192 https://www.monitoring-plugins.org/doc/guidelines.html#THRESHOLDFORMAT\n\
188 for THRESHOLD format and examples.\n") 193 for THRESHOLD format and examples.\n")
189 194
190#define UT_SUPPORT \ 195#define UT_SUPPORT \
191 _("\n\ 196 _("\n\
192Send email to help@monitoring-plugins.org if you have questions regarding\n\ 197Send email to help@monitoring-plugins.org if you have questions regarding\n\
193use of this software. To submit patches or suggest improvements, send email\n\ 198use of this software. To submit patches or suggest improvements, send email\n\
194to devel@monitoring-plugins.org\n\n") 199to devel@monitoring-plugins.org\n\n")
195 200
196#define UT_NOWARRANTY \ 201#define UT_NOWARRANTY \
197 _("\n\ 202 _("\n\
198The Monitoring Plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n\ 203The Monitoring Plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n\
199copies of the plugins under the terms of the GNU General Public License.\n\ 204copies of the plugins under the terms of the GNU General Public License.\n\
200For more information about these matters, see the file named COPYING.\n") 205For more information about these matters, see the file named COPYING.\n")
201 206
202#define UT_OUTPUT_FORMAT \ 207#define UT_OUTPUT_FORMAT \
203 _("\ 208 _("\
204 --output-format=OUTPUT_FORMAT\n\ 209 --output-format=OUTPUT_FORMAT\n\
205 Select output format. Valid values: \"multi-line\", \"mp-test-json\"\n") 210 Select output format. Valid values: \"multi-line\", \"mp-test-json\"\n")
diff --git a/tap/tap.c b/tap/tap.c
index 00ceab27..fb40736f 100644
--- a/tap/tap.c
+++ b/tap/tap.c
@@ -65,7 +65,8 @@ static void _cleanup(void);
65 * test_name -- the name of the test, may be NULL 65 * test_name -- the name of the test, may be NULL
66 * test_comment -- a comment to print afterwards, may be NULL 66 * test_comment -- a comment to print afterwards, may be NULL
67 */ 67 */
68unsigned int _gen_result(int ok, const char *func, char *file, unsigned int line, char *test_name, ...) { 68unsigned int _gen_result(int ok, const char *func, char *file, unsigned int line, char *test_name,
69 ...) {
69 va_list ap; 70 va_list ap;
70 char *local_test_name = NULL; 71 char *local_test_name = NULL;
71 char *c; 72 char *c;
@@ -95,7 +96,9 @@ unsigned int _gen_result(int ok, const char *func, char *file, unsigned int line
95 } 96 }
96 97
97 if (name_is_digits) { 98 if (name_is_digits) {
98 diag(" You named your test '%s'. You shouldn't use numbers for your test names.", local_test_name); 99 diag(
100 " You named your test '%s'. You shouldn't use numbers for your test names.",
101 local_test_name);
99 diag(" Very confusing."); 102 diag(" Very confusing.");
100 } 103 }
101 } 104 }
@@ -116,8 +119,9 @@ unsigned int _gen_result(int ok, const char *func, char *file, unsigned int line
116 if (local_test_name != NULL) { 119 if (local_test_name != NULL) {
117 flockfile(stdout); 120 flockfile(stdout);
118 for (c = local_test_name; *c != '\0'; c++) { 121 for (c = local_test_name; *c != '\0'; c++) {
119 if (*c == '#') 122 if (*c == '#') {
120 fputc('\\', stdout); 123 fputc('\\', stdout);
124 }
121 fputc((int)*c, stdout); 125 fputc((int)*c, stdout);
122 } 126 }
123 funlockfile(stdout); 127 funlockfile(stdout);
@@ -135,14 +139,16 @@ unsigned int _gen_result(int ok, const char *func, char *file, unsigned int line
135 the test failed. */ 139 the test failed. */
136 if (todo) { 140 if (todo) {
137 printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed); 141 printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed);
138 if (!ok) 142 if (!ok) {
139 failures--; 143 failures--;
144 }
140 } 145 }
141 146
142 printf("\n"); 147 printf("\n");
143 148
144 if (!ok) 149 if (!ok) {
145 diag(" Failed %stest (%s:%s() at line %d)", todo ? "(TODO) " : "", file, func, line); 150 diag(" Failed %stest (%s:%s() at line %d)", todo ? "(TODO) " : "", file, func, line);
151 }
146 152
147 free(local_test_name); 153 free(local_test_name);
148 154
@@ -212,8 +218,9 @@ int plan_skip_all(char *reason) {
212 218
213 printf("1..0"); 219 printf("1..0");
214 220
215 if (reason != NULL) 221 if (reason != NULL) {
216 printf(" # Skip %s", reason); 222 printf(" # Skip %s", reason);
223 }
217 224
218 printf("\n"); 225 printf("\n");
219 226
@@ -294,7 +301,8 @@ int skip(unsigned int n, char *fmt, ...) {
294 301
295 while (n-- > 0) { 302 while (n-- > 0) {
296 test_count++; 303 test_count++;
297 printf("ok %d # skip %s\n", test_count, skip_msg != NULL ? skip_msg : "libtap():malloc() failed"); 304 printf("ok %d # skip %s\n", test_count,
305 skip_msg != NULL ? skip_msg : "libtap():malloc() failed");
298 } 306 }
299 307
300 free(skip_msg); 308 free(skip_msg);
@@ -396,8 +404,9 @@ void _cleanup(void) {
396 return; 404 return;
397 } 405 }
398 406
399 if (failures) 407 if (failures) {
400 diag("Looks like you failed %d tests of %d.", failures, test_count); 408 diag("Looks like you failed %d tests of %d.", failures, test_count);
409 }
401 410
402 UNLOCK; 411 UNLOCK;
403} 412}
diff --git a/tap/tap.h b/tap/tap.h
index 5abbd76a..0c550bfd 100644
--- a/tap/tap.h
+++ b/tap/tap.h
@@ -28,45 +28,50 @@
28 and requires the caller to add the final comma if they've omitted 28 and requires the caller to add the final comma if they've omitted
29 the optional arguments */ 29 the optional arguments */
30#ifdef __GNUC__ 30#ifdef __GNUC__
31# define ok(e, test, ...) \ 31# define ok(e, test, ...) \
32 ((e) ? _gen_result(1, __func__, __FILE__, __LINE__, test, ##__VA_ARGS__) \ 32 ((e) ? _gen_result(1, __func__, __FILE__, __LINE__, test, ##__VA_ARGS__) \
33 : _gen_result(0, __func__, __FILE__, __LINE__, test, ##__VA_ARGS__)) 33 : _gen_result(0, __func__, __FILE__, __LINE__, test, ##__VA_ARGS__))
34 34
35# define ok1(e) ((e) ? _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e)) 35# define ok1(e) \
36 ((e) ? _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) \
37 : _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e))
36 38
37# define pass(test, ...) ok(1, test, ##__VA_ARGS__); 39# define pass(test, ...) ok(1, test, ##__VA_ARGS__);
38# define fail(test, ...) ok(0, test, ##__VA_ARGS__); 40# define fail(test, ...) ok(0, test, ##__VA_ARGS__);
39 41
40# define skip_start(test, n, fmt, ...) \ 42# define skip_start(test, n, fmt, ...) \
41 do { \ 43 do { \
42 if ((test)) { \ 44 if ((test)) { \
43 skip(n, fmt, ##__VA_ARGS__); \ 45 skip(n, fmt, ##__VA_ARGS__); \
44 continue; \ 46 continue; \
45 } 47 }
46#else /* __GNUC__ */ 48#else /* __GNUC__ */
47/* The original tap.h used to test if __STDC_VERSION__ >= 199901L here. This 49/* The original tap.h used to test if __STDC_VERSION__ >= 199901L here. This
48 * doesn't seem to work on HP-UX even though the code compile fine. I'm not 50 * doesn't seem to work on HP-UX even though the code compile fine. I'm not
49 * sure how to add an exception here for HP-UX so I just removed the check 51 * sure how to add an exception here for HP-UX so I just removed the check
50 * for now */ 52 * for now */
51# define ok(e, ...) \ 53# define ok(e, ...) \
52 ((e) ? _gen_result(1, __func__, __FILE__, __LINE__, __VA_ARGS__) : _gen_result(0, __func__, __FILE__, __LINE__, __VA_ARGS__)) 54 ((e) ? _gen_result(1, __func__, __FILE__, __LINE__, __VA_ARGS__) \
55 : _gen_result(0, __func__, __FILE__, __LINE__, __VA_ARGS__))
53 56
54# define ok1(e) ((e) ? _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e)) 57# define ok1(e) \
58 ((e) ? _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) \
59 : _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e))
55 60
56# define pass(...) ok(1, __VA_ARGS__); 61# define pass(...) ok(1, __VA_ARGS__);
57# define fail(...) ok(0, __VA_ARGS__); 62# define fail(...) ok(0, __VA_ARGS__);
58 63
59# define skip_start(test, n, ...) \ 64# define skip_start(test, n, ...) \
60 do { \ 65 do { \
61 if ((test)) { \ 66 if ((test)) { \
62 skip(n, __VA_ARGS__); \ 67 skip(n, __VA_ARGS__); \
63 continue; \ 68 continue; \
64 } 69 }
65#endif /* __GNUC__ */ 70#endif /* __GNUC__ */
66 71
67#define skip_end \ 72#define skip_end \
68 } \ 73 } \
69 while (0) \ 74 while (0) \
70 ; 75 ;
71 76
72unsigned int _gen_result(int, const char *, char *, unsigned int, char *, ...); 77unsigned int _gen_result(int, const char *, char *, unsigned int, char *, ...);
diff --git a/tools/mini_epn.c b/tools/mini_epn.c
index 6f3c5d02..1b09f1c1 100644
--- a/tools/mini_epn.c
+++ b/tools/mini_epn.c
@@ -1,14 +1,14 @@
1/* 1/*
2 * 2 *
3 * MINI_EPN.C - Mini Embedded Perl Nagios 3 * MINI_EPN.C - Mini Embedded Perl Nagios
4 * Contributed by Stanley Hopcroft 4 * Contributed by Stanley Hopcroft
5 * Modified by Douglas Warner 5 * Modified by Douglas Warner
6 * Last Modified: 05/02/2002 6 * Last Modified: 05/02/2002
7 * 7 *
8 * This is a sample mini embedded Perl interpreter (hacked out checks.c and 8 * This is a sample mini embedded Perl interpreter (hacked out checks.c and
9 * perlembed) for use in testing Perl plugins. 9 * perlembed) for use in testing Perl plugins.
10 * 10 *
11 * It can be compiled with the following command (see 'man perlembed' for 11 * It can be compiled with the following command (see 'man perlembed' for
12 * more info): 12 * more info):
13 * 13 *
14 * gcc -omini_epn mini_epn.c `perl -MExtUtils::Embed -e ccopts -e ldopts` 14 * gcc -omini_epn mini_epn.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
@@ -21,7 +21,6 @@
21 * 21 *
22 */ 22 */
23 23
24
25#include <EXTERN.h> 24#include <EXTERN.h>
26#include <perl.h> 25#include <perl.h>
27#include <fcntl.h> 26#include <fcntl.h>
@@ -30,7 +29,7 @@
30/* include PERL xs_init code for module and C library support */ 29/* include PERL xs_init code for module and C library support */
31 30
32#if defined(__cplusplus) 31#if defined(__cplusplus)
33#define is_cplusplus 32# define is_cplusplus
34#endif 33#endif
35 34
36#ifdef is_cplusplus 35#ifdef is_cplusplus
@@ -42,22 +41,20 @@ extern "C" {
42 41
43#ifdef is_cplusplus 42#ifdef is_cplusplus
44} 43}
45# ifndef EXTERN_C 44# ifndef EXTERN_C
46# define EXTERN_C extern "C" 45# define EXTERN_C extern "C"
47# endif 46# endif
48#else 47#else
49# ifndef EXTERN_C 48# ifndef EXTERN_C
50# define EXTERN_C extern 49# define EXTERN_C extern
51# endif 50# endif
52#endif 51#endif
53
54 52
55EXTERN_C void xs_init _((void)); 53EXTERN_C void xs_init _((void));
56 54
57EXTERN_C void boot_DynaLoader _((CV* cv)); 55EXTERN_C void boot_DynaLoader _((CV * cv));
58 56
59EXTERN_C void xs_init(void) 57EXTERN_C void xs_init(void) {
60{
61 char *file = __FILE__; 58 char *file = __FILE__;
62 dXSUB_SYS; 59 dXSUB_SYS;
63 60
@@ -65,85 +62,80 @@ EXTERN_C void xs_init(void)
65 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); 62 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
66} 63}
67 64
68
69static PerlInterpreter *perl = NULL; 65static PerlInterpreter *perl = NULL;
70 66
71 67int main(int argc, char **argv, char **env) {
72int main(int argc, char **argv, char **env) 68 char *embedding[] = {"", "p1.pl"};
73{
74 char *embedding[] = { "", "p1.pl" };
75 char plugin_output[1024]; 69 char plugin_output[1024];
76 char buffer[512]; 70 char buffer[512];
77 char tmpfname[32]; 71 char tmpfname[32];
78 char fname[32]; 72 char fname[32];
79 char *args[] = {"","0", "", "", NULL }; 73 char *args[] = {"", "0", "", "", NULL};
80 FILE *fp; 74 FILE *fp;
81 75
82 const int command_line_size = 160; 76 const int command_line_size = 160;
83 char command_line[command_line_size]; 77 char command_line[command_line_size];
84 char *ap ; 78 char *ap;
85 int exitstatus; 79 int exitstatus;
86 int pclose_result; 80 int pclose_result;
87#ifdef THREADEDPERL 81#ifdef THREADEDPERL
88 dTHX; 82 dTHX;
89#endif 83#endif
90 dSP; 84 dSP;
91 85
92 if ((perl=perl_alloc())==NULL) { 86 if ((perl = perl_alloc()) == NULL) {
93 snprintf(buffer,sizeof(buffer),"Error: Could not allocate memory for embedded Perl interpreter!\n"); 87 snprintf(buffer, sizeof(buffer),
94 buffer[sizeof(buffer)-1]='\x0'; 88 "Error: Could not allocate memory for embedded Perl interpreter!\n");
89 buffer[sizeof(buffer) - 1] = '\x0';
95 printf("%s\n", buffer); 90 printf("%s\n", buffer);
96 exit(1); 91 exit(1);
97 } 92 }
98 perl_construct(perl); 93 perl_construct(perl);
99 exitstatus=perl_parse(perl,xs_init,2,embedding,NULL); 94 exitstatus = perl_parse(perl, xs_init, 2, embedding, NULL);
100 if (!exitstatus) { 95 if (!exitstatus) {
101 96
102 exitstatus=perl_run(perl); 97 exitstatus = perl_run(perl);
103 98
104 while(printf("Enter file name: ") && fgets(command_line, command_line_size, stdin)) { 99 while (printf("Enter file name: ") && fgets(command_line, command_line_size, stdin)) {
105 100
106 /* call the subroutine, passing it the filename as an argument */ 101 /* call the subroutine, passing it the filename as an argument */
107 102
108 command_line[strlen(command_line) -1] = '\0'; 103 command_line[strlen(command_line) - 1] = '\0';
109 104
110 strncpy(fname,command_line,strcspn(command_line," ")); 105 strncpy(fname, command_line, strcspn(command_line, " "));
111 fname[strcspn(command_line," ")] = '\x0'; 106 fname[strcspn(command_line, " ")] = '\x0';
112 args[0] = fname ; 107 args[0] = fname;
113 args[3] = command_line + strlen(fname) + 1 ; 108 args[3] = command_line + strlen(fname) + 1;
114 109
115 /* generate a temporary filename to which stdout can be redirected. */ 110 /* generate a temporary filename to which stdout can be redirected. */
116 sprintf(tmpfname,"/tmp/embedded%d",getpid()); 111 sprintf(tmpfname, "/tmp/embedded%d", getpid());
117 args[2] = tmpfname; 112 args[2] = tmpfname;
118 113
119 /* call our perl interpreter to compile and optionally cache the command */ 114 /* call our perl interpreter to compile and optionally cache the command */
120 perl_call_argv("Embed::Persistent::eval_file", G_DISCARD | G_EVAL, args); 115 perl_call_argv("Embed::Persistent::eval_file", G_DISCARD | G_EVAL, args);
121 116
122 perl_call_argv("Embed::Persistent::run_package", G_DISCARD | G_EVAL, args); 117 perl_call_argv("Embed::Persistent::run_package", G_DISCARD | G_EVAL, args);
123 118
124 /* check return status */ 119 /* check return status */
125 if(SvTRUE(ERRSV)){ 120 if (SvTRUE(ERRSV)) {
126 pclose_result=-2; 121 pclose_result = -2;
127 printf("embedded perl ran %s with error %s\n",fname,SvPV(ERRSV,PL_na)); 122 printf("embedded perl ran %s with error %s\n", fname, SvPV(ERRSV, PL_na));
128 } 123 }
129 124
130 /* read back stdout from script */ 125 /* read back stdout from script */
131 fp=fopen(tmpfname, "r"); 126 fp = fopen(tmpfname, "r");
132 127
133 /* default return string in case nothing was returned */ 128 /* default return string in case nothing was returned */
134 strcpy(plugin_output,"(No output!)"); 129 strcpy(plugin_output, "(No output!)");
135
136 fgets(plugin_output,sizeof(plugin_output)-1,fp);
137 plugin_output[sizeof(plugin_output)-1]='\x0';
138 fclose(fp);
139 unlink(tmpfname);
140 printf("embedded perl plugin output was %d,%s\n",pclose_result, plugin_output);
141 130
131 fgets(plugin_output, sizeof(plugin_output) - 1, fp);
132 plugin_output[sizeof(plugin_output) - 1] = '\x0';
133 fclose(fp);
134 unlink(tmpfname);
135 printf("embedded perl plugin output was %d,%s\n", pclose_result, plugin_output);
142 } 136 }
143
144 } 137 }
145 138
146
147 PL_perl_destruct_level = 0; 139 PL_perl_destruct_level = 0;
148 perl_destruct(perl); 140 perl_destruct(perl);
149 perl_free(perl); 141 perl_free(perl);